diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..edb5dee246 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,46 @@ +# Based on .gitattributes template from https://help.github.com/articles/dealing-with-line-endings + +# Set default behaviour, in case users don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files we want to always be normalized and converted +# to native line endings on checkout. +*.c text +*.cc text +*.cpp text +*.h text +*.hlsl text +*.htm text +*.md text +*.xml text +*.txt text + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf +*.csproj text eol=crlf +*.vcxproj text eol=crlf +*.shfbproj text eol=crlf + +*.resx text eol=crlf +*.aml text eol=crlf + +*.cs text eol=crlf diff=csharp + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.bmp binary +*.ico binary + +*.exe binary +*.dll binary +*.lib binary +*.pdb binary + +*.rtf binary +*.snk binary +*.rc binary + +# Specific files that should be left alone +renderdoccmd/resource.h binary +renderdoc/data/resource.h binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..b0cd1c35cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +Demos/ +Debug/ +Documentation/ +Release/ +Profile/ +dist/ +Resources/*.png +*.exe +*.aps +*.ilk +*.manifest +*.user +bin/ +obj/ +*.opensdf +*.pdb +*.o +*.verto +*.frago +*.so +*.a +*.exp +*.lib +*.sdf +*.suo +*.PixRun +*.dll +symsrv.yes +capture.log* +capture.d3dbgr* +Direct3DLog.txt +ipch/ +*.nvuser +*.shfbproj_* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..63f29fe6ef --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +all: + cd renderdoc && make librenderdoc.so + cd renderdoccmd && make bin/renderdoccmd + +clean: + cd renderdoc && make clean diff --git a/ScintillaNET/License.txt b/ScintillaNET/License.txt new file mode 100644 index 0000000000..80e563d93a --- /dev/null +++ b/ScintillaNET/License.txt @@ -0,0 +1,21 @@ +ScintillaNET is based on the Scintilla component by Neil Hodgson. + +ScintillaNET is released on this same license. + +The ScintillaNET bindings are Copyright 2002-2006 by Garrett Serack + +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. + +GARRETT SERACK AND ALL EMPLOYERS PAST AND PRESENT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL GARRETT SERACK AND ALL EMPLOYERS PAST AND PRESENT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +The license for Scintilla is as follows: +----------------------------------------------------------------------- +Copyright 1998-2006 by Neil Hodgson + +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. + +NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/ScintillaNET/SciLexer.dll b/ScintillaNET/SciLexer.dll new file mode 100644 index 0000000000..39976a576f Binary files /dev/null and b/ScintillaNET/SciLexer.dll differ diff --git a/ScintillaNET/SciLexer64.dll b/ScintillaNET/SciLexer64.dll new file mode 100644 index 0000000000..51a4532340 Binary files /dev/null and b/ScintillaNET/SciLexer64.dll differ diff --git a/ScintillaNET/ScintillaNET.dll b/ScintillaNET/ScintillaNET.dll new file mode 100644 index 0000000000..9857a7bc08 Binary files /dev/null and b/ScintillaNET/ScintillaNET.dll differ diff --git a/ScintillaNET/ScintillaNET.pdb b/ScintillaNET/ScintillaNET.pdb new file mode 100644 index 0000000000..8dd2a279fb Binary files /dev/null and b/ScintillaNET/ScintillaNET.pdb differ diff --git a/ScintillaNET/ScintillaNET.xml b/ScintillaNET/ScintillaNET.xml new file mode 100644 index 0000000000..3f2b7800f8 --- /dev/null +++ b/ScintillaNET/ScintillaNET.xml @@ -0,0 +1,4556 @@ + + + + ScintillaNET + + + + + Provides a writer paradigm for building a list and optionally + the text that is being styled. + + + + + Returns the underlying . + + The underlying if one was provided; otherwise, null. + + + + Returns a enumerable built by the thus far. + + A enumerable representing the style runs written thus far. + + + + Writes a run of the specified string length in the specified style. + + + The string that determines the run length. If a was used to + create the the string value will also be appended. + + The zero-based index of the style for this run. + + + + Initializes a new instance of the class. + + The optional to write to. + + + + Provides data for the StyleNeeded event + + + + + Initializes a new instance of the StyleNeededEventArgs class. + + the document range that needs styling + + + + Returns the document range that needs styling + + + + + Provides data for the StyleChanged event + + + StyleChangedEventHandler is used for the StyleChanged Event which is also used as + a more specific abstraction around the SCN_MODIFIED notification message. + + + + + Base class for modified events + + + ModifiedEventArgs is the base class for all events that are fired + in response to an SCN_MODIFY notification message. They all have + the Undo/Redo flags in common and I'm also including the raw + modificationType integer value for convenience purposes. + + + + + Returns how many characters have changed + + + + + Returns the starting document position where the style has been changed + + + + + Top level ScintillaHelpers Like Style and Folding inherit from this class so they don't have + to reimplement the same Equals method + + + + + Abstract Equals Override. All Helpers must implement this. Use IsSameHelperFamily to + determine if the types are compatible and they have the same Scintilla. For most top + level helpers like Caret and Lexing this should be enough. Helpers like Marker and + Line also need to take other variables into consideration. + + + + + + + Determines if obj belongs to the same Scintilla and is of compatible type + + + + + Struct used for passing parameters to FormatRange() + + + + + The HDC (device context) we print to + + + + + The HDC we use for measuring (may be same as hdc) + + + + + Rectangle in which to print + + + + + Physically printable page size + + + + + Range of characters to print + + + + + A strongly-typed resource class, for looking up localized strings, etc. + + + + + Returns the cached ResourceManager instance used by this class. + + + + + Overrides the current thread's CurrentUICulture property for all + resource lookups using this strongly typed resource class. + + + + + Looks up a localized string similar to Cannot create the Scintilla direct message function.. + + + + + Looks up a localized string similar to Cannot load the '{0}' module into memory.. + + + + + Looks up a localized string similar to The '{0}' argument cannot be an empty string.. + + + + + Looks up a localized string similar to Enumeration already finished.. + + + + + Looks up a localized string similar to Enumeration has not started. Call MoveNext.. + + + + + Looks up a localized string similar to Cross-thread operation not valid: Control '{0}' accessed from a thread other than the thread it was created on.. + + + + + Looks up a localized string similar to Index was out of range. Must be non-negative and less than the size of the collection.. + + + + + Looks up a localized string similar to Insufficient space in the target location to copy the information.. + + + + + Looks up a localized string similar to A change in the control who created this annotation has rendered the object invalid.. + + + + + Looks up a localized string similar to The {0} line must specify a valid line within the document.. + + + + + Looks up a localized string similar to The start line and end line must specify a valid range.. + + + + + Looks up a localized string similar to '{0}' is not a valid Scintilla module.. + + + + + Looks up a localized string similar to The start line must be greater than or equal to zero.. + + + + + Looks up a localized string similar to The module name must be set before any Scintilla object are created.. + + + + + Looks up a localized string similar to '{0}' was out of range. Must be non-negative and less than {1}.. + + + + + Looks up a localized string similar to SciLexer.dll. + + + + + Looks up a localized string similar to SciLexer64.dll. + + + + + Provides an abstraction over Scintilla's Document Pointer + + + + + Increases the document's reference count + + No, you aren't looking at COM, move along. + + + + Overridden. + + Another Document Object + True if both Documents have the same Handle + + + + Overridden + + Document Pointer's hashcode + + + + Decreases the document's reference count + + + When the document's reference count reaches 0 Scintilla will destroy the document + + + + + Scintilla's internal document pointer. + + + + + Specifies the display mode of whitespace characters. + + + + + The normal display mode with whitespace displayed as an empty background color. + + + + + Whitespace characters are drawn as dots and arrows. + + + + + Whitespace used for indentation is displayed normally but after the first visible character, it is shown as dots and arrows. + + + + + Returns an HTML #XXXXXX format for a color. Unlike the ColorTranslator class it + never returns named colors. + + + + + Marshals an IntPtr pointing to un unmanaged byte[] to a .NET String using the given Encoding. + + + I'd love to have this as en extension method but ScintillaNET's probably going to be 2.0 for a long + time to come. There's nothing really compelling in later versions that applies to ScintillaNET that + can't be done with a 2.0 construct (extension methods, linq, etc) + + + + + The flags that are stored along with the fold level. + + + + + The base value for a 0-level fold. The fold level is a number in the range 0 to 4095 (NumberMask). + However, the initial fold level is set to Base(1024) to allow unsigned arithmetic on folding levels. + + + + + WhiteFlag indicates that the line is blank and allows it to be treated slightly different then its level may + indicate. For example, blank lines should generally not be fold points and will be considered part + of the preceding section even though they may have a lesser fold level. + + + + + HeaderFlag indicates that the line is a header (fold point). + + + + + Not documented by current Scintilla docs - associated with the removed Box fold style? + + + + + A bit-mask indicating which bits are used to store the actual fold level. + + + + + Determines how whitespace should be displayed in a control. + + + By default, whitespace is determined by the lexer in use. Setting the + or properties overrides the lexer behavior. + + + + + Gets or sets the whitespace background color. + + + By default, the whitespace background color is determined by the lexer in use. + Setting the BackColor to anything other than overrides the lexer behavior. + Transparent colors are not supported. + + + A that represents the background color of whitespace characters. + The default is . + + + The specified has an alpha value that is less that . + + + + + Gets or sets the whitespace foreground color. + + + By default, the whitespace foreground color is determined by the lexer in use. + Setting the ForeColor to anything other than overrides the lexer behavior. + Transparent colors are not supported. + + + A that represents the foreground color of whitespace characters. + The default is . + + + The specified has an alpha value that is less that . + + + + + Gets or sets the whitespace display mode. + + One of the values. The default is + + The specified value is not a valid value. + + + + + Provides data for the UriDropped event + + + + + Initializes a new instance of the UriDroppedEventArgs class. + + Text of the dropped file or uri + + + + Text of the dropped file or uri + + + + + List of strings to be used with . + + + + + Creates a new instance of an OverLoadList + + + + + Creates a new instance of an OverLoadList. The list of overloads is supplied by collection + + + + + Creates a new instance of an OverLoadList. The + + + + + Text of the overload to be displayed in the CallTip + + + + + Index of the overload to be displayed in the CallTip + + + + + Specifies the line layout caching strategy used by a control. + + + + + No line layout data is cached. + + + + + Line layout data of the current caret line is cached. + + + + + Line layout data for all visible lines and the current caret line are cached. + + + + + Line layout data for the entire document is cached. + + + + + Represents casing styles + + + + + Both upper and lower case + + + + + Only upper case + + + + + Only lower case + + + + + Provides data for the LinesNeedShown event + + + + + Initializes a new instance of the LinesNeedShownEventArgs class. + + the first (top) line that needs to be shown + the last (bottom) line that needs to be shown + + + + Returns the first (top) line that needs to be shown + + + + + Returns the last (bottom) line that needs to be shown + + + + + Built in lexers supported by Scintilla + + + + + No lexing is performed, the Containing application must respond to StyleNeeded events + + + + + No lexing is performed + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Provides methods to place data on and retrieve data from the system Clipboard. + + + + + Copies the current selection in the document to the Clipboard. + + + + + Copies the current selection, or the current line if there is no selection, to the Clipboard. + + + Indicates whether to copy the current line if there is no selection. + + + A line copied in this mode is given a "MSDEVLineSelect" marker when added to the Clipboard and + then used in the method to paste the whole line before the current line. + + + + + Copies the specified range of text (bytes) in the document to the Clipboard. + + The zero-based byte position to start copying. + The zero-based byte position to stop copying. + + + + Moves the current document selection to the Clipboard. + + + + + Replaces the current document selection with the contents of the Clipboard. + + + + + Gets a value indicating whether text (bytes) can be copied given the current selection. + + true if the text can be copied; otherwise, false. + This is equivalent to determining if there is a valid selection. + + + + Gets a value indicating whether text (bytes) can be cut given the current selection. + + true if the text can be cut; otherwise, false. + This is equivalent to determining if there is a valid selection. + + + + Gets a value indicating whether the document can accept text currently stored in the Clipboard. + + true if text can be pasted; otherwise, false. + + + + Gets or sets whether pasted line break characters are converted to match the document's end-of-line mode. + + + true if line break characters are converted; otherwise, false. + The default is true. + + + + + Used internally to signify an ignored parameter by overloads of SendMessageDirect + that match the native Scintilla's Message signatures. + + + + + Represents a DropMarker, currently a single document point. + + + + + A range within the editor. Start and End are both Positions. + + + + + Collapses all folds + + + + + Expands all folds + + + + + Removes trailing spaces from each line + + + + + Overridden, changes the document position. Start and End should + match. + + Document _start position + Document _end position + + + + Collects the DropMarker and causes it to be removed from all + lists it belongs ti. + + + + + Overridden. + + + + + Gets the Client Rectangle in pixels of the DropMarker's visual indicator. + + + + + Forces a repaint of the DropMarker + + + + + Overridden. Drop Markers are points, not a spanned range. Though this could change in the future. + + + + + Uniquely identifies the DropMarker + + + + + Not currently used, the offset in pixels from the document view's top. + + + + + Represents a Scintilla text editor control. + + + + + Interface representing the native Scintilla Message Based API. In addition + to wrappers around each of the messages I have included an additional Method + named SendMessageDirect with 9 overloads. This allows you to send messages + to the Scintilla DefWndProc bypassing Windows' SendMessage. Each of the other + methods wrap calls to SendMessageDirect. + + Scintilla explicetly implements this interface. To use these methods on + a Scintilla control Cast it as INativeScintilla or use NativeScintilla + property. + + The reason for this interface is to keep the "regular" interface surface + area of the Scintilla control as clean and .NETish as possible. Also + this means when you want a direct native interface there's no other + absracted members (Aside from SendMessageDirect ;) cluttering the native + interface. + + + + + Handles Scintilla Call Style: + (,) + + Scintilla Message Number + + + + + Handles Scintilla Call Style: + (int,) + + Scintilla Message Number + wParam + + + + + Handles Scintilla Call Style: + (bool,) + + Scintilla Message Number + boolean wParam + + + + + Handles Scintilla Call Style: + (,stringresult) + Notes: + Helper method to wrap all calls to messages that take a char* + in the lParam and returns a regular .NET String. This overload + assumes there will be no wParam and obtains the string _length + by calling the message with a 0 lParam. + + Scintilla Message Number + String output + + + + + This is the primary Native communication method with Scintilla + used by this control. All the other overloads call into this one. + + + + + Handles Scintilla Call Style: + (int,int) + + Scintilla Message Number + wParam + lParam + + + + + Handles Scintilla Call Style: + (int,uint) + + Scintilla Message Number + wParam + lParam + + + + + Handles Scintilla Call Style: + (,int) + + Scintilla Message Number + always pass null--Unused parameter + lParam + + + + + Handles Scintilla Call Style: + (bool,int) + + Scintilla Message Number + boolean wParam + int lParam + + + + + Handles Scintilla Call Style: + (int,bool) + + Scintilla Message Number + int wParam + boolean lParam + + + + + Handles Scintilla Call Style: + (int,stringresult) + Notes: + Helper method to wrap all calls to messages that take a char* + in the lParam and returns a regular .NET String. This overload + assumes there will be no wParam and obtains the string _length + by calling the message with a 0 lParam. + + Scintilla Message Number + String output + + + + + Handles Scintilla Call Style: + (?) + Notes: + Helper method to wrap all calls to messages that take a char* + in the wParam and set a regular .NET String in the lParam. + Both the _length of the string and an additional wParam are used + so that various string Message styles can be acommodated. + + Scintilla Message Number + int wParam + String output + _length of the input buffer + + + + + Handles Scintilla Call Style: + (int,string) + Notes: + This helper method handles all messages that take + const char* as an input string in the lParam. In + some messages Scintilla expects a NULL terminated string + and in others it depends on the string _length passed in + as wParam. This method handles both situations and will + NULL terminate the string either way. + + + Scintilla Message Number + int wParam + string lParam + + + + + Handles Scintilla Call Style: + (,string) + + Notes: + This helper method handles all messages that take + const char* as an input string in the lParam. In + some messages Scintilla expects a NULL terminated string + and in others it depends on the string _length passed in + as wParam. This method handles both situations and will + NULL terminate the string either way. + + + Scintilla Message Number + always pass null--Unused parameter + string lParam + + + + + Handles Scintilla Call Style: + (string,string) + + Notes: + Used by SCI_SETPROPERTY + + Scintilla Message Number + string wParam + string lParam + + + + + Handles Scintilla Call Style: + (string,stringresult) + + Notes: + This one is used specifically by SCI_GETPROPERTY and SCI_GETPROPERTYEXPANDED + so it assumes it's usage + + + Scintilla Message Number + string wParam + Stringresult output + + + + + Handles Scintilla Call Style: + (string,int) + + Scintilla Message Number + string wParam + int lParam + + + + + Handles Scintilla Call Style: + (string,) + + Scintilla Message Number + string wParam + + + + + Enables the brace matching from current position. + + + + + Adds a line _end marker to the _end of the document + + + + + Appends a copy of the specified string to the _end of this instance. + + The to append. + A representing the appended text. + + + + Creates and returns a new object. + + A new object. + + + + Creates and returns a new object. + + A new object. + + + + Sends the specified message directly to the native Scintilla window, + bypassing any managed APIs. + + The message ID. + The message wparam field. + The message lparam field. + An representing the result of the message request. + + Warning: The Surgeon General Has Determined that Calling the Underlying Scintilla + Window Directly May Result in Unexpected Behavior! + + + The method was called from a thread other than the thread it was created on. + + + + + Overridden. Releases the unmanaged resources used by the and + its child controls and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Exports a HTML representation of the current document. + + A containing the contents of the document formatted as HTML. + Only ASCII documents are supported. Other encoding types have undefined behavior. + + + + Exports a HTML representation of the current document. + + The with which to write. + The title of the HTML document. + + true to output all styles including those not + used in the document; otherwise, false. + + Only ASCII documents are supported. Other encoding types have undefined behavior. + + + + Gets the text of the line containing the caret. + + A representing the text of the line containing the caret. + + + + Gets the text of the line containing the caret and the current caret position within that line. + + When this method returns, contains the byte offset of the current caret position with the line. + A representing the text of the line containing the caret. + + + + Gets a word from the specified position + + + + + Inserts text at the current cursor position + + Text to insert + The range inserted + + + + Inserts text at the given position + + The position to insert text in + Text to insert + The text range inserted + + + + Overridden. See . + + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Overridden. See . + + + + + Raises the event. + + An that contains the event data. + + + + Provides the support for code block selection + + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Overridden. See . + + + + + Overridden. Raises the event. + + An that contains the event data. + + + + Raises the event. + + A that contains the event data. + + + + Raises the event. + + A that contains the event data. + + + + Raises the event. + + A that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Overridden. See . + + + + + Overridden. See . + + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Overridden. See . + + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Overridden. See . + + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Raises the event. + + An that contains the event data. + + + + Checks that if the specified position is on comment. + + + + + Checks that if the specified position is on comment. + + + + + Overridden. See . + + + + + Custom way to find the matching brace when BraceMatch() does not work + + + + + Sets the application-wide default module name of the native Scintilla library. + + The native Scintilla module name. + This method must be called prior to the first control being created. + The is null. + The is an empty string. + This method was called after the first control was created. + + + + Overridden. Processes Windows messages. + + The Windows to process. + + + + Gets or sets a value indicating whether pressing ENTER creates a new line of text in the + control or activates the default button for the form. + + + true if the ENTER key creates a new line of text; false if the ENTER key activates + the default button for the form. The default is false. + + + + + Gets or sets a value indicating whether pressing the TAB key types a TAB character in the control + instead of moving the focus to the next control in the tab order. + + + true if users can enter tabs using the TAB key; false if pressing the TAB key + moves the focus. The default is false. + + + + + Gets a collection containing all annotations in the control. + + + A that contains all the annotations in the control. + + + + + Controls autocompletion behavior. + + + + + Gets or sets the background color for the control. + + + A that represents the background color of the control. + The default is . + + Settings this property resets any current document styling. + + + + This property is not relevant for this class. + + + + + This property is not relevant for this class. + + + + + Gets or sets the border style of the control. + + + A that represents the border type of the control. + The default is . + + + The value assigned is not one of the values. + + + + + Manages CallTip (Visual Studio-like code Tooltip) behaviors + + + + + Gets/Sets the Win32 Window Caption. Defaults to Type's FullName + + + + + Controls Caret Behavior + + + + + Gets Clipboard access for the control. + + A object the provides Clipboard access for the control. + + + + Controls behavior of keyboard bound commands. + + + + + Controls behavior of loading/managing ScintillaNET configurations. + + + + + Overridden. See . + + + + + Gets or sets the character index of the current caret position. + + The character index of the current caret position. + + + Gets or sets the default cursor for the control. + An object of type representing the current default cursor. + + + + Overridden. See . + + + + + Controls behavior of Documents + + + + + Controls behavior of automatic document navigation + + + + + Controls behavior of Drop Markers + + + + + Controls Encoding behavior + + + + + Controls End Of Line Behavior + + + + + Gets or sets the font of the text displayed by the control. + + + The to apply to the text displayed by the control. + The default is the value of the property. + + Settings this property resets any current document styling. + + + + Gets or sets the foreground color of the control. + + + The foreground of the control. + The default is . + + Settings this property resets any current document styling. + + + + Gets or sets the line layout caching strategy in a control. + + + One of the enumeration values. + The default is . + + + The value assigned is not one of the values. + + Larger cache sizes increase performance at the expense of memory. + + + + Gets an object that controls line wrapping options in the control. + + A object that manages line wrapping options in a control. + + + + Gets a collection representing the marker objects and options within the control. + + A representing the marker objects and options within the control. + + + + Gets or sets a value that indicates that the control has been modified by the user since + the control was created or its contents were last set. + + + true if the control's contents have been modified; otherwise, false. + The default is false. + + + + + Gets or sets the position cache size used to layout short runs of text in a control. + + The size of the position cache in bytes. The default is 1024. + Larger cache sizes increase performance at the expense of memory. + + + + Gets or sets a value indicating whether characters not considered alphanumeric (ASCII values 0 through 31) + are prevented as text input. + + + true to prevent control characters as input; otherwise, false. + The default is true. + + + + + Gets or sets the current text in the control. + + The text displayed in the control. + + + + Gets the _length of text in the control. + + The number of characters contained in the text of the control. + + + + Gets the display mode and style behavior associated with the control. + + A object that represents whitespace display mode and style behavior in a control. + + + + Gets or sets the current zoom level of the control. + + The factor by which the contents of the control is zoomed. + + + + Occurs when an annotation has changed. + + + + + Occurs when the user makes a selection from the auto-complete list. + + + + + Occurs when text is about to be removed from the document. + + + + + Occurs when text is about to be inserted into the document. + + + + + Occurs when the value of the property has changed. + + + + + Occurs when a user clicks on a call tip. + + + + + Occurs when the user types an ordinary text character (as opposed to a command character) into the text. + + + + + Occurs when the text or styling of the document changes or is about to change. + + + + + Occurs when a is about to be collected. + + + + + Occurs when a user actions such as a mouse move or key press ends a dwell (hover) activity. + + + + + Occurs when the user hovers the mouse (dwells) in one position for the dwell period. + + + + + Occurs when a folding change has occurred. + + + + + Occurs when a user clicks on text that is in a style with the hotspot attribute set. + + + + + Occurs when a user double-clicks on text that is in a style with the hotspot attribute set. + + + + + Occurs when a user releases a click on text that is in a style with the hotspot attribute set. + + + + + Occurs when the a clicks or releases the mouse on text that has an indicator. + + + + + Occurs when a range of lines that is currently invisible should be made visible. + + + + + Occurs when the control is first loaded. + + + + + Occurs each time a recordable change occurs. + + + + + Occurs when the mouse was clicked inside a margin that was marked as sensitive. + + + + + Occurs when one or more markers has changed in a line of text. + + + + + + Occurs when a user tries to modify text when in read-only mode. + + + + + Occurs when the control is scrolled. + + + + + Occurs when the selection has changed. + + + + + Occurs when the control is about to display or print text that requires styling. + + + + + Occurs when text has been removed from the document. + + + + + Occurs when text has been inserted into the document. + + + + + Occurs when the user zooms the display using the keyboard or the property is set. + + + + + Holds the last previous selection's properties, to let us know when we should fire SelectionChanged + + + + + Type of data to display at one of the positions in a Page Information section + + + + + Nothing is displayed at the position + + + + + The page number is displayed in the format "Page #" + + + + + The document name is displayed + + + + + Style of Indicator to be displayed + + + + + Underline + + + + + Squigly lines (commonly used for spellcheck) + + + + + Small t's are displayed + + + + + Small diagnol lines + + + + + Strikethrough line + + + + + Hidden + + + + + Displayes a bounding box around the indicated text + + + + + Displayes a bounding box around the indicated text with rounded corners + and an translucent background color + + + + + Provides data for the , , and + events. + + + + + Initializes a new instance of the class. + + The byte offset in the document of the character that was clicked. + + + + Gets the byte offset in the document of the character that was clicked. + + An representing the byte offset in the document of the character that was clicked. + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Class for determining how and what to print for a header or footer. + + + + + Default font used for Page Information sections + + + + + Draws the page information section in the specified rectangle + + + + + + + + + Default Constructor + + + + + Full Constructor + + Margin to use + Font to use + Border style + What to print on the left side of the page + What to print in the center of the page + What to print on the right side of the page + + + + Normal Use Constructor + + Border style + What to print on the left side of the page + What to print in the center of the page + What to print on the right side of the page + + + + Border style used for the Page Information section + + + + + Information printed in the center of the Page Information section + + + + + Whether there is a need to display this item, true if left, center, or right are not nothing. + + + + + Font used in printing the Page Information section + + + + + Height required to draw the Page Information section based on the options selected. + + + + + Information printed on the left side of the Page Information section + + + + + Space between the Page Information section and the rest of the page + + + + + Information printed on the right side of the Page Information section + + + + + Default Constructor + + + + + Full Constructor + + Margin to use + Font to use + Border style + What to print on the left side of the page + What to print in the center of the page + What to print on the right side of the page + + + + Normal Use Constructor + + Border style + What to print on the left side of the page + What to print in the center of the page + What to print on the right side of the page + + + + Specifies the symbol displayed by a . + + + + + The marker is drawn as a circle. + + + + + The marker is drawn as a rectangle with rounded edges. + + + + + The marker is drawn as a triangle pointing right. + This symbol is typically used to mark a closed folder. + + + + + The marker is drawn as a horizontal rectangle. + + + + + The marker is drawn as a small arrow pointing right. + + + + + The marker has no visible glpyh. + This symbol can still be used, however, to mark and track lines. + + + + + The marker is drawn as a triangle pointing down. + This symbol is typically used to mark an open folder. + + + + + The marker is drawn as a minus sign. + This symbol is typically used to mark an open folder. + + + + + The marker is drawn as a plus sign. + This symbol is typically used to mark a closed folder. + + + + + The marker is drawn as a vertical line. + This symbol is typically used to mark nested lines of an open folder. + + + + + The marker is drawn as straight lines intersecting in an "L" shape. + This symbol is typically used to mark the end of a folder in a "box style" tree. + + + + + The marker is drawn as straight lines intersecting in a rotated "T" shape. + This symbol is typically used to mark the end of a nested folder in a "box style" tree. + + + + + The marker is drawn as a plus sign surrounded by a rectangle. + This symbol is typically used to mark a closed folder in a "box style" tree. + + + + + The marker is drawn as a plus sign surrounded by a rectangle and vertial lines. + This symbol is typically used to mark a nested closed folder in a "box style" tree. + + + + + The marker is drawn as a minus sign surrounded by a rectangle and a vertical line at the bottom. + This symbol is typically used to mark an open folder in a "box style" tree. + + + + + The marker is drawn as a minus sign surrounded by a rectangle and vertical lines. + This symbol is typically used to mark a nested open folder in a "box style" tree. + + + + + The marker is drawn as curved lines intersecting in an "L" shape. + This symbol is typically used to mark the end of a folder in a "circle style" tree. + + + + + The marker is drawn as curved lines intersecting in a rotated "T" shape. + This symbol is typically used to mark the end of a nested folder in a "circle style" tree. + + + + + The marker is drawn as a plus sign surrounded by a circle. + This symbol is typically used to mark a closed folder in a "circle style" tree. + + + + + The marker is drawn as a plus sign surrounded by a circle and vertial lines. + This symbol is typically used to mark a nested closed folder in a "circle style" tree. + + + + + The marker is drawn as a minus sign surrounded by a circle and a vertical line at the bottom. + This symbol is typically used to mark an open folder in a "circle style" tree. + + + + + The marker is drawn as a minus sign surrounded by a circle and vertical lines. + This symbol is typically used to mark a nested open folder in a "circle style" tree. + + + + + The marker has no visible glyph, however, the background color of the entire text line + is drawn as specified in the property. + + + + + This marker is drawn as three horizontal dots. + + + + + The marker is drawn as three consecutive greater than glyphs. + + + + + The marker is drawn using the image specified in the method. + + + + + The marker has no visible glyph, however, the margin background color is draw as + specified in the property. + + + + + The marker is drawn as a thick vertical line along the left edge of the margin. + + + + + The marker has no visible glyph, however, it can be used to signify to a plugin + that the marker is available for a custom purpose. + + + + + The marker has no visible glyph, however, the entire text line is drawn with an underline in + the color specified by the property. + + + + + Document's EndOfLine Mode + + + + + Carriage Return + Line Feed (Windows Style) + + + + + Carriage Return Only (Mac Style) + + + + + Line Feed Only (Unix Style) + + + + + Provides data for the AutoCompleteAccepted event + + + + + Initializes a new instance of the AutoCompleteAcceptedEventArgs class. + + Text of the selected autocomplete entry selected + + + + Gets/Sets if the autocomplete action should be cancelled + + + + + Text of the selected autocomplete entry selected + + + + + Returns the _start position of the current word in the document. + + + This controls how many characters of the selected autocomplete entry + is actually inserted into the document + + + + + Gets or sets the first visible line in a control. + + The zero-based index of the first visible line in a control. + The value is a visible line rather than a document line. + + + + Represents a collection of objects and options in a control. + + + + + Manages End of line settings for the Scintilla Control + + + + + Converts all lines in the document to the given mode. + + The EndOfLineMode to convert all lines to + + + + Return as a string the characters used to mean _end-of-line. This depends solely on the + selected EOL mode. + + Should Mode not be CR, LF or CrLf, this function returns the empty string. + + + + Gets/Sets if End of line markers are visible in the Scintilla control. + + + + + Gets/Sets the for the document. Default is CrLf. + + + Changing this value does NOT change all EOL marks in a currently-loaded document. + To do this, use ConvertAllLines. + + + + + Initializes a new instance of the KeyWordConfig class. + + + + + + + + The style of visual indicator that the caret displayes. + + + + + The caret is not displayed + + + + + A vertical line is displayed + + + + + A horizontal block is displayed that may cover the character. + + + + + Used to invoke AutoComplete and UserList windows. Also manages AutoComplete + settings. + + + Autocomplete is typically used in IDEs to automatically complete some kind + of identifier or keyword based on a partial name. + + + + + Accepts the current AutoComplete window entry + + + If the AutoComplete window is open Accept() will close it. This also causes the + event to fire + + + + + Cancels the autocomplete window + + + If the AutoComplete window is displayed calling Cancel() will close the window. + + + + + Deletes all registered images. + + + + + Registers an image with index to be displayed in the AutoComplete window. + + Index of the image to register to + Image to display in Bitmap format + + + + Registers an image with index to be displayed in the AutoComplete window. + + Index of the image to register to + Image to display in the XPM image format + Color to mask the image as transparent + + + + Registers an image with index to be displayed in the AutoComplete window. + + Index of the image to register to + Image in the XPM image format + + + + Registers a list of images to be displayed in the AutoComplete window. + + List of images in the Bitmap image format + Indecis are assigned sequentially starting at 0 + + + + Registers a list of images to be displayed in the AutoComplete window. + + List of images in the Bitmap image format + Color to mask the image as transparent + Indecis are assigned sequentially starting at 0 + + + + Registers a list of images to be displayed in the AutoComplete window. + + List of images in the XPM image format + Indecis are assigned sequentially starting at 0 + + + + Registers a list of images to be displayed in the AutoComplete window. + + List of images contained in an ImageList + Indecis are assigned sequentially starting at 0 + + + + Registers a list of images to be displayed in the AutoComplete window. + + List of images contained in an ImageList + Color to mask the image as transparent + Indecis are assigned sequentially starting at 0 + + + + Shows the autocomplete window. + + + This overload assumes that the property has been + set. The lengthEntered is automatically detected by the editor. + + + + + Shows the autocomplete window + + + Sets the property. + In this overload the lengthEntered is automatically detected by the editor. + + + + + Shows the autocomplete window + + Number of characters of the current word already entered in the editor + + This overload assumes that the property has been set. + + + + + Shows the autocomplete window + + Number of characters of the current word already entered in the editor + Sets the property. + + + + Shows the autocomplete window. + + Number of characters of the current word already entered in the editor + Sets the property. + + + + Shows the autocomplete window. + + Sets the property. + + In this overload the lengthEntered is automatically detected by the editor. + + + + + Shows a UserList window + + Index of the userlist to show. Can be any integer + List of words to show. + + UserLists are not as powerful as autocomplete but can be assigned to a user defined index. + + + + + Shows a UserList window + + Index of the userlist to show. Can be any integer + List of words to show separated by " " + + UserLists are not as powerful as autocomplete but can be assigned to a user defined index. + + + + + By default, the list is cancelled if there are no viable matches (the user has typed characters that no longer match a list entry). + If you want to keep displaying the original list, set AutoHide to false. + + + + + Gets or Sets the last automatically calculated LengthEntered used whith . + + + + + The default behavior is for the list to be cancelled if the caret moves before the location it was at when the list was displayed. + By setting this property to false, the list is not cancelled until the caret moves before the first character of the word being completed. + + + + + When an item is selected, any word characters following the caret are first erased if dropRestOfWord is set to true. + + Defaults to false + + + + List of characters (no separated) that causes the AutoComplete window to accept the current + selection. + + + + + Autocompletion list items may display an image as well as text. Each image is first registered with an integer type. + Then this integer is included in the text of the list separated by a '?' from the text. For example, "fclose?2 fopen" + displays image 2 before the string "fclose" and no image before "fopen". + + + + + Returns wether or not the AutoComplete window is currently displayed + + + + + Gets or Sets if the comparison of words to the AutoComplete are case sensitive. + + Defaults to true + + + + Gets the document posision when the AutoComplete window was last invoked + + + + + List if words to display in the AutoComplete window when invoked. + + + + + Character used to split to convert to a List. + + + + + List of words to display in the AutoComplete window. + + + The list of words separated by which + is " " by default. + + + + + Get or set the maximum number of rows that will be visible in an autocompletion list. If there are more rows in the list, then a vertical scrollbar is shown + + Defaults to 5 + + + + Get or set the maximum width of an autocompletion list expressed as the number of characters in the longest item that will be totally visible. + + + If zero (the default) then the list's width is calculated to fit the item with the most characters. Any items that cannot be fully displayed + within the available width are indicated by the presence of ellipsis. + + + + + Gets or Sets the index of the currently selected item in the AutoComplete + + + + + Gets or Sets the Text of the currently selected AutoComplete item. + + + When setting this property it does not change the text of the currently + selected item. Instead it searches the list for the given value and selects + that item if it matches. + + + + + If you set this value to true and a list has only one item, it is automatically added and no list is displayed. + The default is to display the list even if there is only a single item. + + + + + List of characters (no separator) that causes the AutoComplete window to cancel. + + + + + Struct used for specifying the printing bounds + + + + + Left X Bounds Coordinate + + + + + Top Y Bounds Coordinate + + + + + Right X Bounds Coordinate + + + + + Bottom Y Bounds Coordinate + + + + + Provides data for native Scintilla Events + + + All events fired from the INativeScintilla Interface uses + NativeScintillaEventArgs. Msg is a copy + of the Notification Message sent to Scintilla's Parent WndProc + and SCNotification is the SCNotification Struct pointed to by + Msg's lParam. + + + + + Initializes a new instance of the NativeScintillaEventArgs class. + + Notification Message sent from the native Scintilla + SCNotification structure sent from Scintilla that contains the event data + + + + Notification Message sent from the native Scintilla + + + + + SCNotification structure sent from Scintilla that contains the event data + + + + + Mostly behaves like a stack but internally maintains a List for more flexability + + + FakeStack is not a general purpose datastructure and can only hold NavigationPoint objects + + + + + Specifies the visibility and appearance of annotations in a control. + + + + + Annotations are not displayed. + + + + + Annotations are drawn left-justified with no adorment. + + + + + Annotations are indented to match the text and are surrounded by a box. + + + + + Specifies the locations of line wrapping visual glyphs in a control. + + + + + Line wrapping glyphs are drawn near the control border. + + + + + Line wrapping glyphs are drawn at the end of wrapped lines near the text. + + + + + Line wrapping glyphs are drawn at the start of wrapped lines near the text. + + + + + Contains Undo/Redo information, used by many of the events + + + + + Was this action the result of an undo action + + + + + Was this action the result of a redo action + + + + + Is this part of a multiple undo or redo + + + + + Is this the last step in an undi or redo + + + + + Does this affect multiple lines + + + + + Overridden + + + + + Initializes a new instance of the UndoRedoFlags structure. + + Was this action the result of an undo action + Was this action the result of a redo action + Is this part of a multiple undo or redo + Is this the last step in an undi or redo + Does this affect multiple lines + + + + Style of smart indent + + + + + No smart indent + + + + + C++ style indenting + + + + + Alternate C++ style indenting + + + + + Block indenting, the last indentation is retained in new lines + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + ScintillaNET derived class for handling printing of source code from a Scintilla control. + + + + + Method called after the Print method is called and before the first page of the document prints + + A PrintPageEventArgs that contains the event data + + + + Method called when the last page of the document has printed + + A PrintPageEventArgs that contains the event data + + + + Method called when printing a page + + A PrintPageEventArgs that contains the event data + + + + Default Constructor + + Scintilla control being printed + + + + Represents a point in the document used for navigation. + + + + + Overridden. + + + + + Initializes a new instance of the NavigationPont class. + + + + + Provides data for the FoldChanged event + + + + + Initializes a new instance of the FoldChangedEventArgs class. + + Line # that the fold change occured on + new Fold Level of the line + previous Fold Level of the line + What kind of fold modification occured + + + + Gets/Sets the Line # that the fold change occured on + + + + + Gets the new Fold Level of the line + + + + + Gets the previous Fold Level of the line + + + + + Used to display CallTips and Manages CallTip settings. + + + CallTips are a special form of ToolTip that can be displayed specifically for + a document position. It also display a list of method overloads and + highlighight a portion of the message. This is useful in IDE scenarios. + + + + + Hides the calltip + + + and do the same thing + + + + + Hides the calltip + + + and do the same thing + + + + + Displays a calltip without overloads + + + The must already be populated. The calltip will be displayed at the current document position + with no highlight. + + + + + Displays a calltip without overloads + + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + The must already be populated. The calltip will be displayed at the current document position + + + + + Displays a calltip without overloads + + The document position to show the calltip + + The must already be populated. The calltip with no highlight + + + + + Displays a calltip without overloads + + The document position to show the calltip + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + The must already be populated. + + + + + Displays a calltip without overloads + + The calltip message to be displayed + + The calltip will be displayed at the current document position with no highlight + + + + + Displays a calltip without overloads + + The calltip message to be displayed + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + The calltip will be displayed at the current document position + + + + + Displays a calltip without overloads + + The calltip message to be displayed + The document position to show the calltip + + The calltip will be displayed with no highlight + + + + + Displays a calltip without overloads + + The calltip message to be displayed + The document position to show the calltip + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + + + Shows the calltip with overloads + + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. It will be displayed at the current document + position starting at overload 0 with no highlight. + + + + + Shows the calltip with overloads + + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. It will be displayed at the current document + position starting at overload 0 + + + + + Shows the calltip with overloads + + The document position where the calltip should be displayed + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. The overload at position 0 will be displayed + with no highlight. + + + + + Shows the calltip with overloads + + The document position where the calltip should be displayed + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. The overload at position 0 will be displayed. + + + + + Shows the calltip with overloads + + The document position where the calltip should be displayed + The index of the initial overload to display + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. It will be displayed at the current document + position with no highlight + + + + + Shows the calltip with overloads + + The document position where the calltip should be displayed + The index of the initial overload to display + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The current document position will be used starting at position 0 with no highlight + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The current document position will be used starting at position 0 + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + The document position where the calltip should be displayed + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The overload startIndex will be 0 with no Highlight + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + The document position where the calltip should be displayed + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The overload startIndex will be 0 + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + The document position where the calltip should be displayed + The index of the initial overload to display + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + The index of the initial overload to display + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The current document position will be used with no highlight + + + + + Shows the calltip with overloads + + List of overloads to be displayed see + The index of the initial overload to display + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The current document position will be used + + + + + Shows the calltip with overloads + + The index of the initial overload to display + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. It will be displayed at the current document + position with no highlight. + + + + + Shows the calltip with overloads + + The index of the initial overload to display + Start posision of the part of the message that should be selected + End posision of the part of the message that should be selected + + ShowOverload automatically handles displaying a calltip with a list of overloads. It automatically shows the + up and down arrows and cycles through the list of overloads in response to mouse clicks. + The must already be populated. It will be displayed at the current document + position. + + + + + Gets/Sets the background color of all CallTips + + + + + Gets/Sets Text color of all CallTips + + + + + End position of the text to be highlighted in the CalTip + + + + + Start position of the text to be highlighted in the CalTip + + + + + Gets/Sets the Text Color of the portion of the CallTip that is highlighted + + + + + Returns true if a CallTip is currently displayed + + + + + The message displayed in the calltip + + + + + List of method overloads to display in the calltip + + + This is used to display IDE type toolips that include Up/Down arrows that cycle + through the list of overloads when clicked + + + + + Provices data for the TextModified event + + + TextModifiedEventHandler is used as an abstracted subset of the + SCN_MODIFIED notification message. It's used whenever the SCNotification's + modificationType flags are SC_MOD_INSERTTEXT ,SC_MOD_DELETETEXT, + SC_MOD_BEFOREINSERT and SC_MOD_BEFORE_DELETE. They all use a + TextModifiedEventArgs which corresponds to a subset of the + SCNotification struct having to do with these modification types. + + + + + Overridden. + + + + + Initializes a new instance of the TextModifiedEventArgs class. + + document position where the change occured + _length of the change occured + the # of lines added or removed as a result of the change + affected text of the change + true if the change was a direct result of user interaction + the line # of where the marker change occured (if applicable) + + + + Returns true if the change was a direct result of user interaction + + + + + Returns the length of the change occured. + + + + + Returns the # of lines added or removed as a result of the change + + + + + Returns the line # of where the marker change occured (if applicable) + + + + + Returns the document position where the change occured + + + + + The affected text of the change + + + + + Defines a run of styled text in a control + + + + + Represents a new instance of the struct with member data left uninitialized. + + + + + Initializes a new instance of the struct. + + The length of the run. + The zero-based index of the style that the run represents. + + + + Gets or sets length of this . + + An representing the length of this . + + + + Gets or sets the style index of this . + + An representing the zero-based style index of this . + + + + Provides data for the MarkerChanged event + + + + + Initializes a new instance of the LinesNeedShownEventArgs class. + + Line number where the marker change occured + What type of Scintilla modification occured + + + + Returns the line number where the marker change occured + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Controls color mode fore printing + + + + + Normal + + + + + Inverts the colors + + + + + Black Text on white background + + + + + Styled color text on white background + + + + + Styled color text on white background for unstyled background colors + + + + + Provides data for the MarginClick event + + + + + Initializes a new instance of the MarginClickEventArgs class. + + + Any Modifier keys (shift, alt, ctrl) that were in use at the + time the click event occured + + Document position of the line where the click occured + Document line # where the click occured + Margin where the click occured + marker number that should be toggled in result of the click + Whether the fold at the current line should be toggled + + + + Returns the Document line # where the click occured + + + + + Returns the Margin where the click occured + + + + + Returns any Modifier keys (shift, alt, ctrl) that were in use at the + time the click event occured + + + + + Returns the Document position of the line where the click occured + + + + + Gets/Sets whether the fold at the current line should be toggled + + + + + Gets/Sets the marker number that should be toggled in result of the click + + + + + Controls line wrapping options in a control. + + + + + The number of lines displayed when a line of text is wrapped. + + The zero-based index of the line to count. + The numbers of display lines the line of text occupies. + + + + Forces the line range specified to wrap at the given pixel width. This operates independently + of the current line wrapping property. + + The zero-based line index to start wrapping. + The zero-based line index to stop wrapping. + + The maximum width in pixels of the lines to wrap. A value of zero resets forced line wrapping. + + + + + Initializes a new instance of the class. + + The control that created this object. + + + + Gets or sets how wrapped lines are indented. + + + One of the values. + The default is . + + + The value assigned is not one of the values. + + + + + Gets or sets the size that wrapped lines are indented when is . + + An representing the size (in characters) that wrapped lines are indented. + The value is less that zero or greater than 256. + + + + Gets or sets how and whether line wrapping is performed. + + + One of the values. + The default is . + + + The value assigned is not one of the values. + + + + + Gets or sets the visual glyphs displayed on wrapped lines. + + + A bitwise combination of the values. + The default is . + + + + + Gets or sets the location of visual glyphs displayed on wrapped lines. + + + A bitwise combination of the values. + The default is . + + + + + Enables the Smart Indenter so that On enter, it indents the next line. + + + + + For Custom Smart Indenting, assign a handler to this delegate property. + + + + + If Smart Indenting is enabled, this delegate will be added to the CharAdded multicast event. + + + + + Smart Indenting helper method + + + + + How long lines are visually indicated + + + + + No indication + + + + + A vertical line is displayed + + + + + The background color changes + + + + + Manages Document Navigation, which is a snapshot history of movements within + a document. + + + + + Causes the current position to navigate to the last snapshotted document position. + + + + + After 1 or more backwards navigations this command navigates to the previous + backwards navigation point. + + + + + List of entries that allow you to navigate backwards. + + + The ForwardStack and BackwardStack can be shared between multiple + ScintillaNET objects. This is useful in MDI applications when you wish + to have a shared document navigation that remembers positions in each + document. + + + + + Returns true if ScintillaNET can perform a successful backward navigation. + + + + + Returns true if ScintillaNET can perform a successful forward navigation. + + + + + List of entries that allow you to navigate forwards. + + + The ForwardStack and BackwardStack can be shared between multiple + ScintillaNET objects. This is useful in MDI applications when you wish + to have a shared document navigation that remembers positions in each + document. + + + + + Gets/Sets whether Document Navigation is tracked. Defaults to true. + + + + + Maximum number of places the document navigation remembers. Defaults to 50. + + + When the max value is reached the oldest entries are removed. + + + + + Time in milliseconds to wait before a Navigation Point is set. Default is 200 + + + In text editing, the current caret position is constantly changing. Rather than capture every + change in position, ScintillaNET captures the current position [NavigationPointTimeout]ms after a + position changes, only then is it eligable for another snapshot + + + + + Initializes a new instance of the CommandBindingConfig structure. + + + + + The CharacterSet used by the document + + + + + Provides data for the MacroRecorded event + + + + + Initializes a new instance of the MacroRecordEventArgs class. + + the recorded window message that can be sent back to the native Scintilla window + + + + Initializes a new instance of the MacroRecordEventArgs class. + + NativeScintillaEventArgs object containing the message data + + + + Returns the recorded window message that can be sent back to the native Scintilla window + + + + + Read or change the Flags associated with a fold. The default value is 0. + + + + + Read or change the Fold Marker Scheme. This changes the way Scintilla displays folds + in the control. The default is BoxPlusMinus and the value Custom can be used to disable + ScintillaNET changing selections made directly using MarkerCollection.FolderXX methods. + + + + + Read or change the value controlling whether to use compact folding from the lexer. + + This tracks the property "fold.compact" + + + + Manages DropMarkers, a Stack Based document bookmarking system. + + + + + Collects the last dropped DropMarker + + + When a DropMarker is collected the current document posision is moved + to the DropMarker posision, the DropMarker is removed from the stack + and the visual indicator is removed. + + + + + Drops a DropMarker at the current document position + + + Dropping a DropMarker creates a visual marker (red triangle) + indicating the DropMarker point. + + The newly created DropMarker + + + + Drops a DropMarker at the specified document position + + + The newly created DropMarker + + Dropping a DropMarker creates a visual marker (red triangle) + indicating the DropMarker point. + + + + + Gets/Sets a list of All DropMarkers specific to this Scintilla control + + + + + Gets/Sets the Stack of DropMarkers + + + You can manually set this to implement your own shared DropMarker stack + between Scintilla Controls. + + + + + + Gets/Sets a shared name associated with other Scintilla controls. + + + All Scintilla controls with the same SharedStackName share a common + DropMarker stack. This is useful in MDI applications where you want + the DropMarker stack not to be specific to one document. + + + + + Manages the Native Scintilla's Document features. + + + See Scintilla's documentation on multiple views for an understanding of Documents. + Note that all ScintillaNET specific features are considered to be part of the View, not document. + + + + + Creates a new Document + + + + + + Gets/Sets the currently loaded Document + + + + + Manages Caret Settings + + + The caret is the blinking line that indicates the current document position. This + is sometimes referred to as cursor. + + + + + Places the caret somewhere within the document that is displayed in the + Scintilla Window + + + If the caret is already visible in the current scrolled view this method does + nothing. + + + + + Scintilla remembers the x value of the last position horizontally moved to explicitly by the user and this value is then + used when moving vertically such as by using the up and down keys. This method sets the current x position of the caret as + the remembered value. + + + + + Scrolls the Scintilla window so that the Caret is visible. + + + + + Places the caret at the specified document position + + Position in the document to place the caret + + + + Gets/Sets the current anchor position + + + If the anchor position is less than the Caret Position it acts as the _start of + the selection. + + + + + Gets/Sets the time interval in milliseconds that the caret should blink. + + + This defaults to the system default value. + + + + + Gets/Sets the color of the Caret. + + Defaults to black + + + + Gets/Sets the transparency alpha of the CurrentLine Background highlight + + + Values range from 0 to 256. Default is 256. + + + + + Gets/Sets the color of the document line where the caret currently resides + + + The property must be set to true in order + for this to to take effect. + + + + + Gets/Sets if the current document line where the caret resides is highlighted. + + + determines the color. + + + + + Controls when the last position of the caret on the line is saved. When set to true, the position is not saved when you type a character, a tab, paste the clipboard content or press backspace + + + Defaults to false + + + + + Gets/Sets the current Line Number that the caret resides. + + + + + Gets/Sets the current document position where the caret resides + + + + + Gets/Sets the displayed. + + + + + Gets/Sets the width in pixels of the Caret + + + This defaults to the system default. + + + + + Provides data for the CallTipClick event + + + + + Initializes a new instance of the CallTipClickEventArgs class. + + CallTipArrow clicked + Current posision of the overload list + New position of the overload list + List of overloads to be cycled in the calltip + Start position of the highlighted text + End position of the highlighted text + + + + Returns the CallTipArrow that was clicked + + + + + Gets/Sets if the CallTip should be hidden + + + + + Gets the current index of the CallTip's overload list + + + + + Gets/Sets the _end position of the CallTip's highlighted portion of text + + + + + Gets/Sets the _start position of the CallTip's highlighted portion of text + + + + + Gets/Sets the new index of the CallTip's overload list + + + + + Returns the OverLoad list of the CallTip + + + + + Specifies how line wrapping visual glyphs are displayed in a control. + + + + + No line wrapping glyphs are displayed. + + + + + Line wrapping glyphs are displayed at the end of wrapped lines. + + + + + Line wrapping glyphs are displayed at the start of wrapped lines. This also has + the effect of indenting the line by one additional unit to accommodate the glyph. + + + + + This matches the Win32 NMHDR structure + + + + + Represents the Binding Combination of a Keyboard Key + Modifiers + + + + + Overridden. + + Another KeyBinding struct + True if the Keycode and Modifiers are equal + + + + Overridden + + Hashcode of ToString() + + + + Overridden. Returns string representation of the Keyboard shortcut + + Returns string representation of the Keyboard shortcut + + + + Initializes a new instance of the KeyBinding structure. + + Key to trigger command + key modifiers to the Keyboard shortcut + + + + Gets/Sets Key to trigger command + + + + + Gets sets key modifiers to the Keyboard shortcut + + + + + The flags affecting how the fold is marked in the main text area (as well as in the margin). If the value + changes for onscreen text, the display will redraw. + + + + + A line is drawn above the text if the fold is expanded. + + + + + A line is drawn above the text if the fold is collapsed. + + + + + A line is drawn below the text if the fold is expanded. + + + + + A line is drawn below the text if the fold is collapsed. + + + + + Display hexadecimal fold levels in line margin to aid debugging of folding. The appearance of this feature may change in the future. + + + + + Experimental feature that has been removed. + + + + + Represents an arrow in the CallTip + + + + + No arrow + + + + + The Up arrow + + + + + The Down Arrow + + + + + Represents a customizable read-only block of text which can be displayed below + each line in a control. + + + + + Removes all text and styles associated with the annotation. + + + + + Overridden. Determines whether the specified is equal to the current . + + The object to compare with the current object. + + true if the specified is equal to the + current ; otherwise, false. + + + + + Determines whether the specified is equal to the current . + + The annotation to compare with the current annotation. + + true if the specified is equal to the + current ; otherwise, false. + + + + + Overridden. Serves as a hash function for a particular type. + + A hash code for the current . + + + + Returns a enumerable representing the individual character styling of the annotation text. + + + A enumerable representing the individual character styling, + where the property of each run represents the number + of characters the run spans. + + + + + Uses the enumerable specified to individually style characters in the annotation text. + + + The enumerable indicating how to style the annotation text, + where the property of each run represents the number + of characters the run spans. + + is null. + + The property must be set prior to styling and the sum length of + all runs should match the text length. + + + + + Tests whether two object differ in location or content. + + The object that is to the left of the inequality operator. + The object that is to the right of the inequality operator. + true if the objects are considered unequal; otherwise, false. + + + + Tests whether two objects have equal location and content. + + The object that is to the left of the equality operator. + The object that is to the right of the equality operator. + true if the objects are considered equal; otherwise, false. + + + + Initializes a new instance of the class. + + The control that created this object. + The zero-based index of the document line containing the annotation. + + + + Gets the total number of text lines in the annotation. + + An representing the total number of text lines in the annotation. + + + + Gets the index of the document line containing the annotation. + + + An representing the zero-based index of the document line + containing the annotation, or -1 if the annotation has been rendered invalid + from a change in the control that created it. + + + + + Gets or sets the index of the style used to style the annotation text. + + + An representing the zero-based index of the style used to style the annotation text, + or -1 if the annotation has individually style characters. + + + + + Gets or sets the text of the annotation. + + A representing the annotation text, or null if there is no annotation. + + Only line feed characters ('\n') are recognized as line breaks. + All other control characters are not rendered. + + + + + Converts Bitmap images to XPM data for use with ScintillaNET. + Warning: images with more than (around) 50 colors will generate incorrect XPM + The XpmConverter class was based on code from flashdevelop. + + + + + The default transparent Color + + + + + Converts Bitmap images to XPM data for use with ScintillaNET. + Warning: images with more than (around) 50 colors will generate incorrect XPM. + Uses the DefaultTransparentColor. + + The image to transform. + + + + Converts Bitmap images to XPM data for use with ScintillaNET. + Warning: images with more than (around) 50 colors will generate incorrect XPM + tColor: specified transparent color in format: "#00FF00". + + The image to transform. + The overriding transparent Color + + + + Cicles an image list object to convert contained images into xpm + at the same time we add converted images into an arraylist that lets us to retrieve images later. + Uses the DefaultTransparentColor. + + The image list to transform. + + + + Cicles an image list object to convert contained images into xpm + at the same time we add converted images into an arraylist that lets us to retrieve images later + + The image list to transform. + The overriding transparent Color + + + + Provides data for Scintilla mouse events + + + + + Initializes a new instance of the ScintillaMouseEventArgs class. + + X (left) position of mouse in pixels + Y (top) position of mouse in pixels + Document position + + + + Returns the Document position + + + + + Returns the X (left) position of mouse in pixels + + + + + Returns the Y (top) position of mouse in pixels + + + + + Type of border to print for a Page Information section + + + + + No border + + + + + Border along the top + + + + + Border along the bottom + + + + + A full border around the page information section + + + + + Default Constructor + + + + + Full Constructor + + Margin to use + Font to use + Border style + What to print on the left side of the page + What to print in the center of the page + What to print on the right side of the page + + + + Normal Use Constructor + + Border style + What to print on the left side of the page + What to print in the center of the page + What to print on the right side of the page + + + + Defines a marker's appearance in a control. + + + + + Gets or sets the marker symbol. + + One of the values. The default is . + + The value assigned is not one of the values. + + + + + Data structure used to store DropMarkers in the AllDocumentDropMarkers property. + + + + + Provides data for the CharAdded event + + + + + Initializes a new instance of the CharAddedEventArgs class. + + The character that was added + + + + Returns the character that was added + + + + + Represents a collection of objects and options in a control. + + + Annotations are customizable read-only blocks of text which can be displayed below + each line in a control. + + + + + Removes all annotations from the document. + + This is equivalent to setting the property to null for each line. + + + + Creates and returns a new object. + + A new object. + + + + Returns an enumerator for the . + + An for the . + + + + Initializes a new instance of the class. + + The control that created this object. + + + + Gets the number of annotations in the . + + The number of annotations contained in the . + + As there can be one annotation per document line, + this is equivalent to the property. + + + + + Gets or sets the offset applied to style indexes used in annotations. + + The offset applied to style indexes used in annotations. + + Annotation styles may be completely separated from standard text styles by setting a style offset. + For example, a value of 512 would shift the range of possible annotation styles to be from 512 to 767 + so they do not overlap with standard text styles. This adjustment is applied automatically when setting + or calling so the offset should NOT be + manually factored in by the caller. This property is provided to maintain architectural symmetry with + the native Scintilla component but is an advanced feature and typically should never need to be changed. + + + + + Gets or sets the visibility style for all annotations. + + + One of the values. + The default is . + + + The value assigned is not one of the values. + + + + + Gets the annotation at the specified line index. + + The zero-based document line index of the annotation to get. + The at the specified line index. + + is less than zero. -or- + is equal to or greater than . + + + + + Specifies the line wrapping modes that can be applied to a control. + + + + + Line wrapping is disabled. + + + + + Lines wrap on word boundaries. + + + + + Lines wrap between characters. + + + + + Common predefined styles that are always valid with any lexer. + + + + + ScintillaNET derived class for handling printed page settings. It holds information + on how and what to print in the header and footer of pages. + + + + + Default footer style used when no footer is provided. + + + + + Default header style used when no header is provided. + + + + + Default constructor + + + + + Method used to render colored text on a printer + + + + + Number of points to add or subtract to the size of each screen font during printing + + + + + Page Information printed in the footer of the page + + + + + Page Information printed in header of the page + + + + + Controls find behavior for non-regular expression searches + + + + + Find must match the whole word + + + + + Find must match the case of the expression + + + + + Only match the _start of a word + + + + + Not used in ScintillaNET + + + + + Not used in ScintillaNET + + + + + Provides data for a DropMarkerCollect event + + + + + Initializes a new instance of the DropMarkerCollectEventArgs class. + + + + + Returns the DropMarker that was collected + + + + + Manages commands, which are actions in ScintillaNET that can be bound to key combinations. + + + + + Adds a key combination to a Command + + Character corresponding to a (keyboard) key to trigger command + Command to execute + + + + Adds a key combination to a Command + + Character corresponding to a (keyboard) key to trigger command + Shift, alt, ctrl + Command to execute + + + + Adds a key combination to a Command + + Key to trigger command + Command to execute + + + + Adds a key combination to a Command + + Key to trigger command + Shift, alt, ctrl + Command to execute + + + + Executes a Command + + Any + Value to indicate whether other bound commands should continue to execute + + + + Returns a list of Commands bound to a keyboard shortcut + + Character corresponding to a (keyboard) key to trigger command + List of Commands bound to a keyboard shortcut + + + + Returns a list of Commands bound to a keyboard shortcut + + Character corresponding to a (keyboard) key to trigger command + Shift, alt, ctrl + List of Commands bound to a keyboard shortcut + + + + Returns a list of Commands bound to a keyboard shortcut + + Key to trigger command + List of Commands bound to a keyboard shortcut + + + + Returns a list of Commands bound to a keyboard shortcut + + Key to trigger command + Shift, alt, ctrl + List of Commands bound to a keyboard shortcut + + + + Returns a list of KeyBindings bound to a given command + + Command to execute + List of KeyBindings bound to the given command + + + + Removes all key command bindings + + + Performing this action will make ScintillaNET virtually unusable until you assign new command bindings. + This removes even basic functionality like arrow keys, common clipboard commands, home/_end, etc. + + + + + Removes all commands bound to a keyboard shortcut + + Character corresponding to a (keyboard) key to trigger command + + + + Removes a keyboard shortcut / command combination + + Character corresponding to a (keyboard) key to trigger command + Command to execute + + + + Removes all commands bound to a keyboard shortcut + + Character corresponding to a (keyboard) key to trigger command + Shift, alt, ctrl + + + + Removes a keyboard shortcut / command combination + + Character corresponding to a (keyboard) key to trigger command + Shift, alt, ctrl + Command to execute + + + + Removes all commands bound to a keyboard shortcut + + Key to trigger command + + + + Removes a keyboard shortcut / command combination + + Key to trigger command + Command to execute + + + + Removes all commands bound to a keyboard shortcut + + Key to trigger command + Shift, alt, ctrl + + + + Removes a keyboard shortcut / command combination + + Key to trigger command + Shift, alt, ctrl + Command to execute + + + + Gets/Sets if a key combination can be bound to more than one command. (default is true) + + + When set to false only the first command bound to a key combination is kept. + Subsequent requests are ignored. + + + + + Specifies how wrapped lines are indented when line wrapping is enabled in a control. + + + + + Wrapped lines are aligned on the left and indented by the amount + spcified in the property. + + + + + Wrapped lines are aligned to the first subline indent. + + + + + Wrapped lines are aligned to the first subline indent plus + one more level of indentation. + + + + + List of commands that ScintillaNET can execute. These can be + bound to keyboard shortcuts + + + + + Provides data for the event. + + + + + Initializes a new instance of the class. + + The document line index of the annotation that changed. + The number of lines added to or removed from the annotation that changed. + + + + Gets the number of lines added to or removed from the changed annotation. + + + An representing the number of lines added to or removed from the annotation. + Postive values indicate lines have been added; negative values indicate lines have been removed. + + + + + Gets the index of the document line containing the changed annotation. + + The zero-based index of the document line containing the changed annotation. + + + diff --git a/WinFormsUI/Docking/AutoHideStripBase.cs b/WinFormsUI/Docking/AutoHideStripBase.cs new file mode 100644 index 0000000000..edc7461811 --- /dev/null +++ b/WinFormsUI/Docking/AutoHideStripBase.cs @@ -0,0 +1,540 @@ +using System; +using System.Collections; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public abstract partial class AutoHideStripBase : Control + { + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected class Tab : IDisposable + { + private IDockContent m_content; + + protected internal Tab(IDockContent content) + { + m_content = content; + } + + ~Tab() + { + Dispose(false); + } + + public IDockContent Content + { + get { return m_content; } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected sealed class TabCollection : IEnumerable + { + #region IEnumerable Members + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + #endregion + + internal TabCollection(DockPane pane) + { + m_dockPane = pane; + } + + private DockPane m_dockPane = null; + public DockPane DockPane + { + get { return m_dockPane; } + } + + public DockPanel DockPanel + { + get { return DockPane.DockPanel; } + } + + public int Count + { + get { return DockPane.DisplayingContents.Count; } + } + + public Tab this[int index] + { + get + { + IDockContent content = DockPane.DisplayingContents[index]; + if (content == null) + throw (new ArgumentOutOfRangeException("index")); + if (content.DockHandler.AutoHideTab == null) + content.DockHandler.AutoHideTab = (DockPanel.AutoHideStripControl.CreateTab(content)); + return content.DockHandler.AutoHideTab as Tab; + } + } + + public bool Contains(Tab tab) + { + return (IndexOf(tab) != -1); + } + + public bool Contains(IDockContent content) + { + return (IndexOf(content) != -1); + } + + public int IndexOf(Tab tab) + { + if (tab == null) + return -1; + + return IndexOf(tab.Content); + } + + public int IndexOf(IDockContent content) + { + return DockPane.DisplayingContents.IndexOf(content); + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected class Pane : IDisposable + { + private DockPane m_dockPane; + + protected internal Pane(DockPane dockPane) + { + m_dockPane = dockPane; + } + + ~Pane() + { + Dispose(false); + } + + public DockPane DockPane + { + get { return m_dockPane; } + } + + public TabCollection AutoHideTabs + { + get + { + if (DockPane.AutoHideTabs == null) + DockPane.AutoHideTabs = new TabCollection(DockPane); + return DockPane.AutoHideTabs as TabCollection; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected sealed class PaneCollection : IEnumerable + { + private class AutoHideState + { + public DockState m_dockState; + public bool m_selected = false; + + public AutoHideState(DockState dockState) + { + m_dockState = dockState; + } + + public DockState DockState + { + get { return m_dockState; } + } + + public bool Selected + { + get { return m_selected; } + set { m_selected = value; } + } + } + + private class AutoHideStateCollection + { + private AutoHideState[] m_states; + + public AutoHideStateCollection() + { + m_states = new AutoHideState[] { + new AutoHideState(DockState.DockTopAutoHide), + new AutoHideState(DockState.DockBottomAutoHide), + new AutoHideState(DockState.DockLeftAutoHide), + new AutoHideState(DockState.DockRightAutoHide) + }; + } + + public AutoHideState this[DockState dockState] + { + get + { + for (int i = 0; i < m_states.Length; i++) + { + if (m_states[i].DockState == dockState) + return m_states[i]; + } + throw new ArgumentOutOfRangeException("dockState"); + } + } + + public bool ContainsPane(DockPane pane) + { + if (pane.IsHidden) + return false; + + for (int i = 0; i < m_states.Length; i++) + { + if (m_states[i].DockState == pane.DockState && m_states[i].Selected) + return true; + } + return false; + } + } + + internal PaneCollection(DockPanel panel, DockState dockState) + { + m_dockPanel = panel; + m_states = new AutoHideStateCollection(); + States[DockState.DockTopAutoHide].Selected = (dockState == DockState.DockTopAutoHide); + States[DockState.DockBottomAutoHide].Selected = (dockState == DockState.DockBottomAutoHide); + States[DockState.DockLeftAutoHide].Selected = (dockState == DockState.DockLeftAutoHide); + States[DockState.DockRightAutoHide].Selected = (dockState == DockState.DockRightAutoHide); + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private AutoHideStateCollection m_states; + private AutoHideStateCollection States + { + get { return m_states; } + } + + public int Count + { + get + { + int count = 0; + foreach (DockPane pane in DockPanel.Panes) + { + if (States.ContainsPane(pane)) + count++; + } + + return count; + } + } + + public Pane this[int index] + { + get + { + int count = 0; + foreach (DockPane pane in DockPanel.Panes) + { + if (!States.ContainsPane(pane)) + continue; + + if (count == index) + { + if (pane.AutoHidePane == null) + pane.AutoHidePane = DockPanel.AutoHideStripControl.CreatePane(pane); + return pane.AutoHidePane as Pane; + } + + count++; + } + throw new ArgumentOutOfRangeException("index"); + } + } + + public bool Contains(Pane pane) + { + return (IndexOf(pane) != -1); + } + + public int IndexOf(Pane pane) + { + if (pane == null) + return -1; + + int index = 0; + foreach (DockPane dockPane in DockPanel.Panes) + { + if (!States.ContainsPane(pane.DockPane)) + continue; + + if (pane == dockPane.AutoHidePane) + return index; + + index++; + } + return -1; + } + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + #endregion + } + + protected AutoHideStripBase(DockPanel panel) + { + m_dockPanel = panel; + m_panesTop = new PaneCollection(panel, DockState.DockTopAutoHide); + m_panesBottom = new PaneCollection(panel, DockState.DockBottomAutoHide); + m_panesLeft = new PaneCollection(panel, DockState.DockLeftAutoHide); + m_panesRight = new PaneCollection(panel, DockState.DockRightAutoHide); + + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.Selectable, false); + } + + private DockPanel m_dockPanel; + protected DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private PaneCollection m_panesTop; + protected PaneCollection PanesTop + { + get { return m_panesTop; } + } + + private PaneCollection m_panesBottom; + protected PaneCollection PanesBottom + { + get { return m_panesBottom; } + } + + private PaneCollection m_panesLeft; + protected PaneCollection PanesLeft + { + get { return m_panesLeft; } + } + + private PaneCollection m_panesRight; + protected PaneCollection PanesRight + { + get { return m_panesRight; } + } + + protected PaneCollection GetPanes(DockState dockState) + { + if (dockState == DockState.DockTopAutoHide) + return PanesTop; + else if (dockState == DockState.DockBottomAutoHide) + return PanesBottom; + else if (dockState == DockState.DockLeftAutoHide) + return PanesLeft; + else if (dockState == DockState.DockRightAutoHide) + return PanesRight; + else + throw new ArgumentOutOfRangeException("dockState"); + } + + internal int GetNumberOfPanes(DockState dockState) + { + return GetPanes(dockState).Count; + } + + protected Rectangle RectangleTopLeft + { + get + { + int height = MeasureHeight(); + return PanesTop.Count > 0 && PanesLeft.Count > 0 ? new Rectangle(0, 0, height, height) : Rectangle.Empty; + } + } + + protected Rectangle RectangleTopRight + { + get + { + int height = MeasureHeight(); + return PanesTop.Count > 0 && PanesRight.Count > 0 ? new Rectangle(Width - height, 0, height, height) : Rectangle.Empty; + } + } + + protected Rectangle RectangleBottomLeft + { + get + { + int height = MeasureHeight(); + return PanesBottom.Count > 0 && PanesLeft.Count > 0 ? new Rectangle(0, Height - height, height, height) : Rectangle.Empty; + } + } + + protected Rectangle RectangleBottomRight + { + get + { + int height = MeasureHeight(); + return PanesBottom.Count > 0 && PanesRight.Count > 0 ? new Rectangle(Width - height, Height - height, height, height) : Rectangle.Empty; + } + } + + protected internal Rectangle GetTabStripRectangle(DockState dockState) + { + int height = MeasureHeight(); + if (dockState == DockState.DockTopAutoHide && PanesTop.Count > 0) + return new Rectangle(RectangleTopLeft.Width, 0, Width - RectangleTopLeft.Width - RectangleTopRight.Width, height); + else if (dockState == DockState.DockBottomAutoHide && PanesBottom.Count > 0) + return new Rectangle(RectangleBottomLeft.Width, Height - height, Width - RectangleBottomLeft.Width - RectangleBottomRight.Width, height); + else if (dockState == DockState.DockLeftAutoHide && PanesLeft.Count > 0) + return new Rectangle(0, RectangleTopLeft.Width, height, Height - RectangleTopLeft.Height - RectangleBottomLeft.Height); + else if (dockState == DockState.DockRightAutoHide && PanesRight.Count > 0) + return new Rectangle(Width - height, RectangleTopRight.Width, height, Height - RectangleTopRight.Height - RectangleBottomRight.Height); + else + return Rectangle.Empty; + } + + private GraphicsPath m_displayingArea = null; + private GraphicsPath DisplayingArea + { + get + { + if (m_displayingArea == null) + m_displayingArea = new GraphicsPath(); + + return m_displayingArea; + } + } + + private void SetRegion() + { + DisplayingArea.Reset(); + DisplayingArea.AddRectangle(RectangleTopLeft); + DisplayingArea.AddRectangle(RectangleTopRight); + DisplayingArea.AddRectangle(RectangleBottomLeft); + DisplayingArea.AddRectangle(RectangleBottomRight); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockTopAutoHide)); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockBottomAutoHide)); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockLeftAutoHide)); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockRightAutoHide)); + Region = new Region(DisplayingArea); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button != MouseButtons.Left) + return; + + IDockContent content = HitTest(); + if (content == null) + return; + + SetActiveAutoHideContent(content); + + content.DockHandler.Activate(); + } + + protected override void OnMouseHover(EventArgs e) + { + base.OnMouseHover(e); + + if (!DockPanel.ShowAutoHideContentOnHover) + return; + + IDockContent content = HitTest(); + SetActiveAutoHideContent(content); + + // requires further tracking of mouse hover behavior, + ResetMouseEventArgs(); + } + + private void SetActiveAutoHideContent(IDockContent content) + { + if (content != null && DockPanel.ActiveAutoHideContent != content) + DockPanel.ActiveAutoHideContent = content; + } + + protected override void OnLayout(LayoutEventArgs levent) + { + RefreshChanges(); + base.OnLayout (levent); + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + SetRegion(); + OnRefreshChanges(); + } + + protected virtual void OnRefreshChanges() + { + } + + protected internal abstract int MeasureHeight(); + + private IDockContent HitTest() + { + Point ptMouse = PointToClient(Control.MousePosition); + return HitTest(ptMouse); + } + + protected virtual Tab CreateTab(IDockContent content) + { + return new Tab(content); + } + + protected virtual Pane CreatePane(DockPane dockPane) + { + return new Pane(dockPane); + } + + protected abstract IDockContent HitTest(Point point); + } +} diff --git a/WinFormsUI/Docking/DockAreasEditor.cs b/WinFormsUI/Docking/DockAreasEditor.cs new file mode 100644 index 0000000000..921f602b98 --- /dev/null +++ b/WinFormsUI/Docking/DockAreasEditor.cs @@ -0,0 +1,142 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Design; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal class DockAreasEditor : UITypeEditor + { + private class DockAreasEditorControl : System.Windows.Forms.UserControl + { + private CheckBox checkBoxFloat; + private CheckBox checkBoxDockLeft; + private CheckBox checkBoxDockRight; + private CheckBox checkBoxDockTop; + private CheckBox checkBoxDockBottom; + private CheckBox checkBoxDockFill; + private DockAreas m_oldDockAreas; + + public DockAreas DockAreas + { + get + { + DockAreas dockAreas = 0; + if (checkBoxFloat.Checked) + dockAreas |= DockAreas.Float; + if (checkBoxDockLeft.Checked) + dockAreas |= DockAreas.DockLeft; + if (checkBoxDockRight.Checked) + dockAreas |= DockAreas.DockRight; + if (checkBoxDockTop.Checked) + dockAreas |= DockAreas.DockTop; + if (checkBoxDockBottom.Checked) + dockAreas |= DockAreas.DockBottom; + if (checkBoxDockFill.Checked) + dockAreas |= DockAreas.Document; + + if (dockAreas == 0) + return m_oldDockAreas; + else + return dockAreas; + } + } + + public DockAreasEditorControl() + { + checkBoxFloat = new CheckBox(); + checkBoxDockLeft = new CheckBox(); + checkBoxDockRight = new CheckBox(); + checkBoxDockTop = new CheckBox(); + checkBoxDockBottom = new CheckBox(); + checkBoxDockFill = new CheckBox(); + + SuspendLayout(); + + checkBoxFloat.Appearance = Appearance.Button; + checkBoxFloat.Dock = DockStyle.Top; + checkBoxFloat.Height = 24; + checkBoxFloat.Text = Strings.DockAreaEditor_FloatCheckBoxText; + checkBoxFloat.TextAlign = ContentAlignment.MiddleCenter; + checkBoxFloat.FlatStyle = FlatStyle.System; + + checkBoxDockLeft.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockLeft.Dock = System.Windows.Forms.DockStyle.Left; + checkBoxDockLeft.Width = 24; + checkBoxDockLeft.FlatStyle = FlatStyle.System; + + checkBoxDockRight.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockRight.Dock = System.Windows.Forms.DockStyle.Right; + checkBoxDockRight.Width = 24; + checkBoxDockRight.FlatStyle = FlatStyle.System; + + checkBoxDockTop.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockTop.Dock = System.Windows.Forms.DockStyle.Top; + checkBoxDockTop.Height = 24; + checkBoxDockTop.FlatStyle = FlatStyle.System; + + checkBoxDockBottom.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockBottom.Dock = System.Windows.Forms.DockStyle.Bottom; + checkBoxDockBottom.Height = 24; + checkBoxDockBottom.FlatStyle = FlatStyle.System; + + checkBoxDockFill.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockFill.Dock = System.Windows.Forms.DockStyle.Fill; + checkBoxDockFill.FlatStyle = FlatStyle.System; + + this.Controls.AddRange(new Control[] { + checkBoxDockFill, + checkBoxDockBottom, + checkBoxDockTop, + checkBoxDockRight, + checkBoxDockLeft, + checkBoxFloat}); + + Size = new System.Drawing.Size(160, 144); + BackColor = SystemColors.Control; + ResumeLayout(); + } + + public void SetStates(DockAreas dockAreas) + { + m_oldDockAreas = dockAreas; + if ((dockAreas & DockAreas.DockLeft) != 0) + checkBoxDockLeft.Checked = true; + if ((dockAreas & DockAreas.DockRight) != 0) + checkBoxDockRight.Checked = true; + if ((dockAreas & DockAreas.DockTop) != 0) + checkBoxDockTop.Checked = true; + if ((dockAreas & DockAreas.DockTop) != 0) + checkBoxDockTop.Checked = true; + if ((dockAreas & DockAreas.DockBottom) != 0) + checkBoxDockBottom.Checked = true; + if ((dockAreas & DockAreas.Document) != 0) + checkBoxDockFill.Checked = true; + if ((dockAreas & DockAreas.Float) != 0) + checkBoxFloat.Checked = true; + } + } + + private DockAreasEditor.DockAreasEditorControl m_ui = null; + + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.DropDown; + } + + public override object EditValue(ITypeDescriptorContext context, IServiceProvider sp, object value) + { + if (m_ui == null) + m_ui = new DockAreasEditor.DockAreasEditorControl(); + + m_ui.SetStates((DockAreas)value); + + IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)sp.GetService(typeof(IWindowsFormsEditorService)); + edSvc.DropDownControl(m_ui); + + return m_ui.DockAreas; + } + } +} diff --git a/WinFormsUI/Docking/DockContent.cs b/WinFormsUI/Docking/DockContent.cs new file mode 100644 index 0000000000..7c4579e330 --- /dev/null +++ b/WinFormsUI/Docking/DockContent.cs @@ -0,0 +1,374 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class DockContent : Form, IDockContent + { + public DockContent() + { + m_dockHandler = new DockContentHandler(this, new GetPersistStringCallback(GetPersistString)); + m_dockHandler.DockStateChanged += new EventHandler(DockHandler_DockStateChanged); + //Suggested as a fix by bensty regarding form resize + this.ParentChanged += new EventHandler(DockContent_ParentChanged); + } + + //Suggested as a fix by bensty regarding form resize + private void DockContent_ParentChanged(object Sender, EventArgs e) + { + if (this.Parent != null) + this.Font = this.Parent.Font; + } + + private DockContentHandler m_dockHandler = null; + [Browsable(false)] + public DockContentHandler DockHandler + { + get { return m_dockHandler; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_AllowEndUserDocking_Description")] + [DefaultValue(true)] + public bool AllowEndUserDocking + { + get { return DockHandler.AllowEndUserDocking; } + set { DockHandler.AllowEndUserDocking = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_DockAreas_Description")] + [DefaultValue(DockAreas.DockLeft|DockAreas.DockRight|DockAreas.DockTop|DockAreas.DockBottom|DockAreas.Document|DockAreas.Float)] + public DockAreas DockAreas + { + get { return DockHandler.DockAreas; } + set { DockHandler.DockAreas = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_AutoHidePortion_Description")] + [DefaultValue(0.25)] + public double AutoHidePortion + { + get { return DockHandler.AutoHidePortion; } + set { DockHandler.AutoHidePortion = value; } + } + + private string m_tabText = null; + [Localizable(true)] + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_TabText_Description")] + [DefaultValue(null)] + public string TabText + { + get { return m_tabText; } + set { DockHandler.TabText = m_tabText = value; } + } + + private bool ShouldSerializeTabText() + { + return (m_tabText != null); + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_CloseButton_Description")] + [DefaultValue(true)] + public bool CloseButton + { + get { return DockHandler.CloseButton; } + set { DockHandler.CloseButton = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_CloseButtonVisible_Description")] + [DefaultValue(true)] + public bool CloseButtonVisible + { + get { return DockHandler.CloseButtonVisible; } + set { DockHandler.CloseButtonVisible = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockPanel DockPanel + { + get { return DockHandler.DockPanel; } + set { DockHandler.DockPanel = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockState DockState + { + get { return DockHandler.DockState; } + set { DockHandler.DockState = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockPane Pane + { + get { return DockHandler.Pane; } + set { DockHandler.Pane = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsHidden + { + get { return DockHandler.IsHidden; } + set { DockHandler.IsHidden = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockState VisibleState + { + get { return DockHandler.VisibleState; } + set { DockHandler.VisibleState = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsFloat + { + get { return DockHandler.IsFloat; } + set { DockHandler.IsFloat = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockPane PanelPane + { + get { return DockHandler.PanelPane; } + set { DockHandler.PanelPane = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockPane FloatPane + { + get { return DockHandler.FloatPane; } + set { DockHandler.FloatPane = value; } + } + + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + protected virtual string GetPersistString() + { + return GetType().ToString(); + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_HideOnClose_Description")] + [DefaultValue(false)] + public bool HideOnClose + { + get { return DockHandler.HideOnClose; } + set { DockHandler.HideOnClose = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_ShowHint_Description")] + [DefaultValue(DockState.Unknown)] + public DockState ShowHint + { + get { return DockHandler.ShowHint; } + set { DockHandler.ShowHint = value; } + } + + [Browsable(false)] + public bool IsActivated + { + get { return DockHandler.IsActivated; } + } + + public bool IsDockStateValid(DockState dockState) + { + return DockHandler.IsDockStateValid(dockState); + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_TabPageContextMenu_Description")] + [DefaultValue(null)] + public ContextMenu TabPageContextMenu + { + get { return DockHandler.TabPageContextMenu; } + set { DockHandler.TabPageContextMenu = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_TabPageContextMenuStrip_Description")] + [DefaultValue(null)] + public ContextMenuStrip TabPageContextMenuStrip + { + get { return DockHandler.TabPageContextMenuStrip; } + set { DockHandler.TabPageContextMenuStrip = value; } + } + + [Localizable(true)] + [Category("Appearance")] + [LocalizedDescription("DockContent_ToolTipText_Description")] + [DefaultValue(null)] + public string ToolTipText + { + get { return DockHandler.ToolTipText; } + set { DockHandler.ToolTipText = value; } + } + + public new void Activate() + { + DockHandler.Activate(); + } + + public new void Hide() + { + DockHandler.Hide(); + } + + public new void Show() + { + DockHandler.Show(); + } + + public void Show(DockPanel dockPanel) + { + DockHandler.Show(dockPanel); + } + + public void Show(DockPanel dockPanel, DockState dockState) + { + DockHandler.Show(dockPanel, dockState); + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public void Show(DockPanel dockPanel, Rectangle floatWindowBounds) + { + DockHandler.Show(dockPanel, floatWindowBounds); + } + + public void Show(DockPane pane, IDockContent beforeContent) + { + DockHandler.Show(pane, beforeContent); + } + + public void Show(DockPane previousPane, DockAlignment alignment, double proportion) + { + DockHandler.Show(previousPane, alignment, proportion); + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public void FloatAt(Rectangle floatWindowBounds) + { + DockHandler.FloatAt(floatWindowBounds); + } + + public void DockTo(DockPane paneTo, DockStyle dockStyle, int contentIndex) + { + DockHandler.DockTo(paneTo, dockStyle, contentIndex); + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + DockHandler.DockTo(panel, dockStyle); + } + + #region IDockContent Members + void IDockContent.OnActivated(EventArgs e) + { + this.OnActivated(e); + } + + void IDockContent.OnDeactivate(EventArgs e) + { + this.OnDeactivate(e); + } + #endregion + + #region Events + private void DockHandler_DockStateChanged(object sender, EventArgs e) + { + OnDockStateChanged(e); + } + + private static readonly object DockStateChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("Pane_DockStateChanged_Description")] + public event EventHandler DockStateChanged + { + add { Events.AddHandler(DockStateChangedEvent, value); } + remove { Events.RemoveHandler(DockStateChangedEvent, value); } + } + protected virtual void OnDockStateChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[DockStateChangedEvent]; + if (handler != null) + handler(this, e); + } + #endregion + + /// + /// Overridden to avoid resize issues with nested controls + /// + /// + /// http://blogs.msdn.com/b/alejacma/archive/2008/11/20/controls-won-t-get-resized-once-the-nesting-hierarchy-of-windows-exceeds-a-certain-depth-x64.aspx + /// http://support.microsoft.com/kb/953934 + /// + protected override void OnSizeChanged(EventArgs e) + { + if (DockPanel != null && DockPanel.SupportDeeplyNestedContent && IsHandleCreated) + { + BeginInvoke((MethodInvoker)delegate + { + base.OnSizeChanged(e); + }); + } + else + { + base.OnSizeChanged(e); + } + } + + protected override void OnFormClosing(FormClosingEventArgs e) + { + if (Pane != null && Pane.DockPanel != null && Pane.DockPanel.CloseTabsToLeft && + Pane.ActiveContent == this && Pane.TabStripControl != null) + { + var tabs = Pane.TabStripControl.Tabs; + + if (tabs != null && tabs.Count > 1) + { + for (int i = 0; i < tabs.Count; i++) + { + if (tabs[i].Content == this) + { + DockContent dc = null; + + if (i > 0) + { + for (int j = i-1; j >= 0; j--) + { + if (tabs[j].Content is DockContent) + { + dc = tabs[j].Content as DockContent; + break; + } + } + } + + if(dc != null) + dc.Show(); + + break; + } + } + } + } + + base.OnFormClosing(e); + } + } +} diff --git a/WinFormsUI/Docking/DockContentCollection.cs b/WinFormsUI/Docking/DockContentCollection.cs new file mode 100644 index 0000000000..d6ee6bf09c --- /dev/null +++ b/WinFormsUI/Docking/DockContentCollection.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class DockContentCollection : ReadOnlyCollection + { + private static List _emptyList = new List(0); + + internal DockContentCollection() + : base(new List()) + { + } + + internal DockContentCollection(DockPane pane) + : base(_emptyList) + { + m_dockPane = pane; + } + + private DockPane m_dockPane = null; + private DockPane DockPane + { + get { return m_dockPane; } + } + + public new IDockContent this[int index] + { + get + { + if (DockPane == null) + return Items[index] as IDockContent; + else + return GetVisibleContent(index); + } + } + + internal int Add(IDockContent content) + { +#if DEBUG + if (DockPane != null) + throw new InvalidOperationException(); +#endif + + if (Contains(content)) + return IndexOf(content); + + Items.Add(content); + return Count - 1; + } + + internal void AddAt(IDockContent content, int index) + { +#if DEBUG + if (DockPane != null) + throw new InvalidOperationException(); +#endif + + if (index < 0 || index > Items.Count - 1) + return; + + if (Contains(content)) + return; + + Items.Insert(index, content); + } + + public new bool Contains(IDockContent content) + { + if (DockPane == null) + return Items.Contains(content); + else + return (GetIndexOfVisibleContents(content) != -1); + } + + public new int Count + { + get + { + if (DockPane == null) + return base.Count; + else + return CountOfVisibleContents; + } + } + + public new int IndexOf(IDockContent content) + { + if (DockPane == null) + { + if (!Contains(content)) + return -1; + else + return Items.IndexOf(content); + } + else + return GetIndexOfVisibleContents(content); + } + + internal void Remove(IDockContent content) + { + if (DockPane != null) + throw new InvalidOperationException(); + + if (!Contains(content)) + return; + + Items.Remove(content); + } + + private int CountOfVisibleContents + { + get + { +#if DEBUG + if (DockPane == null) + throw new InvalidOperationException(); +#endif + + int count = 0; + foreach (IDockContent content in DockPane.Contents) + { + if (content.DockHandler.DockState == DockPane.DockState) + count++; + } + return count; + } + } + + private IDockContent GetVisibleContent(int index) + { +#if DEBUG + if (DockPane == null) + throw new InvalidOperationException(); +#endif + + int currentIndex = -1; + foreach (IDockContent content in DockPane.Contents) + { + if (content.DockHandler.DockState == DockPane.DockState) + currentIndex++; + + if (currentIndex == index) + return content; + } + throw (new ArgumentOutOfRangeException()); + } + + private int GetIndexOfVisibleContents(IDockContent content) + { +#if DEBUG + if (DockPane == null) + throw new InvalidOperationException(); +#endif + + if (content == null) + return -1; + + int index = -1; + foreach (IDockContent c in DockPane.Contents) + { + if (c.DockHandler.DockState == DockPane.DockState) + { + index++; + + if (c == content) + return index; + } + } + return -1; + } + } +} diff --git a/WinFormsUI/Docking/DockContentEventArgs.cs b/WinFormsUI/Docking/DockContentEventArgs.cs new file mode 100644 index 0000000000..92a9362bbb --- /dev/null +++ b/WinFormsUI/Docking/DockContentEventArgs.cs @@ -0,0 +1,19 @@ +using System; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class DockContentEventArgs : EventArgs + { + private IDockContent m_content; + + public DockContentEventArgs(IDockContent content) + { + m_content = content; + } + + public IDockContent Content + { + get { return m_content; } + } + } +} diff --git a/WinFormsUI/Docking/DockContentHandler.cs b/WinFormsUI/Docking/DockContentHandler.cs new file mode 100644 index 0000000000..f872b22b25 --- /dev/null +++ b/WinFormsUI/Docking/DockContentHandler.cs @@ -0,0 +1,1146 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public delegate string GetPersistStringCallback(); + + public class DockContentHandler : IDisposable, IDockDragSource + { + public DockContentHandler(Form form) : this(form, null) + { + } + + public DockContentHandler(Form form, GetPersistStringCallback getPersistStringCallback) + { + if (!(form is IDockContent)) + throw new ArgumentException(Strings.DockContent_Constructor_InvalidForm, "form"); + + m_form = form; + m_getPersistStringCallback = getPersistStringCallback; + + m_events = new EventHandlerList(); + Form.Disposed +=new EventHandler(Form_Disposed); + Form.TextChanged += new EventHandler(Form_TextChanged); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + DockPanel = null; + if (m_autoHideTab != null) + m_autoHideTab.Dispose(); + if (m_tab != null) + m_tab.Dispose(); + + Form.Disposed -= new EventHandler(Form_Disposed); + Form.TextChanged -= new EventHandler(Form_TextChanged); + m_events.Dispose(); + } + } + + private Form m_form; + public Form Form + { + get { return m_form; } + } + + public IDockContent Content + { + get { return Form as IDockContent; } + } + + private IDockContent m_previousActive = null; + public IDockContent PreviousActive + { + get { return m_previousActive; } + internal set { m_previousActive = value; } + } + + private IDockContent m_nextActive = null; + public IDockContent NextActive + { + get { return m_nextActive; } + internal set { m_nextActive = value; } + } + + private EventHandlerList m_events; + private EventHandlerList Events + { + get { return m_events; } + } + + private bool m_allowEndUserDocking = true; + public bool AllowEndUserDocking + { + get { return m_allowEndUserDocking; } + set { m_allowEndUserDocking = value; } + } + + private double m_autoHidePortion = 0.25; + public double AutoHidePortion + { + get { return m_autoHidePortion; } + set + { + if (value <= 0) + throw(new ArgumentOutOfRangeException(Strings.DockContentHandler_AutoHidePortion_OutOfRange)); + + if (m_autoHidePortion == value) + return; + + m_autoHidePortion = value; + + if (DockPanel == null) + return; + + if (DockPanel.ActiveAutoHideContent == Content) + DockPanel.PerformLayout(); + } + } + + private bool m_closeButton = true; + public bool CloseButton + { + get { return m_closeButton; } + set + { + if (m_closeButton == value) + return; + + m_closeButton = value; + if (IsActiveContentHandler) + Pane.RefreshChanges(); + } + } + + private bool m_closeButtonVisible = true; + /// + /// Determines whether the close button is visible on the content + /// + public bool CloseButtonVisible + { + get { return m_closeButtonVisible; } + set + { + if (m_closeButtonVisible == value) + return; + + m_closeButtonVisible = value; + if (IsActiveContentHandler) + Pane.RefreshChanges(); + } + } + + private bool IsActiveContentHandler + { + get { return Pane != null && Pane.ActiveContent != null && Pane.ActiveContent.DockHandler == this; } + } + + private DockState DefaultDockState + { + get + { + if (ShowHint != DockState.Unknown && ShowHint != DockState.Hidden) + return ShowHint; + + if ((DockAreas & DockAreas.Document) != 0) + return DockState.Document; + if ((DockAreas & DockAreas.DockRight) != 0) + return DockState.DockRight; + if ((DockAreas & DockAreas.DockLeft) != 0) + return DockState.DockLeft; + if ((DockAreas & DockAreas.DockBottom) != 0) + return DockState.DockBottom; + if ((DockAreas & DockAreas.DockTop) != 0) + return DockState.DockTop; + + return DockState.Unknown; + } + } + + private DockState DefaultShowState + { + get + { + if (ShowHint != DockState.Unknown) + return ShowHint; + + if ((DockAreas & DockAreas.Document) != 0) + return DockState.Document; + if ((DockAreas & DockAreas.DockRight) != 0) + return DockState.DockRight; + if ((DockAreas & DockAreas.DockLeft) != 0) + return DockState.DockLeft; + if ((DockAreas & DockAreas.DockBottom) != 0) + return DockState.DockBottom; + if ((DockAreas & DockAreas.DockTop) != 0) + return DockState.DockTop; + if ((DockAreas & DockAreas.Float) != 0) + return DockState.Float; + + return DockState.Unknown; + } + } + + private DockAreas m_allowedAreas = DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.DockBottom | DockAreas.Document | DockAreas.Float; + public DockAreas DockAreas + { + get { return m_allowedAreas; } + set + { + if (m_allowedAreas == value) + return; + + if (!DockHelper.IsDockStateValid(DockState, value)) + throw(new InvalidOperationException(Strings.DockContentHandler_DockAreas_InvalidValue)); + + m_allowedAreas = value; + + if (!DockHelper.IsDockStateValid(ShowHint, m_allowedAreas)) + ShowHint = DockState.Unknown; + } + } + + private DockState m_dockState = DockState.Unknown; + public DockState DockState + { + get { return m_dockState; } + set + { + if (m_dockState == value) + return; + + DockPanel.SuspendLayout(true); + + if (value == DockState.Hidden) + IsHidden = true; + else + SetDockState(false, value, Pane); + + DockPanel.ResumeLayout(true, true); + } + } + + private DockPanel m_dockPanel = null; + public DockPanel DockPanel + { + get { return m_dockPanel; } + set + { + if (m_dockPanel == value) + return; + + Pane = null; + + if (m_dockPanel != null) + m_dockPanel.RemoveContent(Content); + + if (m_tab != null) + { + m_tab.Dispose(); + m_tab = null; + } + + if (m_autoHideTab != null) + { + m_autoHideTab.Dispose(); + m_autoHideTab = null; + } + + m_dockPanel = value; + + if (m_dockPanel != null) + { + m_dockPanel.AddContent(Content); + Form.TopLevel = false; + Form.FormBorderStyle = FormBorderStyle.None; + Form.ShowInTaskbar = false; + Form.WindowState = FormWindowState.Normal; + if (Win32Helper.IsRunningOnMono) + return; + + NativeMethods.SetWindowPos(Form.Handle, IntPtr.Zero, 0, 0, 0, 0, + Win32.FlagsSetWindowPos.SWP_NOACTIVATE | + Win32.FlagsSetWindowPos.SWP_NOMOVE | + Win32.FlagsSetWindowPos.SWP_NOSIZE | + Win32.FlagsSetWindowPos.SWP_NOZORDER | + Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER | + Win32.FlagsSetWindowPos.SWP_FRAMECHANGED); + } + } + } + + public Icon Icon + { + get { return Form.Icon; } + } + + public DockPane Pane + { + get { return IsFloat ? FloatPane : PanelPane; } + set + { + if (Pane == value) + return; + + DockPanel.SuspendLayout(true); + + DockPane oldPane = Pane; + + SuspendSetDockState(); + FloatPane = (value == null ? null : (value.IsFloat ? value : FloatPane)); + PanelPane = (value == null ? null : (value.IsFloat ? PanelPane : value)); + ResumeSetDockState(IsHidden, value != null ? value.DockState : DockState.Unknown, oldPane); + + DockPanel.ResumeLayout(true, true); + } + } + + private bool m_isHidden = true; + public bool IsHidden + { + get { return m_isHidden; } + set + { + if (m_isHidden == value) + return; + + SetDockState(value, VisibleState, Pane); + } + } + + private string m_tabText = null; + public string TabText + { + get { return m_tabText == null || m_tabText == "" ? Form.Text : m_tabText; } + set + { + if (m_tabText == value) + return; + + m_tabText = value; + if (Pane != null) + Pane.RefreshChanges(); + } + } + + private DockState m_visibleState = DockState.Unknown; + public DockState VisibleState + { + get { return m_visibleState; } + set + { + if (m_visibleState == value) + return; + + SetDockState(IsHidden, value, Pane); + } + } + + private bool m_isFloat = false; + public bool IsFloat + { + get { return m_isFloat; } + set + { + if (m_isFloat == value) + return; + + DockState visibleState = CheckDockState(value); + + if (visibleState == DockState.Unknown) + throw new InvalidOperationException(Strings.DockContentHandler_IsFloat_InvalidValue); + + SetDockState(IsHidden, visibleState, Pane); + } + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public DockState CheckDockState(bool isFloat) + { + DockState dockState; + + if (isFloat) + { + if (!IsDockStateValid(DockState.Float)) + dockState = DockState.Unknown; + else + dockState = DockState.Float; + } + else + { + dockState = (PanelPane != null) ? PanelPane.DockState : DefaultDockState; + if (dockState != DockState.Unknown && !IsDockStateValid(dockState)) + dockState = DockState.Unknown; + } + + return dockState; + } + + private DockPane m_panelPane = null; + public DockPane PanelPane + { + get { return m_panelPane; } + set + { + if (m_panelPane == value) + return; + + if (value != null) + { + if (value.IsFloat || value.DockPanel != DockPanel) + throw new InvalidOperationException(Strings.DockContentHandler_DockPane_InvalidValue); + } + + DockPane oldPane = Pane; + + if (m_panelPane != null) + RemoveFromPane(m_panelPane); + m_panelPane = value; + if (m_panelPane != null) + { + m_panelPane.AddContent(Content); + SetDockState(IsHidden, IsFloat ? DockState.Float : m_panelPane.DockState, oldPane); + } + else + SetDockState(IsHidden, DockState.Unknown, oldPane); + } + } + + private void RemoveFromPane(DockPane pane) + { + pane.RemoveContent(Content); + SetPane(null); + if (pane.Contents.Count == 0) + pane.Dispose(); + } + + private DockPane m_floatPane = null; + public DockPane FloatPane + { + get { return m_floatPane; } + set + { + if (m_floatPane == value) + return; + + if (value != null) + { + if (!value.IsFloat || value.DockPanel != DockPanel) + throw new InvalidOperationException(Strings.DockContentHandler_FloatPane_InvalidValue); + } + + DockPane oldPane = Pane; + + if (m_floatPane != null) + RemoveFromPane(m_floatPane); + m_floatPane = value; + if (m_floatPane != null) + { + m_floatPane.AddContent(Content); + SetDockState(IsHidden, IsFloat ? DockState.Float : VisibleState, oldPane); + } + else + SetDockState(IsHidden, DockState.Unknown, oldPane); + } + } + + private int m_countSetDockState = 0; + private void SuspendSetDockState() + { + m_countSetDockState ++; + } + + private void ResumeSetDockState() + { + m_countSetDockState --; + if (m_countSetDockState < 0) + m_countSetDockState = 0; + } + + internal bool IsSuspendSetDockState + { + get { return m_countSetDockState != 0; } + } + + private void ResumeSetDockState(bool isHidden, DockState visibleState, DockPane oldPane) + { + ResumeSetDockState(); + SetDockState(isHidden, visibleState, oldPane); + } + + internal void SetDockState(bool isHidden, DockState visibleState, DockPane oldPane) + { + if (IsSuspendSetDockState) + return; + + if (DockPanel == null && visibleState != DockState.Unknown) + throw new InvalidOperationException(Strings.DockContentHandler_SetDockState_NullPanel); + + if (visibleState == DockState.Hidden || (visibleState != DockState.Unknown && !IsDockStateValid(visibleState))) + throw new InvalidOperationException(Strings.DockContentHandler_SetDockState_InvalidState); + + DockPanel dockPanel = DockPanel; + if (dockPanel != null) + dockPanel.SuspendLayout(true); + + SuspendSetDockState(); + + DockState oldDockState = DockState; + + if (m_isHidden != isHidden || oldDockState == DockState.Unknown) + { + m_isHidden = isHidden; + } + m_visibleState = visibleState; + m_dockState = isHidden ? DockState.Hidden : visibleState; + + if (visibleState == DockState.Unknown) + Pane = null; + else + { + m_isFloat = (m_visibleState == DockState.Float); + + if (Pane == null) + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, visibleState, true); + else if (Pane.DockState != visibleState) + { + if (Pane.Contents.Count == 1) + Pane.SetDockState(visibleState); + else + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, visibleState, true); + } + } + + if (Form.ContainsFocus) + { + if (DockState == DockState.Hidden || DockState == DockState.Unknown) + { + if (!Win32Helper.IsRunningOnMono) + { + DockPanel.ContentFocusManager.GiveUpFocus(Content); + } + } + } + + SetPaneAndVisible(Pane); + + if (oldPane != null && !oldPane.IsDisposed && oldDockState == oldPane.DockState) + RefreshDockPane(oldPane); + + if (Pane != null && DockState == Pane.DockState) + { + if ((Pane != oldPane) || + (Pane == oldPane && oldDockState != oldPane.DockState)) + { + // Avoid early refresh of hidden AutoHide panes + if ((Pane.DockWindow == null || Pane.DockWindow.Visible || Pane.IsHidden) && !Pane.IsAutoHide) + { + RefreshDockPane(Pane); + } + } + } + + if (oldDockState != DockState) + { + if (DockState == DockState.Hidden || DockState == DockState.Unknown || + DockHelper.IsDockStateAutoHide(DockState)) + { + if (!Win32Helper.IsRunningOnMono) + { + DockPanel.ContentFocusManager.RemoveFromList(Content); + } + } + else if (!Win32Helper.IsRunningOnMono) + { + DockPanel.ContentFocusManager.AddToList(Content); + } + + ResetAutoHidePortion(oldDockState, DockState); + OnDockStateChanged(EventArgs.Empty); + } + + ResumeSetDockState(); + + if (dockPanel != null) + dockPanel.ResumeLayout(true, true); + } + + private void ResetAutoHidePortion(DockState oldState, DockState newState) + { + if (oldState == newState || DockHelper.ToggleAutoHideState(oldState) == newState) + return; + + switch (newState) + { + case DockState.DockTop: + case DockState.DockTopAutoHide: + AutoHidePortion = DockPanel.DockTopPortion; + break; + case DockState.DockLeft: + case DockState.DockLeftAutoHide: + AutoHidePortion = DockPanel.DockLeftPortion; + break; + case DockState.DockBottom: + case DockState.DockBottomAutoHide: + AutoHidePortion = DockPanel.DockBottomPortion; + break; + case DockState.DockRight: + case DockState.DockRightAutoHide: + AutoHidePortion = DockPanel.DockRightPortion; + break; + } + } + + private static void RefreshDockPane(DockPane pane) + { + pane.RefreshChanges(); + pane.ValidateActiveContent(); + } + + internal string PersistString + { + get { return GetPersistStringCallback == null ? Form.GetType().ToString() : GetPersistStringCallback(); } + } + + private GetPersistStringCallback m_getPersistStringCallback = null; + public GetPersistStringCallback GetPersistStringCallback + { + get { return m_getPersistStringCallback; } + set { m_getPersistStringCallback = value; } + } + + + private bool m_hideOnClose = false; + public bool HideOnClose + { + get { return m_hideOnClose; } + set { m_hideOnClose = value; } + } + + private DockState m_showHint = DockState.Unknown; + public DockState ShowHint + { + get { return m_showHint; } + set + { + if (!DockHelper.IsDockStateValid(value, DockAreas)) + throw (new InvalidOperationException(Strings.DockContentHandler_ShowHint_InvalidValue)); + + if (m_showHint == value) + return; + + m_showHint = value; + } + } + + private bool m_isActivated = false; + public bool IsActivated + { + get { return m_isActivated; } + internal set + { + if (m_isActivated == value) + return; + + m_isActivated = value; + } + } + + public bool IsDockStateValid(DockState dockState) + { + if (DockPanel != null && dockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.SystemMdi) + return false; + else + return DockHelper.IsDockStateValid(dockState, DockAreas); + } + + private ContextMenu m_tabPageContextMenu = null; + public ContextMenu TabPageContextMenu + { + get { return m_tabPageContextMenu; } + set { m_tabPageContextMenu = value; } + } + + private string m_toolTipText = null; + public string ToolTipText + { + get { return m_toolTipText; } + set { m_toolTipText = value; } + } + + public void Activate() + { + if (DockPanel == null) + Form.Activate(); + else if (Pane == null) + Show(DockPanel); + else + { + IsHidden = false; + Pane.ActiveContent = Content; + if (DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.SystemMdi) + { + Form.Activate(); + return; + } + else if (DockHelper.IsDockStateAutoHide(DockState)) + { + if (DockPanel.ActiveAutoHideContent != Content) + { + DockPanel.ActiveAutoHideContent = null; + return; + } + } + + if (Form.ContainsFocus) + return; + + if (Win32Helper.IsRunningOnMono) + return; + + DockPanel.ContentFocusManager.Activate(Content); + } + } + + public void GiveUpFocus() + { + if (!Win32Helper.IsRunningOnMono) + DockPanel.ContentFocusManager.GiveUpFocus(Content); + } + + private IntPtr m_activeWindowHandle = IntPtr.Zero; + internal IntPtr ActiveWindowHandle + { + get { return m_activeWindowHandle; } + set { m_activeWindowHandle = value; } + } + + public void Hide() + { + IsHidden = true; + } + + internal void SetPaneAndVisible(DockPane pane) + { + SetPane(pane); + SetVisible(); + } + + private void SetPane(DockPane pane) + { + if (pane != null && pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi) + { + if (Form.Parent is DockPane) + SetParent(null); + if (Form.MdiParent != DockPanel.ParentForm) + { + FlagClipWindow = true; + Form.MdiParent = DockPanel.ParentForm; + } + } + else + { + FlagClipWindow = true; + if (Form.MdiParent != null) + Form.MdiParent = null; + if (Form.TopLevel) + Form.TopLevel = false; + SetParent(pane); + } + } + + internal void SetVisible() + { + bool visible; + + if (IsHidden) + visible = false; + else if (Pane != null && Pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi) + visible = true; + else if (Pane != null && Pane.ActiveContent == Content) + visible = true; + else if (Pane != null && Pane.ActiveContent != Content) + visible = false; + else + visible = Form.Visible; + + if (Form.Visible != visible) + Form.Visible = visible; + } + + private void SetParent(Control value) + { + if (Form.Parent == value) + return; + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Workaround of .Net Framework bug: + // Change the parent of a control with focus may result in the first + // MDI child form get activated. + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + bool bRestoreFocus = false; + if (Form.ContainsFocus) + { + // Suggested as a fix for a memory leak by bugreports + if (value == null && !IsFloat) + { + if (!Win32Helper.IsRunningOnMono) + { + DockPanel.ContentFocusManager.GiveUpFocus(this.Content); + } + } + else + { + DockPanel.SaveFocus(); + bRestoreFocus = true; + } + } + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + Form.Parent = value; + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Workaround of .Net Framework bug: + // Change the parent of a control with focus may result in the first + // MDI child form get activated. + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if (bRestoreFocus) + Activate(); + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + } + + public void Show() + { + if (DockPanel == null) + Form.Show(); + else + Show(DockPanel); + } + + public void Show(DockPanel dockPanel) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel)); + + if (DockState == DockState.Unknown) + Show(dockPanel, DefaultShowState); + else + Activate(); + } + + public void Show(DockPanel dockPanel, DockState dockState) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel)); + + if (dockState == DockState.Unknown || dockState == DockState.Hidden) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidDockState)); + + dockPanel.SuspendLayout(true); + + DockPanel = dockPanel; + + if (dockState == DockState.Float && FloatPane == null) + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Float, true); + else if (PanelPane == null) + { + DockPane paneExisting = null; + foreach (DockPane pane in DockPanel.Panes) + if (pane.DockState == dockState) + { + if (paneExisting == null || pane.IsActivated) + paneExisting = pane; + + if (pane.IsActivated) + break; + } + + if (paneExisting == null) + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, dockState, true); + else + Pane = paneExisting; + } + + DockState = dockState; + dockPanel.ResumeLayout(true, true); //we'll resume the layout before activating to ensure that the position + Activate(); //and size of the form are finally processed before the form is shown + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public void Show(DockPanel dockPanel, Rectangle floatWindowBounds) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel)); + + dockPanel.SuspendLayout(true); + + DockPanel = dockPanel; + if (FloatPane == null) + { + IsHidden = true; // to reduce the screen flicker + FloatPane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Float, false); + FloatPane.FloatWindow.StartPosition = FormStartPosition.Manual; + } + + FloatPane.FloatWindow.Bounds = floatWindowBounds; + + Show(dockPanel, DockState.Float); + Activate(); + + dockPanel.ResumeLayout(true, true); + } + + public void Show(DockPane pane, IDockContent beforeContent) + { + if (pane == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullPane)); + + if (beforeContent != null && pane.Contents.IndexOf(beforeContent) == -1) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidBeforeContent)); + + pane.DockPanel.SuspendLayout(true); + + DockPanel = pane.DockPanel; + Pane = pane; + pane.SetContentIndex(Content, pane.Contents.IndexOf(beforeContent)); + Show(); + + pane.DockPanel.ResumeLayout(true, true); + } + + public void Show(DockPane previousPane, DockAlignment alignment, double proportion) + { + if (previousPane == null) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidPrevPane)); + + if (DockHelper.IsDockStateAutoHide(previousPane.DockState)) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidPrevPane)); + + previousPane.DockPanel.SuspendLayout(true); + + DockPanel = previousPane.DockPanel; + DockPanel.DockPaneFactory.CreateDockPane(Content, previousPane, alignment, proportion, true); + Show(); + + previousPane.DockPanel.ResumeLayout(true, true); + } + + public void Close() + { + DockPanel dockPanel = DockPanel; + if (dockPanel != null) + dockPanel.SuspendLayout(true); + Form.Close(); + if (dockPanel != null) + dockPanel.ResumeLayout(true, true); + + } + + private DockPaneStripBase.Tab m_tab = null; + internal DockPaneStripBase.Tab GetTab(DockPaneStripBase dockPaneStrip) + { + if (m_tab == null) + m_tab = dockPaneStrip.CreateTab(Content); + + return m_tab; + } + + private IDisposable m_autoHideTab = null; + internal IDisposable AutoHideTab + { + get { return m_autoHideTab; } + set { m_autoHideTab = value; } + } + + #region Events + private static readonly object DockStateChangedEvent = new object(); + public event EventHandler DockStateChanged + { + add { Events.AddHandler(DockStateChangedEvent, value); } + remove { Events.RemoveHandler(DockStateChangedEvent, value); } + } + protected virtual void OnDockStateChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[DockStateChangedEvent]; + if (handler != null) + handler(this, e); + } + #endregion + + private void Form_Disposed(object sender, EventArgs e) + { + Dispose(); + } + + private void Form_TextChanged(object sender, EventArgs e) + { + if (DockHelper.IsDockStateAutoHide(DockState)) + DockPanel.RefreshAutoHideStrip(); + else if (Pane != null) + { + if (Pane.FloatWindow != null) + Pane.FloatWindow.SetText(); + Pane.RefreshChanges(); + } + } + + private bool m_flagClipWindow = false; + internal bool FlagClipWindow + { + get { return m_flagClipWindow; } + set + { + if (m_flagClipWindow == value) + return; + + m_flagClipWindow = value; + if (m_flagClipWindow) + Form.Region = new Region(Rectangle.Empty); + else + Form.Region = null; + } + } + + private ContextMenuStrip m_tabPageContextMenuStrip = null; + public ContextMenuStrip TabPageContextMenuStrip + { + get { return m_tabPageContextMenuStrip; } + set { m_tabPageContextMenuStrip = value; } + } + + #region IDockDragSource Members + + Control IDragSource.DragControl + { + get { return Form; } + } + + bool IDockDragSource.CanDockTo(DockPane pane) + { + if (!IsDockStateValid(pane.DockState)) + return false; + + if (Pane == pane && pane.DisplayingContents.Count == 1) + return false; + + return true; + } + + Rectangle IDockDragSource.BeginDrag(Point ptMouse) + { + Size size; + DockPane floatPane = this.FloatPane; + if (DockState == DockState.Float || floatPane == null || floatPane.FloatWindow.NestedPanes.Count != 1) + size = DockPanel.DefaultFloatWindowSize; + else + size = floatPane.FloatWindow.Size; + + Point location; + Rectangle rectPane = Pane.ClientRectangle; + if (DockState == DockState.Document) + { + if (Pane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + location = new Point(rectPane.Left, rectPane.Bottom - size.Height); + else + location = new Point(rectPane.Left, rectPane.Top); + } + else + { + location = new Point(rectPane.Left, rectPane.Bottom); + location.Y -= size.Height; + } + location = Pane.PointToScreen(location); + + if (ptMouse.X > location.X + size.Width) + location.X += ptMouse.X - (location.X + size.Width) + Measures.SplitterSize; + + return new Rectangle(location, size); + } + + void IDockDragSource.EndDrag() + { + } + + public void FloatAt(Rectangle floatWindowBounds) + { + DockPane pane = DockPanel.DockPaneFactory.CreateDockPane(Content, floatWindowBounds, true); + } + + public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex) + { + if (dockStyle == DockStyle.Fill) + { + bool samePane = (Pane == pane); + if (!samePane) + Pane = pane; + + if (contentIndex == -1 || !samePane) + pane.SetContentIndex(Content, contentIndex); + else + { + DockContentCollection contents = pane.Contents; + int oldIndex = contents.IndexOf(Content); + int newIndex = contentIndex; + if (oldIndex < newIndex) + { + newIndex += 1; + if (newIndex > contents.Count -1) + newIndex = -1; + } + pane.SetContentIndex(Content, newIndex); + } + } + else + { + DockPane paneFrom = DockPanel.DockPaneFactory.CreateDockPane(Content, pane.DockState, true); + INestedPanesContainer container = pane.NestedPanesContainer; + if (dockStyle == DockStyle.Left) + paneFrom.DockTo(container, pane, DockAlignment.Left, 0.5); + else if (dockStyle == DockStyle.Right) + paneFrom.DockTo(container, pane, DockAlignment.Right, 0.5); + else if (dockStyle == DockStyle.Top) + paneFrom.DockTo(container, pane, DockAlignment.Top, 0.5); + else if (dockStyle == DockStyle.Bottom) + paneFrom.DockTo(container, pane, DockAlignment.Bottom, 0.5); + + paneFrom.DockState = pane.DockState; + } + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + if (panel != DockPanel) + throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel"); + + DockPane pane; + + if (dockStyle == DockStyle.Top) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockTop, true); + else if (dockStyle == DockStyle.Bottom) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockBottom, true); + else if (dockStyle == DockStyle.Left) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockLeft, true); + else if (dockStyle == DockStyle.Right) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockRight, true); + else if (dockStyle == DockStyle.Fill) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Document, true); + else + return; + } + + #endregion + } +} diff --git a/WinFormsUI/Docking/DockOutlineBase.cs b/WinFormsUI/Docking/DockOutlineBase.cs new file mode 100644 index 0000000000..6d24175fc3 --- /dev/null +++ b/WinFormsUI/Docking/DockOutlineBase.cs @@ -0,0 +1,161 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal abstract class DockOutlineBase + { + public DockOutlineBase() + { + Init(); + } + + private void Init() + { + SetValues(Rectangle.Empty, null, DockStyle.None, -1); + SaveOldValues(); + } + + private Rectangle m_oldFloatWindowBounds; + protected Rectangle OldFloatWindowBounds + { + get { return m_oldFloatWindowBounds; } + } + + private Control m_oldDockTo; + protected Control OldDockTo + { + get { return m_oldDockTo; } + } + + private DockStyle m_oldDock; + protected DockStyle OldDock + { + get { return m_oldDock; } + } + + private int m_oldContentIndex; + protected int OldContentIndex + { + get { return m_oldContentIndex; } + } + + protected bool SameAsOldValue + { + get + { + return FloatWindowBounds == OldFloatWindowBounds && + DockTo == OldDockTo && + Dock == OldDock && + ContentIndex == OldContentIndex; + } + } + + private Rectangle m_floatWindowBounds; + public Rectangle FloatWindowBounds + { + get { return m_floatWindowBounds; } + } + + private Control m_dockTo; + public Control DockTo + { + get { return m_dockTo; } + } + + private DockStyle m_dock; + public DockStyle Dock + { + get { return m_dock; } + } + + private int m_contentIndex; + public int ContentIndex + { + get { return m_contentIndex; } + } + + public bool FlagFullEdge + { + get { return m_contentIndex != 0; } + } + + private bool m_flagTestDrop = false; + public bool FlagTestDrop + { + get { return m_flagTestDrop; } + set { m_flagTestDrop = value; } + } + + private void SaveOldValues() + { + m_oldDockTo = m_dockTo; + m_oldDock = m_dock; + m_oldContentIndex = m_contentIndex; + m_oldFloatWindowBounds = m_floatWindowBounds; + } + + protected abstract void OnShow(); + + protected abstract void OnClose(); + + private void SetValues(Rectangle floatWindowBounds, Control dockTo, DockStyle dock, int contentIndex) + { + m_floatWindowBounds = floatWindowBounds; + m_dockTo = dockTo; + m_dock = dock; + m_contentIndex = contentIndex; + FlagTestDrop = true; + } + + private void TestChange() + { + if (m_floatWindowBounds != m_oldFloatWindowBounds || + m_dockTo != m_oldDockTo || + m_dock != m_oldDock || + m_contentIndex != m_oldContentIndex) + OnShow(); + } + + public void Show() + { + SaveOldValues(); + SetValues(Rectangle.Empty, null, DockStyle.None, -1); + TestChange(); + } + + public void Show(DockPane pane, DockStyle dock) + { + SaveOldValues(); + SetValues(Rectangle.Empty, pane, dock, -1); + TestChange(); + } + + public void Show(DockPane pane, int contentIndex) + { + SaveOldValues(); + SetValues(Rectangle.Empty, pane, DockStyle.Fill, contentIndex); + TestChange(); + } + + public void Show(DockPanel dockPanel, DockStyle dock, bool fullPanelEdge) + { + SaveOldValues(); + SetValues(Rectangle.Empty, dockPanel, dock, fullPanelEdge ? -1 : 0); + TestChange(); + } + + public void Show(Rectangle floatWindowBounds) + { + SaveOldValues(); + SetValues(floatWindowBounds, null, DockStyle.None, -1); + TestChange(); + } + + public void Close() + { + OnClose(); + } + } +} diff --git a/WinFormsUI/Docking/DockPane.SplitterControl.cs b/WinFormsUI/Docking/DockPane.SplitterControl.cs new file mode 100644 index 0000000000..dc69fb944f --- /dev/null +++ b/WinFormsUI/Docking/DockPane.SplitterControl.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPane + { + private class SplitterControl : Control, ISplitterDragSource + { + DockPane m_pane; + + public SplitterControl(DockPane pane) + { + SetStyle(ControlStyles.Selectable, false); + m_pane = pane; + } + + public DockPane DockPane + { + get { return m_pane; } + } + + private DockAlignment m_alignment; + public DockAlignment Alignment + { + get { return m_alignment; } + set + { + m_alignment = value; + if (m_alignment == DockAlignment.Left || m_alignment == DockAlignment.Right) + Cursor = Cursors.VSplit; + else if (m_alignment == DockAlignment.Top || m_alignment == DockAlignment.Bottom) + Cursor = Cursors.HSplit; + else + Cursor = Cursors.Default; + + if (DockPane.DockState == DockState.Document) + Invalidate(); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (DockPane.DockState != DockState.Document) + return; + + Graphics g = e.Graphics; + Rectangle rect = ClientRectangle; + if (Alignment == DockAlignment.Top || Alignment == DockAlignment.Bottom) + g.DrawLine(SystemPens.ControlDark, rect.Left, rect.Bottom - 1, rect.Right, rect.Bottom - 1); + else if (Alignment == DockAlignment.Left || Alignment == DockAlignment.Right) + g.DrawLine(SystemPens.ControlDarkDark, rect.Right - 1, rect.Top, rect.Right - 1, rect.Bottom); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button != MouseButtons.Left) + return; + + DockPane.DockPanel.BeginDrag(this, Parent.RectangleToScreen(Bounds)); + } + + #region ISplitterDragSource Members + + void ISplitterDragSource.BeginDrag(Rectangle rectSplitter) + { + } + + void ISplitterDragSource.EndDrag() + { + } + + bool ISplitterDragSource.IsVertical + { + get + { + NestedDockingStatus status = DockPane.NestedDockingStatus; + return (status.DisplayingAlignment == DockAlignment.Left || + status.DisplayingAlignment == DockAlignment.Right); + } + } + + Rectangle ISplitterDragSource.DragLimitBounds + { + get + { + NestedDockingStatus status = DockPane.NestedDockingStatus; + Rectangle rectLimit = Parent.RectangleToScreen(status.LogicalBounds); + if (((ISplitterDragSource)this).IsVertical) + { + rectLimit.X += MeasurePane.MinSize; + rectLimit.Width -= 2 * MeasurePane.MinSize; + } + else + { + rectLimit.Y += MeasurePane.MinSize; + rectLimit.Height -= 2 * MeasurePane.MinSize; + } + + return rectLimit; + } + } + + void ISplitterDragSource.MoveSplitter(int offset) + { + NestedDockingStatus status = DockPane.NestedDockingStatus; + double proportion = status.Proportion; + if (status.LogicalBounds.Width <= 0 || status.LogicalBounds.Height <= 0) + return; + else if (status.DisplayingAlignment == DockAlignment.Left) + proportion += ((double)offset) / (double)status.LogicalBounds.Width; + else if (status.DisplayingAlignment == DockAlignment.Right) + proportion -= ((double)offset) / (double)status.LogicalBounds.Width; + else if (status.DisplayingAlignment == DockAlignment.Top) + proportion += ((double)offset) / (double)status.LogicalBounds.Height; + else + proportion -= ((double)offset) / (double)status.LogicalBounds.Height; + + DockPane.SetNestedDockingProportion(proportion); + } + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + + #endregion + } + + private SplitterControl m_splitter; + private SplitterControl Splitter + { + get { return m_splitter; } + } + + internal Rectangle SplitterBounds + { + set { Splitter.Bounds = value; } + } + + internal DockAlignment SplitterAlignment + { + set { Splitter.Alignment = value; } + } + } +} \ No newline at end of file diff --git a/WinFormsUI/Docking/DockPane.cs b/WinFormsUI/Docking/DockPane.cs new file mode 100644 index 0000000000..ca637e24d4 --- /dev/null +++ b/WinFormsUI/Docking/DockPane.cs @@ -0,0 +1,1317 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + [ToolboxItem(false)] + public partial class DockPane : UserControl, IDockDragSource + { + public enum AppearanceStyle + { + ToolWindow, + Document + } + + private enum HitTestArea + { + Caption, + TabStrip, + Content, + None + } + + private struct HitTestResult + { + public HitTestArea HitArea; + public int Index; + + public HitTestResult(HitTestArea hitTestArea, int index) + { + HitArea = hitTestArea; + Index = index; + } + } + + private DockPaneCaptionBase m_captionControl; + private DockPaneCaptionBase CaptionControl + { + get { return m_captionControl; } + } + + private DockPaneStripBase m_tabStripControl; + public DockPaneStripBase TabStripControl + { + get { return m_tabStripControl; } + } + + internal protected DockPane(IDockContent content, DockState visibleState, bool show) + { + InternalConstruct(content, visibleState, false, Rectangle.Empty, null, DockAlignment.Right, 0.5, show); + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")] + internal protected DockPane(IDockContent content, FloatWindow floatWindow, bool show) + { + if (floatWindow == null) + throw new ArgumentNullException("floatWindow"); + + InternalConstruct(content, DockState.Float, false, Rectangle.Empty, floatWindow.NestedPanes.GetDefaultPreviousPane(this), DockAlignment.Right, 0.5, show); + } + + internal protected DockPane(IDockContent content, DockPane previousPane, DockAlignment alignment, double proportion, bool show) + { + if (previousPane == null) + throw (new ArgumentNullException("previousPane")); + InternalConstruct(content, previousPane.DockState, false, Rectangle.Empty, previousPane, alignment, proportion, show); + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")] + internal protected DockPane(IDockContent content, Rectangle floatWindowBounds, bool show) + { + InternalConstruct(content, DockState.Float, true, floatWindowBounds, null, DockAlignment.Right, 0.5, show); + } + + private void InternalConstruct(IDockContent content, DockState dockState, bool flagBounds, Rectangle floatWindowBounds, DockPane prevPane, DockAlignment alignment, double proportion, bool show) + { + if (dockState == DockState.Hidden || dockState == DockState.Unknown) + throw new ArgumentException(Strings.DockPane_SetDockState_InvalidState); + + if (content == null) + throw new ArgumentNullException(Strings.DockPane_Constructor_NullContent); + + if (content.DockHandler.DockPanel == null) + throw new ArgumentException(Strings.DockPane_Constructor_NullDockPanel); + + + SuspendLayout(); + SetStyle(ControlStyles.Selectable, false); + + m_isFloat = (dockState == DockState.Float); + + m_contents = new DockContentCollection(); + m_displayingContents = new DockContentCollection(this); + m_dockPanel = content.DockHandler.DockPanel; + m_dockPanel.AddPane(this); + + m_splitter = new SplitterControl(this); + + m_nestedDockingStatus = new NestedDockingStatus(this); + + m_captionControl = DockPanel.DockPaneCaptionFactory.CreateDockPaneCaption(this); + m_tabStripControl = DockPanel.DockPaneStripFactory.CreateDockPaneStrip(this); + Controls.AddRange(new Control[] { m_captionControl, m_tabStripControl }); + + DockPanel.SuspendLayout(true); + if (flagBounds) + FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this, floatWindowBounds); + else if (prevPane != null) + DockTo(prevPane.NestedPanesContainer, prevPane, alignment, proportion); + + SetDockState(dockState); + if (show) + content.DockHandler.Pane = this; + else if (this.IsFloat) + content.DockHandler.FloatPane = this; + else + content.DockHandler.PanelPane = this; + + ResumeLayout(); + DockPanel.ResumeLayout(true, true); + } + + private bool m_isDisposing; + + protected override void Dispose(bool disposing) + { + if (disposing) + { + // IMPORTANT: avoid nested call into this method on Mono. + // https://github.com/dockpanelsuite/dockpanelsuite/issues/16 + if (Win32Helper.IsRunningOnMono) + { + if (m_isDisposing) + return; + + m_isDisposing = true; + } + + m_dockState = DockState.Unknown; + + if (NestedPanesContainer != null) + NestedPanesContainer.NestedPanes.Remove(this); + + if (DockPanel != null) + { + DockPanel.RemovePane(this); + m_dockPanel = null; + } + + Splitter.Dispose(); + if (m_autoHidePane != null) + m_autoHidePane.Dispose(); + } + base.Dispose(disposing); + } + + private IDockContent m_activeContent = null; + public virtual IDockContent ActiveContent + { + get { return m_activeContent; } + set + { + if (ActiveContent == value) + return; + + if (value != null) + { + if (!DisplayingContents.Contains(value)) + throw (new InvalidOperationException(Strings.DockPane_ActiveContent_InvalidValue)); + } + else + { + if (DisplayingContents.Count != 0) + throw (new InvalidOperationException(Strings.DockPane_ActiveContent_InvalidValue)); + } + + IDockContent oldValue = m_activeContent; + + if (DockPanel.ActiveAutoHideContent == oldValue) + DockPanel.ActiveAutoHideContent = null; + + m_activeContent = value; + + if (DockPanel.DocumentStyle == DocumentStyle.DockingMdi && DockState == DockState.Document) + { + if (m_activeContent != null) + m_activeContent.DockHandler.Form.BringToFront(); + } + else + { + if (m_activeContent != null) + m_activeContent.DockHandler.SetVisible(); + if (oldValue != null && DisplayingContents.Contains(oldValue)) + oldValue.DockHandler.SetVisible(); + if (IsActivated && m_activeContent != null) + m_activeContent.DockHandler.Activate(); + } + + if (FloatWindow != null) + FloatWindow.SetText(); + + if (DockPanel.DocumentStyle == DocumentStyle.DockingMdi && + DockState == DockState.Document) + RefreshChanges(false); // delayed layout to reduce screen flicker + else + RefreshChanges(); + + if (m_activeContent != null) + TabStripControl.EnsureTabVisible(m_activeContent); + } + } + + private bool m_allowDockDragAndDrop = true; + public virtual bool AllowDockDragAndDrop + { + get { return m_allowDockDragAndDrop; } + set { m_allowDockDragAndDrop = value; } + } + + private IDisposable m_autoHidePane = null; + internal IDisposable AutoHidePane + { + get { return m_autoHidePane; } + set { m_autoHidePane = value; } + } + + private object m_autoHideTabs = null; + internal object AutoHideTabs + { + get { return m_autoHideTabs; } + set { m_autoHideTabs = value; } + } + + private object TabPageContextMenu + { + get + { + IDockContent content = ActiveContent; + + if (content == null) + return null; + + if (content.DockHandler.TabPageContextMenuStrip != null) + return content.DockHandler.TabPageContextMenuStrip; + else if (content.DockHandler.TabPageContextMenu != null) + return content.DockHandler.TabPageContextMenu; + else + return null; + } + } + + internal bool HasTabPageContextMenu + { + get { return TabPageContextMenu != null; } + } + + internal void ShowTabPageContextMenu(Control control, Point position) + { + object menu = TabPageContextMenu; + + if (menu == null) + return; + + ContextMenuStrip contextMenuStrip = menu as ContextMenuStrip; + if (contextMenuStrip != null) + { + contextMenuStrip.Show(control, position); + return; + } + + ContextMenu contextMenu = menu as ContextMenu; + if (contextMenu != null) + contextMenu.Show(this, position); + } + + private Rectangle CaptionRectangle + { + get + { + if (!HasCaption) + return Rectangle.Empty; + + Rectangle rectWindow = DisplayingRectangle; + int x, y, width; + x = rectWindow.X; + y = rectWindow.Y; + width = rectWindow.Width; + int height = CaptionControl.MeasureHeight(); + + return new Rectangle(x, y, width, height); + } + } + + internal Rectangle ContentRectangle + { + get + { + Rectangle rectWindow = DisplayingRectangle; + Rectangle rectCaption = CaptionRectangle; + Rectangle rectTabStrip = TabStripRectangle; + + int x = rectWindow.X; + + int y = rectWindow.Y + (rectCaption.IsEmpty ? 0 : rectCaption.Height); + if (DockState == DockState.Document && DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Top) + y += rectTabStrip.Height; + + int width = rectWindow.Width; + int height = rectWindow.Height - rectCaption.Height - rectTabStrip.Height; + + return new Rectangle(x, y, width, height); + } + } + + internal Rectangle TabStripRectangle + { + get + { + if (Appearance == AppearanceStyle.ToolWindow) + return TabStripRectangle_ToolWindow; + else + return TabStripRectangle_Document; + } + } + + private Rectangle TabStripRectangle_ToolWindow + { + get + { + if (DisplayingContents.Count <= 1 || IsAutoHide) + return Rectangle.Empty; + + Rectangle rectWindow = DisplayingRectangle; + + int width = rectWindow.Width; + int height = TabStripControl.MeasureHeight(); + int x = rectWindow.X; + int y = rectWindow.Bottom - height; + Rectangle rectCaption = CaptionRectangle; + if (rectCaption.Contains(x, y)) + y = rectCaption.Y + rectCaption.Height; + + return new Rectangle(x, y, width, height); + } + } + + private Rectangle TabStripRectangle_Document + { + get + { + if (DisplayingContents.Count == 0) + return Rectangle.Empty; + + if (DisplayingContents.Count == 1 && DockPanel.DocumentStyle == DocumentStyle.DockingSdi) + return Rectangle.Empty; + + Rectangle rectWindow = DisplayingRectangle; + int x = rectWindow.X; + int width = rectWindow.Width; + int height = TabStripControl.MeasureHeight(); + + int y = 0; + if (DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + y = rectWindow.Height - height; + else + y = rectWindow.Y; + + return new Rectangle(x, y, width, height); + } + } + + public virtual string CaptionText + { + get { return ActiveContent == null ? string.Empty : ActiveContent.DockHandler.TabText; } + } + + private DockContentCollection m_contents; + public DockContentCollection Contents + { + get { return m_contents; } + } + + private DockContentCollection m_displayingContents; + public DockContentCollection DisplayingContents + { + get { return m_displayingContents; } + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private bool HasCaption + { + get + { + if (DockState == DockState.Document || + DockState == DockState.Hidden || + DockState == DockState.Unknown || + (DockState == DockState.Float && FloatWindow.VisibleNestedPanes.Count <= 1)) + return false; + else + return true; + } + } + + private bool m_isActivated = false; + public bool IsActivated + { + get { return m_isActivated; } + } + internal void SetIsActivated(bool value) + { + if (m_isActivated == value) + return; + + m_isActivated = value; + if (DockState != DockState.Document) + RefreshChanges(false); + OnIsActivatedChanged(EventArgs.Empty); + } + + private bool m_isActiveDocumentPane = false; + public bool IsActiveDocumentPane + { + get { return m_isActiveDocumentPane; } + } + internal void SetIsActiveDocumentPane(bool value) + { + if (m_isActiveDocumentPane == value) + return; + + m_isActiveDocumentPane = value; + if (DockState == DockState.Document) + RefreshChanges(); + OnIsActiveDocumentPaneChanged(EventArgs.Empty); + } + + public bool IsDockStateValid(DockState dockState) + { + foreach (IDockContent content in Contents) + if (!content.DockHandler.IsDockStateValid(dockState)) + return false; + + return true; + } + + public bool IsAutoHide + { + get { return DockHelper.IsDockStateAutoHide(DockState); } + } + + public AppearanceStyle Appearance + { + get { return (DockState == DockState.Document) ? AppearanceStyle.Document : AppearanceStyle.ToolWindow; } + } + + internal Rectangle DisplayingRectangle + { + get { return ClientRectangle; } + } + + public void Activate() + { + if (DockHelper.IsDockStateAutoHide(DockState) && DockPanel.ActiveAutoHideContent != ActiveContent) + DockPanel.ActiveAutoHideContent = ActiveContent; + else if (!IsActivated && ActiveContent != null) + ActiveContent.DockHandler.Activate(); + } + + internal void AddContent(IDockContent content) + { + if (Contents.Contains(content)) + return; + + Contents.Add(content); + } + + internal void Close() + { + Dispose(); + } + + public void CloseActiveContent() + { + CloseContent(ActiveContent); + } + + internal void CloseContent(IDockContent content) + { + if (content == null) + return; + + if (!content.DockHandler.CloseButton) + return; + + DockPanel dockPanel = DockPanel; + + dockPanel.SuspendLayout(true); + + try + { + if (content.DockHandler.HideOnClose) + { + content.DockHandler.Hide(); + NestedDockingStatus.NestedPanes.SwitchPaneWithFirstChild(this); + } + else + content.DockHandler.Close(); + } + finally + { + dockPanel.ResumeLayout(true, true); + } + } + + private HitTestResult GetHitTest(Point ptMouse) + { + Point ptMouseClient = PointToClient(ptMouse); + + Rectangle rectCaption = CaptionRectangle; + if (rectCaption.Contains(ptMouseClient)) + return new HitTestResult(HitTestArea.Caption, -1); + + Rectangle rectContent = ContentRectangle; + if (rectContent.Contains(ptMouseClient)) + return new HitTestResult(HitTestArea.Content, -1); + + Rectangle rectTabStrip = TabStripRectangle; + if (rectTabStrip.Contains(ptMouseClient)) + return new HitTestResult(HitTestArea.TabStrip, TabStripControl.HitTest(TabStripControl.PointToClient(ptMouse))); + + return new HitTestResult(HitTestArea.None, -1); + } + + private bool m_isHidden = true; + public bool IsHidden + { + get { return m_isHidden; } + } + private void SetIsHidden(bool value) + { + if (m_isHidden == value) + return; + + m_isHidden = value; + if (DockHelper.IsDockStateAutoHide(DockState)) + { + DockPanel.RefreshAutoHideStrip(); + DockPanel.PerformLayout(); + } + else if (NestedPanesContainer != null) + ((Control)NestedPanesContainer).PerformLayout(); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + SetIsHidden(DisplayingContents.Count == 0); + if (!IsHidden) + { + CaptionControl.Bounds = CaptionRectangle; + TabStripControl.Bounds = TabStripRectangle; + + SetContentBounds(); + + foreach (IDockContent content in Contents) + { + if (DisplayingContents.Contains(content)) + if (content.DockHandler.FlagClipWindow && content.DockHandler.Form.Visible) + content.DockHandler.FlagClipWindow = false; + } + } + + base.OnLayout(levent); + } + + internal void SetContentBounds() + { + Rectangle rectContent = ContentRectangle; + if (DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi) + rectContent = DockPanel.RectangleToMdiClient(RectangleToScreen(rectContent)); + + Rectangle rectInactive = new Rectangle(-rectContent.Width, rectContent.Y, rectContent.Width, rectContent.Height); + foreach (IDockContent content in Contents) + if (content.DockHandler.Pane == this) + { + if (content == ActiveContent) + content.DockHandler.Form.Bounds = rectContent; + else + content.DockHandler.Form.Bounds = rectInactive; + } + } + + internal void RefreshChanges() + { + RefreshChanges(true); + } + + private void RefreshChanges(bool performLayout) + { + if (IsDisposed) + return; + + CaptionControl.RefreshChanges(); + TabStripControl.RefreshChanges(); + if (DockState == DockState.Float && FloatWindow != null) + FloatWindow.RefreshChanges(); + if (DockHelper.IsDockStateAutoHide(DockState) && DockPanel != null) + { + DockPanel.RefreshAutoHideStrip(); + DockPanel.PerformLayout(); + } + + if (performLayout) + PerformLayout(); + } + + internal void RemoveContent(IDockContent content) + { + if (!Contents.Contains(content)) + return; + + Contents.Remove(content); + } + + public void SetContentIndex(IDockContent content, int index) + { + int oldIndex = Contents.IndexOf(content); + if (oldIndex == -1) + throw (new ArgumentException(Strings.DockPane_SetContentIndex_InvalidContent)); + + if (index < 0 || index > Contents.Count - 1) + if (index != -1) + throw (new ArgumentOutOfRangeException(Strings.DockPane_SetContentIndex_InvalidIndex)); + + if (oldIndex == index) + return; + if (oldIndex == Contents.Count - 1 && index == -1) + return; + + Contents.Remove(content); + if (index == -1) + Contents.Add(content); + else if (oldIndex < index) + Contents.AddAt(content, index - 1); + else + Contents.AddAt(content, index); + + RefreshChanges(); + } + + private void SetParent() + { + if (DockState == DockState.Unknown || DockState == DockState.Hidden) + { + SetParent(null); + Splitter.Parent = null; + } + else if (DockState == DockState.Float) + { + SetParent(FloatWindow); + Splitter.Parent = FloatWindow; + } + else if (DockHelper.IsDockStateAutoHide(DockState)) + { + SetParent(DockPanel.AutoHideControl); + Splitter.Parent = null; + } + else + { + SetParent(DockPanel.DockWindows[DockState]); + Splitter.Parent = Parent; + } + } + + private void SetParent(Control value) + { + if (Parent == value) + return; + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Workaround of .Net Framework bug: + // Change the parent of a control with focus may result in the first + // MDI child form get activated. + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + IDockContent contentFocused = GetFocusedContent(); + if (contentFocused != null) + DockPanel.SaveFocus(); + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + Parent = value; + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Workaround of .Net Framework bug: + // Change the parent of a control with focus may result in the first + // MDI child form get activated. + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if (contentFocused != null) + contentFocused.DockHandler.Activate(); + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + } + + public new void Show() + { + Activate(); + } + + internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline) + { + if (!dragSource.CanDockTo(this)) + return; + + Point ptMouse = Control.MousePosition; + + HitTestResult hitTestResult = GetHitTest(ptMouse); + if (hitTestResult.HitArea == HitTestArea.Caption) + dockOutline.Show(this, -1); + else if (hitTestResult.HitArea == HitTestArea.TabStrip && hitTestResult.Index != -1) + dockOutline.Show(this, hitTestResult.Index); + } + + internal void ValidateActiveContent() + { + if (ActiveContent == null) + { + if (DisplayingContents.Count != 0) + ActiveContent = DisplayingContents[0]; + return; + } + + if (DisplayingContents.IndexOf(ActiveContent) >= 0) + return; + + IDockContent prevVisible = null; + for (int i = Contents.IndexOf(ActiveContent) - 1; i >= 0; i--) + if (Contents[i].DockHandler.DockState == DockState) + { + prevVisible = Contents[i]; + break; + } + + IDockContent nextVisible = null; + for (int i = Contents.IndexOf(ActiveContent) + 1; i < Contents.Count; i++) + if (Contents[i].DockHandler.DockState == DockState) + { + nextVisible = Contents[i]; + break; + } + + if (prevVisible != null) + ActiveContent = prevVisible; + else if (nextVisible != null) + ActiveContent = nextVisible; + else + ActiveContent = null; + } + + private static readonly object DockStateChangedEvent = new object(); + public event EventHandler DockStateChanged + { + add { Events.AddHandler(DockStateChangedEvent, value); } + remove { Events.RemoveHandler(DockStateChangedEvent, value); } + } + protected virtual void OnDockStateChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[DockStateChangedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object IsActivatedChangedEvent = new object(); + public event EventHandler IsActivatedChanged + { + add { Events.AddHandler(IsActivatedChangedEvent, value); } + remove { Events.RemoveHandler(IsActivatedChangedEvent, value); } + } + protected virtual void OnIsActivatedChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[IsActivatedChangedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object IsActiveDocumentPaneChangedEvent = new object(); + public event EventHandler IsActiveDocumentPaneChanged + { + add { Events.AddHandler(IsActiveDocumentPaneChangedEvent, value); } + remove { Events.RemoveHandler(IsActiveDocumentPaneChangedEvent, value); } + } + protected virtual void OnIsActiveDocumentPaneChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[IsActiveDocumentPaneChangedEvent]; + if (handler != null) + handler(this, e); + } + + public DockWindow DockWindow + { + get { return (m_nestedDockingStatus.NestedPanes == null) ? null : m_nestedDockingStatus.NestedPanes.Container as DockWindow; } + set + { + DockWindow oldValue = DockWindow; + if (oldValue == value) + return; + + DockTo(value); + } + } + + public FloatWindow FloatWindow + { + get { return (m_nestedDockingStatus.NestedPanes == null) ? null : m_nestedDockingStatus.NestedPanes.Container as FloatWindow; } + set + { + FloatWindow oldValue = FloatWindow; + if (oldValue == value) + return; + + DockTo(value); + } + } + + private NestedDockingStatus m_nestedDockingStatus; + public NestedDockingStatus NestedDockingStatus + { + get { return m_nestedDockingStatus; } + } + + private bool m_isFloat; + public bool IsFloat + { + get { return m_isFloat; } + } + + public INestedPanesContainer NestedPanesContainer + { + get + { + if (NestedDockingStatus.NestedPanes == null) + return null; + else + return NestedDockingStatus.NestedPanes.Container; + } + } + + private DockState m_dockState = DockState.Unknown; + public DockState DockState + { + get { return m_dockState; } + set + { + SetDockState(value); + } + } + + public DockPane SetDockState(DockState value) + { + if (value == DockState.Unknown || value == DockState.Hidden) + throw new InvalidOperationException(Strings.DockPane_SetDockState_InvalidState); + + if ((value == DockState.Float) == this.IsFloat) + { + InternalSetDockState(value); + return this; + } + + if (DisplayingContents.Count == 0) + return null; + + IDockContent firstContent = null; + for (int i = 0; i < DisplayingContents.Count; i++) + { + IDockContent content = DisplayingContents[i]; + if (content.DockHandler.IsDockStateValid(value)) + { + firstContent = content; + break; + } + } + if (firstContent == null) + return null; + + firstContent.DockHandler.DockState = value; + DockPane pane = firstContent.DockHandler.Pane; + DockPanel.SuspendLayout(true); + for (int i = 0; i < DisplayingContents.Count; i++) + { + IDockContent content = DisplayingContents[i]; + if (content.DockHandler.IsDockStateValid(value)) + content.DockHandler.Pane = pane; + } + DockPanel.ResumeLayout(true, true); + return pane; + } + + private void InternalSetDockState(DockState value) + { + if (m_dockState == value) + return; + + DockState oldDockState = m_dockState; + INestedPanesContainer oldContainer = NestedPanesContainer; + + m_dockState = value; + + SuspendRefreshStateChange(); + + IDockContent contentFocused = GetFocusedContent(); + if (contentFocused != null) + DockPanel.SaveFocus(); + + if (!IsFloat) + DockWindow = DockPanel.DockWindows[DockState]; + else if (FloatWindow == null) + FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this); + + if (contentFocused != null) + { + if (!Win32Helper.IsRunningOnMono) + { + DockPanel.ContentFocusManager.Activate(contentFocused); + } + } + + ResumeRefreshStateChange(oldContainer, oldDockState); + } + + private int m_countRefreshStateChange = 0; + private void SuspendRefreshStateChange() + { + m_countRefreshStateChange++; + DockPanel.SuspendLayout(true); + } + + private void ResumeRefreshStateChange() + { + m_countRefreshStateChange--; + System.Diagnostics.Debug.Assert(m_countRefreshStateChange >= 0); + DockPanel.ResumeLayout(true, true); + } + + private bool IsRefreshStateChangeSuspended + { + get { return m_countRefreshStateChange != 0; } + } + + private void ResumeRefreshStateChange(INestedPanesContainer oldContainer, DockState oldDockState) + { + ResumeRefreshStateChange(); + RefreshStateChange(oldContainer, oldDockState); + } + + private void RefreshStateChange(INestedPanesContainer oldContainer, DockState oldDockState) + { + if (IsRefreshStateChangeSuspended) + return; + + SuspendRefreshStateChange(); + + DockPanel.SuspendLayout(true); + + IDockContent contentFocused = GetFocusedContent(); + if (contentFocused != null) + DockPanel.SaveFocus(); + SetParent(); + + if (ActiveContent != null) + ActiveContent.DockHandler.SetDockState(ActiveContent.DockHandler.IsHidden, DockState, ActiveContent.DockHandler.Pane); + foreach (IDockContent content in Contents) + { + if (content.DockHandler.Pane == this) + content.DockHandler.SetDockState(content.DockHandler.IsHidden, DockState, content.DockHandler.Pane); + } + + if (oldContainer != null) + { + Control oldContainerControl = (Control)oldContainer; + if (oldContainer.DockState == oldDockState && !oldContainerControl.IsDisposed) + oldContainerControl.PerformLayout(); + } + if (DockHelper.IsDockStateAutoHide(oldDockState)) + DockPanel.RefreshActiveAutoHideContent(); + + if (NestedPanesContainer.DockState == DockState) + ((Control)NestedPanesContainer).PerformLayout(); + if (DockHelper.IsDockStateAutoHide(DockState)) + DockPanel.RefreshActiveAutoHideContent(); + + if (DockHelper.IsDockStateAutoHide(oldDockState) || + DockHelper.IsDockStateAutoHide(DockState)) + { + DockPanel.RefreshAutoHideStrip(); + DockPanel.PerformLayout(); + } + + ResumeRefreshStateChange(); + + if (contentFocused != null) + contentFocused.DockHandler.Activate(); + + DockPanel.ResumeLayout(true, true); + + if (oldDockState != DockState) + OnDockStateChanged(EventArgs.Empty); + } + + private IDockContent GetFocusedContent() + { + IDockContent contentFocused = null; + foreach (IDockContent content in Contents) + { + if (content.DockHandler.Form.ContainsFocus) + { + contentFocused = content; + break; + } + } + + return contentFocused; + } + + public DockPane DockTo(INestedPanesContainer container) + { + if (container == null) + throw new InvalidOperationException(Strings.DockPane_DockTo_NullContainer); + + DockAlignment alignment; + if (container.DockState == DockState.DockLeft || container.DockState == DockState.DockRight) + alignment = DockAlignment.Bottom; + else + alignment = DockAlignment.Right; + + return DockTo(container, container.NestedPanes.GetDefaultPreviousPane(this), alignment, 0.5); + } + + public DockPane DockTo(INestedPanesContainer container, DockPane previousPane, DockAlignment alignment, double proportion) + { + if (container == null) + throw new InvalidOperationException(Strings.DockPane_DockTo_NullContainer); + + if (container.IsFloat == this.IsFloat) + { + InternalAddToDockList(container, previousPane, alignment, proportion); + return this; + } + + IDockContent firstContent = GetFirstContent(container.DockState); + if (firstContent == null) + return null; + + DockPane pane; + DockPanel.DummyContent.DockPanel = DockPanel; + if (container.IsFloat) + pane = DockPanel.DockPaneFactory.CreateDockPane(DockPanel.DummyContent, (FloatWindow)container, true); + else + pane = DockPanel.DockPaneFactory.CreateDockPane(DockPanel.DummyContent, container.DockState, true); + + pane.DockTo(container, previousPane, alignment, proportion); + SetVisibleContentsToPane(pane); + DockPanel.DummyContent.DockPanel = null; + + return pane; + } + + private void SetVisibleContentsToPane(DockPane pane) + { + SetVisibleContentsToPane(pane, ActiveContent); + } + + private void SetVisibleContentsToPane(DockPane pane, IDockContent activeContent) + { + for (int i = 0; i < DisplayingContents.Count; i++) + { + IDockContent content = DisplayingContents[i]; + if (content.DockHandler.IsDockStateValid(pane.DockState)) + { + content.DockHandler.Pane = pane; + i--; + } + } + + if (activeContent.DockHandler.Pane == pane) + pane.ActiveContent = activeContent; + } + + private void InternalAddToDockList(INestedPanesContainer container, DockPane prevPane, DockAlignment alignment, double proportion) + { + if ((container.DockState == DockState.Float) != IsFloat) + throw new InvalidOperationException(Strings.DockPane_DockTo_InvalidContainer); + + int count = container.NestedPanes.Count; + if (container.NestedPanes.Contains(this)) + count--; + if (prevPane == null && count > 0) + throw new InvalidOperationException(Strings.DockPane_DockTo_NullPrevPane); + + if (prevPane != null && !container.NestedPanes.Contains(prevPane)) + throw new InvalidOperationException(Strings.DockPane_DockTo_NoPrevPane); + + if (prevPane == this) + throw new InvalidOperationException(Strings.DockPane_DockTo_SelfPrevPane); + + INestedPanesContainer oldContainer = NestedPanesContainer; + DockState oldDockState = DockState; + container.NestedPanes.Add(this); + NestedDockingStatus.SetStatus(container.NestedPanes, prevPane, alignment, proportion); + + if (DockHelper.IsDockWindowState(DockState)) + m_dockState = container.DockState; + + RefreshStateChange(oldContainer, oldDockState); + } + + public void SetNestedDockingProportion(double proportion) + { + NestedDockingStatus.SetStatus(NestedDockingStatus.NestedPanes, NestedDockingStatus.PreviousPane, NestedDockingStatus.Alignment, proportion); + if (NestedPanesContainer != null) + ((Control)NestedPanesContainer).PerformLayout(); + } + + public DockPane Float() + { + DockPanel.SuspendLayout(true); + + IDockContent activeContent = ActiveContent; + + DockPane floatPane = GetFloatPaneFromContents(); + if (floatPane == null) + { + IDockContent firstContent = GetFirstContent(DockState.Float); + if (firstContent == null) + { + DockPanel.ResumeLayout(true, true); + return null; + } + floatPane = DockPanel.DockPaneFactory.CreateDockPane(firstContent, DockState.Float, true); + } + SetVisibleContentsToPane(floatPane, activeContent); + + DockPanel.ResumeLayout(true, true); + return floatPane; + } + + private DockPane GetFloatPaneFromContents() + { + DockPane floatPane = null; + for (int i = 0; i < DisplayingContents.Count; i++) + { + IDockContent content = DisplayingContents[i]; + if (!content.DockHandler.IsDockStateValid(DockState.Float)) + continue; + + if (floatPane != null && content.DockHandler.FloatPane != floatPane) + return null; + else + floatPane = content.DockHandler.FloatPane; + } + + return floatPane; + } + + private IDockContent GetFirstContent(DockState dockState) + { + for (int i = 0; i < DisplayingContents.Count; i++) + { + IDockContent content = DisplayingContents[i]; + if (content.DockHandler.IsDockStateValid(dockState)) + return content; + } + return null; + } + + public void RestoreToPanel() + { + DockPanel.SuspendLayout(true); + + IDockContent activeContent = DockPanel.ActiveContent; + + for (int i = DisplayingContents.Count - 1; i >= 0; i--) + { + IDockContent content = DisplayingContents[i]; + if (content.DockHandler.CheckDockState(false) != DockState.Unknown) + content.DockHandler.IsFloat = false; + } + + DockPanel.ResumeLayout(true, true); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_MOUSEACTIVATE) + Activate(); + + base.WndProc(ref m); + } + + #region IDockDragSource Members + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + + bool IDockDragSource.IsDockStateValid(DockState dockState) + { + return IsDockStateValid(dockState); + } + + bool IDockDragSource.CanDockTo(DockPane pane) + { + if (!IsDockStateValid(pane.DockState)) + return false; + + if (pane == this) + return false; + + return true; + } + + Rectangle IDockDragSource.BeginDrag(Point ptMouse) + { + Point location = PointToScreen(new Point(0, 0)); + Size size; + + DockPane floatPane = ActiveContent.DockHandler.FloatPane; + if (DockState == DockState.Float || floatPane == null || floatPane.FloatWindow.NestedPanes.Count != 1) + size = DockPanel.DefaultFloatWindowSize; + else + size = floatPane.FloatWindow.Size; + + if (ptMouse.X > location.X + size.Width) + location.X += ptMouse.X - (location.X + size.Width) + Measures.SplitterSize; + + return new Rectangle(location, size); + } + + void IDockDragSource.EndDrag() + { + } + + public void FloatAt(Rectangle floatWindowBounds) + { + if (FloatWindow == null || FloatWindow.NestedPanes.Count != 1) + FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this, floatWindowBounds); + else + FloatWindow.Bounds = floatWindowBounds; + + DockState = DockState.Float; + + NestedDockingStatus.NestedPanes.SwitchPaneWithFirstChild(this); + } + + public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex) + { + if (dockStyle == DockStyle.Fill) + { + IDockContent activeContent = ActiveContent; + for (int i = Contents.Count - 1; i >= 0; i--) + { + IDockContent c = Contents[i]; + if (c.DockHandler.DockState == DockState) + { + c.DockHandler.Pane = pane; + if (contentIndex != -1) + pane.SetContentIndex(c, contentIndex); + } + } + pane.ActiveContent = activeContent; + } + else + { + if (dockStyle == DockStyle.Left) + DockTo(pane.NestedPanesContainer, pane, DockAlignment.Left, 0.5); + else if (dockStyle == DockStyle.Right) + DockTo(pane.NestedPanesContainer, pane, DockAlignment.Right, 0.5); + else if (dockStyle == DockStyle.Top) + DockTo(pane.NestedPanesContainer, pane, DockAlignment.Top, 0.5); + else if (dockStyle == DockStyle.Bottom) + DockTo(pane.NestedPanesContainer, pane, DockAlignment.Bottom, 0.5); + + DockState = pane.DockState; + } + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + if (panel != DockPanel) + throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel"); + + if (dockStyle == DockStyle.Top) + DockState = DockState.DockTop; + else if (dockStyle == DockStyle.Bottom) + DockState = DockState.DockBottom; + else if (dockStyle == DockStyle.Left) + DockState = DockState.DockLeft; + else if (dockStyle == DockStyle.Right) + DockState = DockState.DockRight; + else if (dockStyle == DockStyle.Fill) + DockState = DockState.Document; + } + + #endregion + } +} diff --git a/WinFormsUI/Docking/DockPaneCaptionBase.cs b/WinFormsUI/Docking/DockPaneCaptionBase.cs new file mode 100644 index 0000000000..e66b261f5a --- /dev/null +++ b/WinFormsUI/Docking/DockPaneCaptionBase.cs @@ -0,0 +1,100 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public abstract class DockPaneCaptionBase : Control + { + protected internal DockPaneCaptionBase(DockPane pane) + { + m_dockPane = pane; + + SetStyle(ControlStyles.OptimizedDoubleBuffer | + ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.Selectable, false); + } + + private DockPane m_dockPane; + protected DockPane DockPane + { + get { return m_dockPane; } + } + + protected DockPane.AppearanceStyle Appearance + { + get { return DockPane.Appearance; } + } + + protected bool HasTabPageContextMenu + { + get { return DockPane.HasTabPageContextMenu; } + } + + protected void ShowTabPageContextMenu(Point position) + { + DockPane.ShowTabPageContextMenu(this, position); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + + if (e.Button == MouseButtons.Right) + ShowTabPageContextMenu(new Point(e.X, e.Y)); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button == MouseButtons.Left && + DockPane.DockPanel.AllowEndUserDocking && + DockPane.AllowDockDragAndDrop && + !DockHelper.IsDockStateAutoHide(DockPane.DockState) && + DockPane.ActiveContent != null) + DockPane.DockPanel.BeginDrag(DockPane); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK) + { + if (DockHelper.IsDockStateAutoHide(DockPane.DockState)) + { + DockPane.DockPanel.ActiveAutoHideContent = null; + return; + } + + if (DockPane.IsFloat) + DockPane.RestoreToPanel(); + else + DockPane.Float(); + } + base.WndProc(ref m); + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + OnRefreshChanges(); + } + + protected virtual void OnRightToLeftLayoutChanged() + { + } + + protected virtual void OnRefreshChanges() + { + } + + protected internal abstract int MeasureHeight(); + } +} diff --git a/WinFormsUI/Docking/DockPaneCollection.cs b/WinFormsUI/Docking/DockPaneCollection.cs new file mode 100644 index 0000000000..d946aca71c --- /dev/null +++ b/WinFormsUI/Docking/DockPaneCollection.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class DockPaneCollection : ReadOnlyCollection + { + internal DockPaneCollection() + : base(new List()) + { + } + + internal int Add(DockPane pane) + { + if (Items.Contains(pane)) + return Items.IndexOf(pane); + + Items.Add(pane); + return Count - 1; + } + + internal void AddAt(DockPane pane, int index) + { + if (index < 0 || index > Items.Count - 1) + return; + + if (Contains(pane)) + return; + + Items.Insert(index, pane); + } + + internal void Dispose() + { + for (int i=Count - 1; i>=0; i--) + this[i].Close(); + } + + internal void Remove(DockPane pane) + { + Items.Remove(pane); + } + } +} diff --git a/WinFormsUI/Docking/DockPaneStripBase.cs b/WinFormsUI/Docking/DockPaneStripBase.cs new file mode 100644 index 0000000000..3329438399 --- /dev/null +++ b/WinFormsUI/Docking/DockPaneStripBase.cs @@ -0,0 +1,265 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Collections; +using System.Collections.Generic; +using System.Security.Permissions; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public abstract class DockPaneStripBase : Control + { + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public class Tab : IDisposable + { + private IDockContent m_content; + + public Tab(IDockContent content) + { + m_content = content; + } + + ~Tab() + { + Dispose(false); + } + + public IDockContent Content + { + get { return m_content; } + } + + public Form ContentForm + { + get { return m_content as Form; } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public sealed class TabCollection : IEnumerable + { + #region IEnumerable Members + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + #endregion + + internal TabCollection(DockPane pane) + { + m_dockPane = pane; + } + + private DockPane m_dockPane; + public DockPane DockPane + { + get { return m_dockPane; } + } + + public int Count + { + get { return DockPane.DisplayingContents.Count; } + } + + public Tab this[int index] + { + get + { + IDockContent content = DockPane.DisplayingContents[index]; + if (content == null) + throw (new ArgumentOutOfRangeException("index")); + return content.DockHandler.GetTab(DockPane.TabStripControl); + } + } + + public bool Contains(Tab tab) + { + return (IndexOf(tab) != -1); + } + + public bool Contains(IDockContent content) + { + return (IndexOf(content) != -1); + } + + public int IndexOf(Tab tab) + { + if (tab == null) + return -1; + + return DockPane.DisplayingContents.IndexOf(tab.Content); + } + + public int IndexOf(IDockContent content) + { + return DockPane.DisplayingContents.IndexOf(content); + } + } + + protected DockPaneStripBase(DockPane pane) + { + m_dockPane = pane; + + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.Selectable, false); + AllowDrop = true; + } + + private DockPane m_dockPane; + public DockPane DockPane + { + get { return m_dockPane; } + } + + protected DockPane.AppearanceStyle Appearance + { + get { return DockPane.Appearance; } + } + + private TabCollection m_tabs = null; + public TabCollection Tabs + { + get + { + if (m_tabs == null) + m_tabs = new TabCollection(DockPane); + + return m_tabs; + } + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + OnRefreshChanges(); + } + + protected virtual void OnRefreshChanges() + { + } + + protected internal abstract int MeasureHeight(); + + protected internal abstract void EnsureTabVisible(IDockContent content); + + public int HitTest() + { + return HitTest(PointToClient(Control.MousePosition)); + } + + public abstract int HitTest(Point point); + + protected internal abstract GraphicsPath GetOutline(int index); + + protected internal virtual Tab CreateTab(IDockContent content) + { + return new Tab(content); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + int index = HitTest(e.Location); + + if (index != -1) + { + if (e.Button == MouseButtons.Middle) + { + // Close the specified content. + IDockContent content = Tabs[index].Content; + DockPane.CloseContent(content); + } + else + { + IDockContent content = Tabs[index].Content; + if (DockPane.ActiveContent != content) + DockPane.ActiveContent = content; + } + } + + if (e.Button == MouseButtons.Left) + { + if (DockPane.DockPanel.AllowEndUserDocking && DockPane.AllowDockDragAndDrop && DockPane.ActiveContent.DockHandler.AllowEndUserDocking) + DockPane.DockPanel.BeginDrag(DockPane.ActiveContent.DockHandler); + } + } + + protected bool HasTabPageContextMenu + { + get { return DockPane.HasTabPageContextMenu; } + } + + protected void ShowTabPageContextMenu(Point position) + { + DockPane.ShowTabPageContextMenu(this, position); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + + if (e.Button == MouseButtons.Right) + ShowTabPageContextMenu(new Point(e.X, e.Y)); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK) + { + base.WndProc(ref m); + + int index = HitTest(); + if (DockPane.DockPanel.AllowEndUserDocking && index != -1) + { + IDockContent content = Tabs[index].Content; + if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown) + content.DockHandler.IsFloat = !content.DockHandler.IsFloat; + } + + return; + } + + base.WndProc(ref m); + return; + } + + protected override void OnDragOver(DragEventArgs drgevent) + { + base.OnDragOver(drgevent); + + if (!DockPane.DockPanel.RaiseTabsOnDragOver) + return; + + int index = HitTest(); + if (index != -1) + { + IDockContent content = Tabs[index].Content; + if (DockPane.ActiveContent != content) + DockPane.ActiveContent = content; + } + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.Appearance.cs b/WinFormsUI/Docking/DockPanel.Appearance.cs new file mode 100644 index 0000000000..eb97d901cf --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.Appearance.cs @@ -0,0 +1,35 @@ +using WeifenLuo.WinFormsUI.Docking.Skins; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public partial class DockPanel + { + private DockPanelSkin m_dockPanelSkin = DockPanelSkinBuilder.Create(Style.VisualStudio2005); + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockPanelSkin")] + public DockPanelSkin Skin + { + get { return m_dockPanelSkin; } + set { m_dockPanelSkin = value; } + } + + private Style m_dockPanelSkinStyle = Style.VisualStudio2005; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockPanelSkinStyle")] + [DefaultValue(Style.VisualStudio2005)] + public Style SkinStyle + { + get { return m_dockPanelSkinStyle; } + set + { + if (m_dockPanelSkinStyle == value) + return; + + m_dockPanelSkinStyle = value; + + Skin = DockPanelSkinBuilder.Create(m_dockPanelSkinStyle); + } + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.AutoHideWindow.cs b/WinFormsUI/Docking/DockPanel.AutoHideWindow.cs new file mode 100644 index 0000000000..4d910b8370 --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.AutoHideWindow.cs @@ -0,0 +1,634 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPanel + { + private class AutoHideWindowControl : Panel, ISplitterDragSource + { + private class SplitterControl : SplitterBase + { + public SplitterControl(AutoHideWindowControl autoHideWindow) + { + m_autoHideWindow = autoHideWindow; + } + + private AutoHideWindowControl m_autoHideWindow; + private AutoHideWindowControl AutoHideWindow + { + get { return m_autoHideWindow; } + } + + protected override int SplitterSize + { + get { return Measures.SplitterSize; } + } + + protected override void StartDrag() + { + AutoHideWindow.DockPanel.BeginDrag(AutoHideWindow, AutoHideWindow.RectangleToScreen(Bounds)); + } + } + + #region consts + private const int ANIMATE_TIME = 100; // in mini-seconds + #endregion + + private Timer m_timerMouseTrack; + private SplitterControl m_splitter; + + public AutoHideWindowControl(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + + m_timerMouseTrack = new Timer(); + m_timerMouseTrack.Tick += new EventHandler(TimerMouseTrack_Tick); + + Visible = false; + m_splitter = new SplitterControl(this); + Controls.Add(m_splitter); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + m_timerMouseTrack.Dispose(); + } + base.Dispose(disposing); + } + + private DockPanel m_dockPanel = null; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private DockPane m_activePane = null; + public DockPane ActivePane + { + get { return m_activePane; } + } + private void SetActivePane() + { + DockPane value = (ActiveContent == null ? null : ActiveContent.DockHandler.Pane); + + if (value == m_activePane) + return; + + m_activePane = value; + } + + private static readonly object ActiveContentChangedEvent = new object(); + public event EventHandler ActiveContentChanged + { + add { Events.AddHandler(ActiveContentChangedEvent, value); } + remove { Events.RemoveHandler(ActiveContentChangedEvent, value); } + } + + protected virtual void OnActiveContentChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent]; + if (handler != null) + handler(this, e); + } + + private IDockContent m_activeContent = null; + public IDockContent ActiveContent + { + get { return m_activeContent; } + set + { + if (value == m_activeContent) + return; + + if (value != null) + { + if (!DockHelper.IsDockStateAutoHide(value.DockHandler.DockState) || value.DockHandler.DockPanel != DockPanel) + throw (new InvalidOperationException(Strings.DockPanel_ActiveAutoHideContent_InvalidValue)); + } + + DockPanel.SuspendLayout(); + + if (m_activeContent != null) + { + if (m_activeContent.DockHandler.Form.ContainsFocus) + { + if (!Win32Helper.IsRunningOnMono) + { + DockPanel.ContentFocusManager.GiveUpFocus(m_activeContent); + } + } + + AnimateWindow(false); + } + + m_activeContent = value; + SetActivePane(); + if (ActivePane != null) + ActivePane.ActiveContent = m_activeContent; + + if (m_activeContent != null) + AnimateWindow(true); + + DockPanel.ResumeLayout(); + DockPanel.RefreshAutoHideStrip(); + + SetTimerMouseTrack(); + + OnActiveContentChanged(EventArgs.Empty); + } + } + + public DockState DockState + { + get { return ActiveContent == null ? DockState.Unknown : ActiveContent.DockHandler.DockState; } + } + + private bool m_flagAnimate = true; + private bool FlagAnimate + { + get { return m_flagAnimate; } + set { m_flagAnimate = value; } + } + + private bool m_flagDragging = false; + internal bool FlagDragging + { + get { return m_flagDragging; } + set + { + if (m_flagDragging == value) + return; + + m_flagDragging = value; + SetTimerMouseTrack(); + } + } + + private void AnimateWindow(bool show) + { + if (!FlagAnimate && Visible != show) + { + Visible = show; + return; + } + + Parent.SuspendLayout(); + + Rectangle rectSource = GetRectangle(!show); + Rectangle rectTarget = GetRectangle(show); + int dxLoc, dyLoc; + int dWidth, dHeight; + dxLoc = dyLoc = dWidth = dHeight = 0; + if (DockState == DockState.DockTopAutoHide) + dHeight = show ? 1 : -1; + else if (DockState == DockState.DockLeftAutoHide) + dWidth = show ? 1 : -1; + else if (DockState == DockState.DockRightAutoHide) + { + dxLoc = show ? -1 : 1; + dWidth = show ? 1 : -1; + } + else if (DockState == DockState.DockBottomAutoHide) + { + dyLoc = (show ? -1 : 1); + dHeight = (show ? 1 : -1); + } + + if (show) + { + Bounds = DockPanel.GetAutoHideWindowBounds(new Rectangle(-rectTarget.Width, -rectTarget.Height, rectTarget.Width, rectTarget.Height)); + if (Visible == false) + Visible = true; + PerformLayout(); + } + + SuspendLayout(); + + LayoutAnimateWindow(rectSource); + if (Visible == false) + Visible = true; + + int speedFactor = 1; + int totalPixels = (rectSource.Width != rectTarget.Width) ? + Math.Abs(rectSource.Width - rectTarget.Width) : + Math.Abs(rectSource.Height - rectTarget.Height); + int remainPixels = totalPixels; + DateTime startingTime = DateTime.Now; + while (rectSource != rectTarget) + { + DateTime startPerMove = DateTime.Now; + + rectSource.X += dxLoc * speedFactor; + rectSource.Y += dyLoc * speedFactor; + rectSource.Width += dWidth * speedFactor; + rectSource.Height += dHeight * speedFactor; + if (Math.Sign(rectTarget.X - rectSource.X) != Math.Sign(dxLoc)) + rectSource.X = rectTarget.X; + if (Math.Sign(rectTarget.Y - rectSource.Y) != Math.Sign(dyLoc)) + rectSource.Y = rectTarget.Y; + if (Math.Sign(rectTarget.Width - rectSource.Width) != Math.Sign(dWidth)) + rectSource.Width = rectTarget.Width; + if (Math.Sign(rectTarget.Height - rectSource.Height) != Math.Sign(dHeight)) + rectSource.Height = rectTarget.Height; + + LayoutAnimateWindow(rectSource); + if (Parent != null) + Parent.Update(); + + remainPixels -= speedFactor; + + while (true) + { + TimeSpan time = new TimeSpan(0, 0, 0, 0, ANIMATE_TIME); + TimeSpan elapsedPerMove = DateTime.Now - startPerMove; + TimeSpan elapsedTime = DateTime.Now - startingTime; + if (((int)((time - elapsedTime).TotalMilliseconds)) <= 0) + { + speedFactor = remainPixels; + break; + } + else + speedFactor = remainPixels * (int)elapsedPerMove.TotalMilliseconds / (int)((time - elapsedTime).TotalMilliseconds); + if (speedFactor >= 1) + break; + } + } + ResumeLayout(); + Parent.ResumeLayout(); + } + + private void LayoutAnimateWindow(Rectangle rect) + { + Bounds = DockPanel.GetAutoHideWindowBounds(rect); + + Rectangle rectClient = ClientRectangle; + + if (DockState == DockState.DockLeftAutoHide) + ActivePane.Location = new Point(rectClient.Right - 2 - Measures.SplitterSize - ActivePane.Width, ActivePane.Location.Y); + else if (DockState == DockState.DockTopAutoHide) + ActivePane.Location = new Point(ActivePane.Location.X, rectClient.Bottom - 2 - Measures.SplitterSize - ActivePane.Height); + } + + private Rectangle GetRectangle(bool show) + { + if (DockState == DockState.Unknown) + return Rectangle.Empty; + + Rectangle rect = DockPanel.AutoHideWindowRectangle; + + if (show) + return rect; + + if (DockState == DockState.DockLeftAutoHide) + rect.Width = 0; + else if (DockState == DockState.DockRightAutoHide) + { + rect.X += rect.Width; + rect.Width = 0; + } + else if (DockState == DockState.DockTopAutoHide) + rect.Height = 0; + else + { + rect.Y += rect.Height; + rect.Height = 0; + } + + return rect; + } + + private void SetTimerMouseTrack() + { + if (ActivePane == null || ActivePane.IsActivated || FlagDragging) + { + m_timerMouseTrack.Enabled = false; + return; + } + + // start the timer + int hovertime = SystemInformation.MouseHoverTime ; + + // assign a default value 400 in case of setting Timer.Interval invalid value exception + if (hovertime <= 0) + hovertime = 400; + + m_timerMouseTrack.Interval = 2 * (int)hovertime; + m_timerMouseTrack.Enabled = true; + } + + protected virtual Rectangle DisplayingRectangle + { + get + { + Rectangle rect = ClientRectangle; + + // exclude the border and the splitter + if (DockState == DockState.DockBottomAutoHide) + { + rect.Y += 2 + Measures.SplitterSize; + rect.Height -= 2 + Measures.SplitterSize; + } + else if (DockState == DockState.DockRightAutoHide) + { + rect.X += 2 + Measures.SplitterSize; + rect.Width -= 2 + Measures.SplitterSize; + } + else if (DockState == DockState.DockTopAutoHide) + rect.Height -= 2 + Measures.SplitterSize; + else if (DockState == DockState.DockLeftAutoHide) + rect.Width -= 2 + Measures.SplitterSize; + + return rect; + } + } + + protected override void OnLayout(LayoutEventArgs levent) + { + DockPadding.All = 0; + if (DockState == DockState.DockLeftAutoHide) + { + DockPadding.Right = 2; + m_splitter.Dock = DockStyle.Right; + } + else if (DockState == DockState.DockRightAutoHide) + { + DockPadding.Left = 2; + m_splitter.Dock = DockStyle.Left; + } + else if (DockState == DockState.DockTopAutoHide) + { + DockPadding.Bottom = 2; + m_splitter.Dock = DockStyle.Bottom; + } + else if (DockState == DockState.DockBottomAutoHide) + { + DockPadding.Top = 2; + m_splitter.Dock = DockStyle.Top; + } + + Rectangle rectDisplaying = DisplayingRectangle; + Rectangle rectHidden = new Rectangle(-rectDisplaying.Width, rectDisplaying.Y, rectDisplaying.Width, rectDisplaying.Height); + foreach (Control c in Controls) + { + DockPane pane = c as DockPane; + if (pane == null) + continue; + + + if (pane == ActivePane) + pane.Bounds = rectDisplaying; + else + pane.Bounds = rectHidden; + } + + base.OnLayout(levent); + } + + protected override void OnPaint(PaintEventArgs e) + { + // Draw the border + Graphics g = e.Graphics; + + if (DockState == DockState.DockBottomAutoHide) + g.DrawLine(SystemPens.ControlLightLight, 0, 1, ClientRectangle.Right, 1); + else if (DockState == DockState.DockRightAutoHide) + g.DrawLine(SystemPens.ControlLightLight, 1, 0, 1, ClientRectangle.Bottom); + else if (DockState == DockState.DockTopAutoHide) + { + g.DrawLine(SystemPens.ControlDark, 0, ClientRectangle.Height - 2, ClientRectangle.Right, ClientRectangle.Height - 2); + g.DrawLine(SystemPens.ControlDarkDark, 0, ClientRectangle.Height - 1, ClientRectangle.Right, ClientRectangle.Height - 1); + } + else if (DockState == DockState.DockLeftAutoHide) + { + g.DrawLine(SystemPens.ControlDark, ClientRectangle.Width - 2, 0, ClientRectangle.Width - 2, ClientRectangle.Bottom); + g.DrawLine(SystemPens.ControlDarkDark, ClientRectangle.Width - 1, 0, ClientRectangle.Width - 1, ClientRectangle.Bottom); + } + + base.OnPaint(e); + } + + public void RefreshActiveContent() + { + if (ActiveContent == null) + return; + + if (!DockHelper.IsDockStateAutoHide(ActiveContent.DockHandler.DockState)) + { + FlagAnimate = false; + ActiveContent = null; + FlagAnimate = true; + } + } + + public void RefreshActivePane() + { + SetTimerMouseTrack(); + } + + private void TimerMouseTrack_Tick(object sender, EventArgs e) + { + if (IsDisposed) + return; + + if (ActivePane == null || ActivePane.IsActivated) + { + m_timerMouseTrack.Enabled = false; + return; + } + + DockPane pane = ActivePane; + Point ptMouseInAutoHideWindow = PointToClient(Control.MousePosition); + Point ptMouseInDockPanel = DockPanel.PointToClient(Control.MousePosition); + + Rectangle rectTabStrip = DockPanel.GetTabStripRectangle(pane.DockState); + + if (!ClientRectangle.Contains(ptMouseInAutoHideWindow) && !rectTabStrip.Contains(ptMouseInDockPanel)) + { + ActiveContent = null; + m_timerMouseTrack.Enabled = false; + } + } + + #region ISplitterDragSource Members + + void ISplitterDragSource.BeginDrag(Rectangle rectSplitter) + { + FlagDragging = true; + } + + void ISplitterDragSource.EndDrag() + { + FlagDragging = false; + } + + bool ISplitterDragSource.IsVertical + { + get { return (DockState == DockState.DockLeftAutoHide || DockState == DockState.DockRightAutoHide); } + } + + Rectangle ISplitterDragSource.DragLimitBounds + { + get + { + Rectangle rectLimit = DockPanel.DockArea; + + if ((this as ISplitterDragSource).IsVertical) + { + rectLimit.X += MeasurePane.MinSize; + rectLimit.Width -= 2 * MeasurePane.MinSize; + } + else + { + rectLimit.Y += MeasurePane.MinSize; + rectLimit.Height -= 2 * MeasurePane.MinSize; + } + + return DockPanel.RectangleToScreen(rectLimit); + } + } + + void ISplitterDragSource.MoveSplitter(int offset) + { + Rectangle rectDockArea = DockPanel.DockArea; + IDockContent content = ActiveContent; + if (DockState == DockState.DockLeftAutoHide && rectDockArea.Width > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion += ((double)offset) / (double)rectDockArea.Width; + else + content.DockHandler.AutoHidePortion = Width + offset; + } + else if (DockState == DockState.DockRightAutoHide && rectDockArea.Width > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion -= ((double)offset) / (double)rectDockArea.Width; + else + content.DockHandler.AutoHidePortion = Width - offset; + } + else if (DockState == DockState.DockBottomAutoHide && rectDockArea.Height > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion -= ((double)offset) / (double)rectDockArea.Height; + else + content.DockHandler.AutoHidePortion = Height - offset; + } + else if (DockState == DockState.DockTopAutoHide && rectDockArea.Height > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion += ((double)offset) / (double)rectDockArea.Height; + else + content.DockHandler.AutoHidePortion = Height + offset; + } + } + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + + #endregion + } + + private AutoHideWindowControl AutoHideWindow + { + get { return m_autoHideWindow; } + } + + internal Control AutoHideControl + { + get { return m_autoHideWindow; } + } + + internal void RefreshActiveAutoHideContent() + { + AutoHideWindow.RefreshActiveContent(); + } + + internal Rectangle AutoHideWindowRectangle + { + get + { + DockState state = AutoHideWindow.DockState; + Rectangle rectDockArea = DockArea; + if (ActiveAutoHideContent == null) + return Rectangle.Empty; + + if (Parent == null) + return Rectangle.Empty; + + Rectangle rect = Rectangle.Empty; + double autoHideSize = ActiveAutoHideContent.DockHandler.AutoHidePortion; + if (state == DockState.DockLeftAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Width * autoHideSize; + if (autoHideSize > rectDockArea.Width - MeasurePane.MinSize) + autoHideSize = rectDockArea.Width - MeasurePane.MinSize; + rect.X = rectDockArea.X; + rect.Y = rectDockArea.Y; + rect.Width = (int)autoHideSize; + rect.Height = rectDockArea.Height; + } + else if (state == DockState.DockRightAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Width * autoHideSize; + if (autoHideSize > rectDockArea.Width - MeasurePane.MinSize) + autoHideSize = rectDockArea.Width - MeasurePane.MinSize; + rect.X = rectDockArea.X + rectDockArea.Width - (int)autoHideSize; + rect.Y = rectDockArea.Y; + rect.Width = (int)autoHideSize; + rect.Height = rectDockArea.Height; + } + else if (state == DockState.DockTopAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Height * autoHideSize; + if (autoHideSize > rectDockArea.Height - MeasurePane.MinSize) + autoHideSize = rectDockArea.Height - MeasurePane.MinSize; + rect.X = rectDockArea.X; + rect.Y = rectDockArea.Y; + rect.Width = rectDockArea.Width; + rect.Height = (int)autoHideSize; + } + else if (state == DockState.DockBottomAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Height * autoHideSize; + if (autoHideSize > rectDockArea.Height - MeasurePane.MinSize) + autoHideSize = rectDockArea.Height - MeasurePane.MinSize; + rect.X = rectDockArea.X; + rect.Y = rectDockArea.Y + rectDockArea.Height - (int)autoHideSize; + rect.Width = rectDockArea.Width; + rect.Height = (int)autoHideSize; + } + + return rect; + } + } + + internal Rectangle GetAutoHideWindowBounds(Rectangle rectAutoHideWindow) + { + if (DocumentStyle == DocumentStyle.SystemMdi || + DocumentStyle == DocumentStyle.DockingMdi) + return (Parent == null) ? Rectangle.Empty : Parent.RectangleToClient(RectangleToScreen(rectAutoHideWindow)); + else + return rectAutoHideWindow; + } + + internal void RefreshAutoHideStrip() + { + AutoHideStripControl.RefreshChanges(); + } + + } +} diff --git a/WinFormsUI/Docking/DockPanel.DockDragHandler.cs b/WinFormsUI/Docking/DockPanel.DockDragHandler.cs new file mode 100644 index 0000000000..2e5935b8e7 --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.DockDragHandler.cs @@ -0,0 +1,816 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPanel + { + private sealed class DockDragHandler : DragHandler + { + private class DockIndicator : DragForm + { + #region IHitTest + private interface IHitTest + { + DockStyle HitTest(Point pt); + DockStyle Status { get; set; } + } + #endregion + + #region PanelIndicator + private class PanelIndicator : PictureBox, IHitTest + { + private static Image _imagePanelLeft = Resources.DockIndicator_PanelLeft; + private static Image _imagePanelRight = Resources.DockIndicator_PanelRight; + private static Image _imagePanelTop = Resources.DockIndicator_PanelTop; + private static Image _imagePanelBottom = Resources.DockIndicator_PanelBottom; + private static Image _imagePanelFill = Resources.DockIndicator_PanelFill; + private static Image _imagePanelLeftActive = Resources.DockIndicator_PanelLeft_Active; + private static Image _imagePanelRightActive = Resources.DockIndicator_PanelRight_Active; + private static Image _imagePanelTopActive = Resources.DockIndicator_PanelTop_Active; + private static Image _imagePanelBottomActive = Resources.DockIndicator_PanelBottom_Active; + private static Image _imagePanelFillActive = Resources.DockIndicator_PanelFill_Active; + + public PanelIndicator(DockStyle dockStyle) + { + m_dockStyle = dockStyle; + SizeMode = PictureBoxSizeMode.AutoSize; + Image = ImageInactive; + } + + private DockStyle m_dockStyle; + private DockStyle DockStyle + { + get { return m_dockStyle; } + } + + private DockStyle m_status; + public DockStyle Status + { + get { return m_status; } + set + { + if (value != DockStyle && value != DockStyle.None) + throw new InvalidEnumArgumentException(); + + if (m_status == value) + return; + + m_status = value; + IsActivated = (m_status != DockStyle.None); + } + } + + private Image ImageInactive + { + get + { + if (DockStyle == DockStyle.Left) + return _imagePanelLeft; + else if (DockStyle == DockStyle.Right) + return _imagePanelRight; + else if (DockStyle == DockStyle.Top) + return _imagePanelTop; + else if (DockStyle == DockStyle.Bottom) + return _imagePanelBottom; + else if (DockStyle == DockStyle.Fill) + return _imagePanelFill; + else + return null; + } + } + + private Image ImageActive + { + get + { + if (DockStyle == DockStyle.Left) + return _imagePanelLeftActive; + else if (DockStyle == DockStyle.Right) + return _imagePanelRightActive; + else if (DockStyle == DockStyle.Top) + return _imagePanelTopActive; + else if (DockStyle == DockStyle.Bottom) + return _imagePanelBottomActive; + else if (DockStyle == DockStyle.Fill) + return _imagePanelFillActive; + else + return null; + } + } + + private bool m_isActivated = false; + private bool IsActivated + { + get { return m_isActivated; } + set + { + m_isActivated = value; + Image = IsActivated ? ImageActive : ImageInactive; + } + } + + public DockStyle HitTest(Point pt) + { + return this.Visible && ClientRectangle.Contains(PointToClient(pt)) ? DockStyle : DockStyle.None; + } + } + #endregion PanelIndicator + + #region PaneIndicator + private class PaneIndicator : PictureBox, IHitTest + { + private struct HotSpotIndex + { + public HotSpotIndex(int x, int y, DockStyle dockStyle) + { + m_x = x; + m_y = y; + m_dockStyle = dockStyle; + } + + private int m_x; + public int X + { + get { return m_x; } + } + + private int m_y; + public int Y + { + get { return m_y; } + } + + private DockStyle m_dockStyle; + public DockStyle DockStyle + { + get { return m_dockStyle; } + } + } + + private static Bitmap _bitmapPaneDiamond = Resources.DockIndicator_PaneDiamond; + private static Bitmap _bitmapPaneDiamondLeft = Resources.DockIndicator_PaneDiamond_Left; + private static Bitmap _bitmapPaneDiamondRight = Resources.DockIndicator_PaneDiamond_Right; + private static Bitmap _bitmapPaneDiamondTop = Resources.DockIndicator_PaneDiamond_Top; + private static Bitmap _bitmapPaneDiamondBottom = Resources.DockIndicator_PaneDiamond_Bottom; + private static Bitmap _bitmapPaneDiamondFill = Resources.DockIndicator_PaneDiamond_Fill; + private static Bitmap _bitmapPaneDiamondHotSpot = Resources.DockIndicator_PaneDiamond_HotSpot; + private static Bitmap _bitmapPaneDiamondHotSpotIndex = Resources.DockIndicator_PaneDiamond_HotSpotIndex; + private static HotSpotIndex[] _hotSpots = new HotSpotIndex[] + { + new HotSpotIndex(1, 0, DockStyle.Top), + new HotSpotIndex(0, 1, DockStyle.Left), + new HotSpotIndex(1, 1, DockStyle.Fill), + new HotSpotIndex(2, 1, DockStyle.Right), + new HotSpotIndex(1, 2, DockStyle.Bottom) + }; + private static GraphicsPath _displayingGraphicsPath = DrawHelper.CalculateGraphicsPathFromBitmap(_bitmapPaneDiamond); + + public PaneIndicator() + { + SizeMode = PictureBoxSizeMode.AutoSize; + Image = _bitmapPaneDiamond; + Region = new Region(DisplayingGraphicsPath); + } + + public static GraphicsPath DisplayingGraphicsPath + { + get { return _displayingGraphicsPath; } + } + + public DockStyle HitTest(Point pt) + { + if (!Visible) + return DockStyle.None; + + pt = PointToClient(pt); + if (!ClientRectangle.Contains(pt)) + return DockStyle.None; + + for (int i = _hotSpots.GetLowerBound(0); i <= _hotSpots.GetUpperBound(0); i++) + { + if (_bitmapPaneDiamondHotSpot.GetPixel(pt.X, pt.Y) == _bitmapPaneDiamondHotSpotIndex.GetPixel(_hotSpots[i].X, _hotSpots[i].Y)) + return _hotSpots[i].DockStyle; + } + + return DockStyle.None; + } + + private DockStyle m_status = DockStyle.None; + public DockStyle Status + { + get { return m_status; } + set + { + m_status = value; + if (m_status == DockStyle.None) + Image = _bitmapPaneDiamond; + else if (m_status == DockStyle.Left) + Image = _bitmapPaneDiamondLeft; + else if (m_status == DockStyle.Right) + Image = _bitmapPaneDiamondRight; + else if (m_status == DockStyle.Top) + Image = _bitmapPaneDiamondTop; + else if (m_status == DockStyle.Bottom) + Image = _bitmapPaneDiamondBottom; + else if (m_status == DockStyle.Fill) + Image = _bitmapPaneDiamondFill; + } + } + } + #endregion PaneIndicator + + #region consts + private int _PanelIndicatorMargin = 10; + #endregion + + private DockDragHandler m_dragHandler; + + public DockIndicator(DockDragHandler dragHandler) + { + m_dragHandler = dragHandler; + Controls.AddRange(new Control[] { + PaneDiamond, + PanelLeft, + PanelRight, + PanelTop, + PanelBottom, + PanelFill + }); + Region = new Region(Rectangle.Empty); + } + + private PaneIndicator m_paneDiamond = null; + private PaneIndicator PaneDiamond + { + get + { + if (m_paneDiamond == null) + m_paneDiamond = new PaneIndicator(); + + return m_paneDiamond; + } + } + + private PanelIndicator m_panelLeft = null; + private PanelIndicator PanelLeft + { + get + { + if (m_panelLeft == null) + m_panelLeft = new PanelIndicator(DockStyle.Left); + + return m_panelLeft; + } + } + + private PanelIndicator m_panelRight = null; + private PanelIndicator PanelRight + { + get + { + if (m_panelRight == null) + m_panelRight = new PanelIndicator(DockStyle.Right); + + return m_panelRight; + } + } + + private PanelIndicator m_panelTop = null; + private PanelIndicator PanelTop + { + get + { + if (m_panelTop == null) + m_panelTop = new PanelIndicator(DockStyle.Top); + + return m_panelTop; + } + } + + private PanelIndicator m_panelBottom = null; + private PanelIndicator PanelBottom + { + get + { + if (m_panelBottom == null) + m_panelBottom = new PanelIndicator(DockStyle.Bottom); + + return m_panelBottom; + } + } + + private PanelIndicator m_panelFill = null; + private PanelIndicator PanelFill + { + get + { + if (m_panelFill == null) + m_panelFill = new PanelIndicator(DockStyle.Fill); + + return m_panelFill; + } + } + + private bool m_fullPanelEdge = false; + public bool FullPanelEdge + { + get { return m_fullPanelEdge; } + set + { + if (m_fullPanelEdge == value) + return; + + m_fullPanelEdge = value; + RefreshChanges(); + } + } + + public DockDragHandler DragHandler + { + get { return m_dragHandler; } + } + + public DockPanel DockPanel + { + get { return DragHandler.DockPanel; } + } + + private DockPane m_dockPane = null; + public DockPane DockPane + { + get { return m_dockPane; } + internal set + { + if (m_dockPane == value) + return; + + DockPane oldDisplayingPane = DisplayingPane; + m_dockPane = value; + if (oldDisplayingPane != DisplayingPane) + RefreshChanges(); + } + } + + private IHitTest m_hitTest = null; + private IHitTest HitTestResult + { + get { return m_hitTest; } + set + { + if (m_hitTest == value) + return; + + if (m_hitTest != null) + m_hitTest.Status = DockStyle.None; + + m_hitTest = value; + } + } + + private DockPane DisplayingPane + { + get { return ShouldPaneDiamondVisible() ? DockPane : null; } + } + + private void RefreshChanges() + { + Region region = new Region(Rectangle.Empty); + Rectangle rectDockArea = FullPanelEdge ? DockPanel.DockArea : DockPanel.DocumentWindowBounds; + + rectDockArea = RectangleToClient(DockPanel.RectangleToScreen(rectDockArea)); + if (ShouldPanelIndicatorVisible(DockState.DockLeft)) + { + PanelLeft.Location = new Point(rectDockArea.X + _PanelIndicatorMargin, rectDockArea.Y + (rectDockArea.Height - PanelRight.Height) / 2); + PanelLeft.Visible = true; + region.Union(PanelLeft.Bounds); + } + else + PanelLeft.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.DockRight)) + { + PanelRight.Location = new Point(rectDockArea.X + rectDockArea.Width - PanelRight.Width - _PanelIndicatorMargin, rectDockArea.Y + (rectDockArea.Height - PanelRight.Height) / 2); + PanelRight.Visible = true; + region.Union(PanelRight.Bounds); + } + else + PanelRight.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.DockTop)) + { + PanelTop.Location = new Point(rectDockArea.X + (rectDockArea.Width - PanelTop.Width) / 2, rectDockArea.Y + _PanelIndicatorMargin); + PanelTop.Visible = true; + region.Union(PanelTop.Bounds); + } + else + PanelTop.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.DockBottom)) + { + PanelBottom.Location = new Point(rectDockArea.X + (rectDockArea.Width - PanelBottom.Width) / 2, rectDockArea.Y + rectDockArea.Height - PanelBottom.Height - _PanelIndicatorMargin); + PanelBottom.Visible = true; + region.Union(PanelBottom.Bounds); + } + else + PanelBottom.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.Document)) + { + Rectangle rectDocumentWindow = RectangleToClient(DockPanel.RectangleToScreen(DockPanel.DocumentWindowBounds)); + PanelFill.Location = new Point(rectDocumentWindow.X + (rectDocumentWindow.Width - PanelFill.Width) / 2, rectDocumentWindow.Y + (rectDocumentWindow.Height - PanelFill.Height) / 2); + PanelFill.Visible = true; + region.Union(PanelFill.Bounds); + } + else + PanelFill.Visible = false; + + if (ShouldPaneDiamondVisible()) + { + Rectangle rect = RectangleToClient(DockPane.RectangleToScreen(DockPane.ClientRectangle)); + PaneDiamond.Location = new Point(rect.Left + (rect.Width - PaneDiamond.Width) / 2, rect.Top + (rect.Height - PaneDiamond.Height) / 2); + PaneDiamond.Visible = true; + using (GraphicsPath graphicsPath = PaneIndicator.DisplayingGraphicsPath.Clone() as GraphicsPath) + { + Point[] pts = new Point[] + { + new Point(PaneDiamond.Left, PaneDiamond.Top), + new Point(PaneDiamond.Right, PaneDiamond.Top), + new Point(PaneDiamond.Left, PaneDiamond.Bottom) + }; + using (Matrix matrix = new Matrix(PaneDiamond.ClientRectangle, pts)) + { + graphicsPath.Transform(matrix); + } + region.Union(graphicsPath); + } + } + else + PaneDiamond.Visible = false; + + Region = region; + } + + private bool ShouldPanelIndicatorVisible(DockState dockState) + { + if (!Visible) + return false; + + if (DockPanel.DockWindows[dockState].Visible) + return false; + + return DragHandler.DragSource.IsDockStateValid(dockState); + } + + private bool ShouldPaneDiamondVisible() + { + if (DockPane == null) + return false; + + if (!DockPanel.AllowEndUserNestedDocking) + return false; + + return DragHandler.DragSource.CanDockTo(DockPane); + } + + public override void Show(bool bActivate) + { + base.Show(bActivate); + Bounds = SystemInformation.VirtualScreen; + RefreshChanges(); + } + + public void TestDrop() + { + Point pt = Control.MousePosition; + DockPane = DockHelper.PaneAtPoint(pt, DockPanel); + + if (TestDrop(PanelLeft, pt) != DockStyle.None) + HitTestResult = PanelLeft; + else if (TestDrop(PanelRight, pt) != DockStyle.None) + HitTestResult = PanelRight; + else if (TestDrop(PanelTop, pt) != DockStyle.None) + HitTestResult = PanelTop; + else if (TestDrop(PanelBottom, pt) != DockStyle.None) + HitTestResult = PanelBottom; + else if (TestDrop(PanelFill, pt) != DockStyle.None) + HitTestResult = PanelFill; + else if (TestDrop(PaneDiamond, pt) != DockStyle.None) + HitTestResult = PaneDiamond; + else + HitTestResult = null; + + if (HitTestResult != null) + { + if (HitTestResult is PaneIndicator) + DragHandler.Outline.Show(DockPane, HitTestResult.Status); + else + DragHandler.Outline.Show(DockPanel, HitTestResult.Status, FullPanelEdge); + } + } + + private static DockStyle TestDrop(IHitTest hitTest, Point pt) + { + return hitTest.Status = hitTest.HitTest(pt); + } + } + + private class DockOutline : DockOutlineBase + { + public DockOutline() + { + m_dragForm = new DragForm(); + SetDragForm(Rectangle.Empty); + DragForm.BackColor = SystemColors.ActiveCaption; + DragForm.Opacity = 0.5; + DragForm.Show(false); + } + + DragForm m_dragForm; + private DragForm DragForm + { + get { return m_dragForm; } + } + + protected override void OnShow() + { + CalculateRegion(); + } + + protected override void OnClose() + { + DragForm.Close(); + } + + private void CalculateRegion() + { + if (SameAsOldValue) + return; + + if (!FloatWindowBounds.IsEmpty) + SetOutline(FloatWindowBounds); + else if (DockTo is DockPanel) + SetOutline(DockTo as DockPanel, Dock, (ContentIndex != 0)); + else if (DockTo is DockPane) + SetOutline(DockTo as DockPane, Dock, ContentIndex); + else + SetOutline(); + } + + private void SetOutline() + { + SetDragForm(Rectangle.Empty); + } + + private void SetOutline(Rectangle floatWindowBounds) + { + SetDragForm(floatWindowBounds); + } + + private void SetOutline(DockPanel dockPanel, DockStyle dock, bool fullPanelEdge) + { + Rectangle rect = fullPanelEdge ? dockPanel.DockArea : dockPanel.DocumentWindowBounds; + rect.Location = dockPanel.PointToScreen(rect.Location); + if (dock == DockStyle.Top) + { + int height = dockPanel.GetDockWindowSize(DockState.DockTop); + rect = new Rectangle(rect.X, rect.Y, rect.Width, height); + } + else if (dock == DockStyle.Bottom) + { + int height = dockPanel.GetDockWindowSize(DockState.DockBottom); + rect = new Rectangle(rect.X, rect.Bottom - height, rect.Width, height); + } + else if (dock == DockStyle.Left) + { + int width = dockPanel.GetDockWindowSize(DockState.DockLeft); + rect = new Rectangle(rect.X, rect.Y, width, rect.Height); + } + else if (dock == DockStyle.Right) + { + int width = dockPanel.GetDockWindowSize(DockState.DockRight); + rect = new Rectangle(rect.Right - width, rect.Y, width, rect.Height); + } + else if (dock == DockStyle.Fill) + { + rect = dockPanel.DocumentWindowBounds; + rect.Location = dockPanel.PointToScreen(rect.Location); + } + + SetDragForm(rect); + } + + private void SetOutline(DockPane pane, DockStyle dock, int contentIndex) + { + if (dock != DockStyle.Fill) + { + Rectangle rect = pane.DisplayingRectangle; + if (dock == DockStyle.Right) + rect.X += rect.Width / 2; + if (dock == DockStyle.Bottom) + rect.Y += rect.Height / 2; + if (dock == DockStyle.Left || dock == DockStyle.Right) + rect.Width -= rect.Width / 2; + if (dock == DockStyle.Top || dock == DockStyle.Bottom) + rect.Height -= rect.Height / 2; + rect.Location = pane.PointToScreen(rect.Location); + + SetDragForm(rect); + } + else if (contentIndex == -1) + { + Rectangle rect = pane.DisplayingRectangle; + rect.Location = pane.PointToScreen(rect.Location); + SetDragForm(rect); + } + else + { + using (GraphicsPath path = pane.TabStripControl.GetOutline(contentIndex)) + { + RectangleF rectF = path.GetBounds(); + Rectangle rect = new Rectangle((int)rectF.X, (int)rectF.Y, (int)rectF.Width, (int)rectF.Height); + using (Matrix matrix = new Matrix(rect, new Point[] { new Point(0, 0), new Point(rect.Width, 0), new Point(0, rect.Height) })) + { + path.Transform(matrix); + } + Region region = new Region(path); + SetDragForm(rect, region); + } + } + } + + private void SetDragForm(Rectangle rect) + { + DragForm.Bounds = rect; + if (rect == Rectangle.Empty) + DragForm.Region = new Region(Rectangle.Empty); + else if (DragForm.Region != null) + DragForm.Region = null; + } + + private void SetDragForm(Rectangle rect, Region region) + { + DragForm.Bounds = rect; + DragForm.Region = region; + } + } + + public DockDragHandler(DockPanel panel) + : base(panel) + { + } + + public new IDockDragSource DragSource + { + get { return base.DragSource as IDockDragSource; } + set { base.DragSource = value; } + } + + private DockOutlineBase m_outline; + public DockOutlineBase Outline + { + get { return m_outline; } + private set { m_outline = value; } + } + + private DockIndicator m_indicator; + private DockIndicator Indicator + { + get { return m_indicator; } + set { m_indicator = value; } + } + + private Rectangle m_floatOutlineBounds; + private Rectangle FloatOutlineBounds + { + get { return m_floatOutlineBounds; } + set { m_floatOutlineBounds = value; } + } + + public void BeginDrag(IDockDragSource dragSource) + { + DragSource = dragSource; + + if (!BeginDrag()) + { + DragSource = null; + return; + } + + Outline = new DockOutline(); + Indicator = new DockIndicator(this); + Indicator.Show(false); + + FloatOutlineBounds = DragSource.BeginDrag(StartMousePosition); + } + + protected override void OnDragging() + { + TestDrop(); + } + + protected override void OnEndDrag(bool abort) + { + DockPanel.SuspendLayout(true); + + Outline.Close(); + Indicator.Close(); + + EndDrag(abort); + + // Queue a request to layout all children controls + DockPanel.PerformMdiClientLayout(); + + DockPanel.ResumeLayout(true, true); + + DragSource.EndDrag(); + + DragSource = null; + } + + private void TestDrop() + { + Outline.FlagTestDrop = false; + + Indicator.FullPanelEdge = ((Control.ModifierKeys & Keys.Shift) != 0); + + if ((Control.ModifierKeys & Keys.Control) == 0) + { + Indicator.TestDrop(); + + if (!Outline.FlagTestDrop) + { + DockPane pane = DockHelper.PaneAtPoint(Control.MousePosition, DockPanel); + if (pane != null && DragSource.IsDockStateValid(pane.DockState)) + pane.TestDrop(DragSource, Outline); + } + + if (!Outline.FlagTestDrop && DragSource.IsDockStateValid(DockState.Float)) + { + FloatWindow floatWindow = DockHelper.FloatWindowAtPoint(Control.MousePosition, DockPanel); + if (floatWindow != null) + floatWindow.TestDrop(DragSource, Outline); + } + } + else + Indicator.DockPane = DockHelper.PaneAtPoint(Control.MousePosition, DockPanel); + + if (!Outline.FlagTestDrop) + { + if (DragSource.IsDockStateValid(DockState.Float)) + { + Rectangle rect = FloatOutlineBounds; + rect.Offset(Control.MousePosition.X - StartMousePosition.X, Control.MousePosition.Y - StartMousePosition.Y); + Outline.Show(rect); + } + } + + if (!Outline.FlagTestDrop) + { + Cursor.Current = Cursors.No; + Outline.Show(); + } + else + Cursor.Current = DragControl.Cursor; + } + + private void EndDrag(bool abort) + { + if (abort) + return; + + if (!Outline.FloatWindowBounds.IsEmpty) + DragSource.FloatAt(Outline.FloatWindowBounds); + else if (Outline.DockTo is DockPane) + { + DockPane pane = Outline.DockTo as DockPane; + DragSource.DockTo(pane, Outline.Dock, Outline.ContentIndex); + } + else if (Outline.DockTo is DockPanel) + { + DockPanel panel = Outline.DockTo as DockPanel; + panel.UpdateDockWindowZOrder(Outline.Dock, Outline.FlagFullEdge); + DragSource.DockTo(panel, Outline.Dock); + } + } + } + + private DockDragHandler m_dockDragHandler = null; + private DockDragHandler GetDockDragHandler() + { + if (m_dockDragHandler == null) + m_dockDragHandler = new DockDragHandler(this); + return m_dockDragHandler; + } + + internal void BeginDrag(IDockDragSource dragSource) + { + GetDockDragHandler().BeginDrag(dragSource); + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.DragHandler.cs b/WinFormsUI/Docking/DockPanel.DragHandler.cs new file mode 100644 index 0000000000..2ae47d02ae --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.DragHandler.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPanel + { + /// + /// DragHandlerBase is the base class for drag handlers. The derived class should: + /// 1. Define its public method BeginDrag. From within this public BeginDrag method, + /// DragHandlerBase.BeginDrag should be called to initialize the mouse capture + /// and message filtering. + /// 2. Override the OnDragging and OnEndDrag methods. + /// + private abstract class DragHandlerBase : NativeWindow, IMessageFilter + { + protected DragHandlerBase() + { + } + + protected abstract Control DragControl + { + get; + } + + private Point m_startMousePosition = Point.Empty; + protected Point StartMousePosition + { + get { return m_startMousePosition; } + private set { m_startMousePosition = value; } + } + + protected bool BeginDrag() + { + if (DragControl == null) + return false; + + StartMousePosition = Control.MousePosition; + + if (!Win32Helper.IsRunningOnMono) + { + if (!NativeMethods.DragDetect(DragControl.Handle, StartMousePosition)) + { + return false; + } + } + + DragControl.FindForm().Capture = true; + AssignHandle(DragControl.FindForm().Handle); + Application.AddMessageFilter(this); + return true; + } + + protected abstract void OnDragging(); + + protected abstract void OnEndDrag(bool abort); + + private void EndDrag(bool abort) + { + ReleaseHandle(); + Application.RemoveMessageFilter(this); + DragControl.FindForm().Capture = false; + + OnEndDrag(abort); + } + + bool IMessageFilter.PreFilterMessage(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_MOUSEMOVE) + OnDragging(); + else if (m.Msg == (int)Win32.Msgs.WM_LBUTTONUP) + EndDrag(false); + else if (m.Msg == (int)Win32.Msgs.WM_CAPTURECHANGED) + EndDrag(true); + else if (m.Msg == (int)Win32.Msgs.WM_KEYDOWN && (int)m.WParam == (int)Keys.Escape) + EndDrag(true); + + return OnPreFilterMessage(ref m); + } + + protected virtual bool OnPreFilterMessage(ref Message m) + { + return false; + } + + protected sealed override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_CANCELMODE || m.Msg == (int)Win32.Msgs.WM_CAPTURECHANGED) + EndDrag(true); + + base.WndProc(ref m); + } + } + + private abstract class DragHandler : DragHandlerBase + { + private DockPanel m_dockPanel; + + protected DragHandler(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + } + + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private IDragSource m_dragSource; + protected IDragSource DragSource + { + get { return m_dragSource; } + set { m_dragSource = value; } + } + + protected sealed override Control DragControl + { + get { return DragSource == null ? null : DragSource.DragControl; } + } + + protected sealed override bool OnPreFilterMessage(ref Message m) + { + if ((m.Msg == (int)Win32.Msgs.WM_KEYDOWN || m.Msg == (int)Win32.Msgs.WM_KEYUP) && + ((int)m.WParam == (int)Keys.ControlKey || (int)m.WParam == (int)Keys.ShiftKey)) + OnDragging(); + + return base.OnPreFilterMessage(ref m); + } + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.FocusManager.cs b/WinFormsUI/Docking/DockPanel.FocusManager.cs new file mode 100644 index 0000000000..a159faec10 --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.FocusManager.cs @@ -0,0 +1,595 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal interface IContentFocusManager + { + void Activate(IDockContent content); + void GiveUpFocus(IDockContent content); + void AddToList(IDockContent content); + void RemoveFromList(IDockContent content); + } + + partial class DockPanel + { + private interface IFocusManager + { + void SuspendFocusTracking(); + void ResumeFocusTracking(); + bool IsFocusTrackingSuspended { get; } + IDockContent ActiveContent { get; } + DockPane ActivePane { get; } + IDockContent ActiveDocument { get; } + DockPane ActiveDocumentPane { get; } + } + + private class FocusManagerImpl : Component, IContentFocusManager, IFocusManager + { + private class HookEventArgs : EventArgs + { + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public int HookCode; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public IntPtr wParam; + public IntPtr lParam; + } + + private class LocalWindowsHook : IDisposable + { + // Internal properties + private IntPtr m_hHook = IntPtr.Zero; + private NativeMethods.HookProc m_filterFunc = null; + private Win32.HookType m_hookType; + + // Event delegate + public delegate void HookEventHandler(object sender, HookEventArgs e); + + // Event: HookInvoked + public event HookEventHandler HookInvoked; + protected void OnHookInvoked(HookEventArgs e) + { + if (HookInvoked != null) + HookInvoked(this, e); + } + + public LocalWindowsHook(Win32.HookType hook) + { + m_hookType = hook; + m_filterFunc = new NativeMethods.HookProc(this.CoreHookProc); + } + + // Default filter function + public IntPtr CoreHookProc(int code, IntPtr wParam, IntPtr lParam) + { + if (code < 0) + return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam); + + // Let clients determine what to do + HookEventArgs e = new HookEventArgs(); + e.HookCode = code; + e.wParam = wParam; + e.lParam = lParam; + OnHookInvoked(e); + + // Yield to the next hook in the chain + return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam); + } + + // Install the hook + public void Install() + { + if (m_hHook != IntPtr.Zero) + Uninstall(); + + int threadId = NativeMethods.GetCurrentThreadId(); + m_hHook = NativeMethods.SetWindowsHookEx(m_hookType, m_filterFunc, IntPtr.Zero, threadId); + } + + // Uninstall the hook + public void Uninstall() + { + if (m_hHook != IntPtr.Zero) + { + NativeMethods.UnhookWindowsHookEx(m_hHook); + m_hHook = IntPtr.Zero; + } + } + + ~LocalWindowsHook() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + Uninstall(); + } + } + + // Use a static instance of the windows hook to prevent stack overflows in the windows kernel. + [ThreadStatic] + private static LocalWindowsHook sm_localWindowsHook; + + private LocalWindowsHook.HookEventHandler m_hookEventHandler; + + public FocusManagerImpl(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + if (Win32Helper.IsRunningOnMono) + return; + m_hookEventHandler = new LocalWindowsHook.HookEventHandler(HookEventHandler); + + // Ensure the windows hook has been created for this thread + if (sm_localWindowsHook == null) + { + sm_localWindowsHook = new LocalWindowsHook(Win32.HookType.WH_CALLWNDPROCRET); + sm_localWindowsHook.Install(); + } + + sm_localWindowsHook.HookInvoked += m_hookEventHandler; + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private bool m_disposed = false; + protected override void Dispose(bool disposing) + { + if (!m_disposed && disposing) + { + if (!Win32Helper.IsRunningOnMono) + { + sm_localWindowsHook.HookInvoked -= m_hookEventHandler; + } + + m_disposed = true; + } + + base.Dispose(disposing); + } + + private IDockContent m_contentActivating = null; + private IDockContent ContentActivating + { + get { return m_contentActivating; } + set { m_contentActivating = value; } + } + + public void Activate(IDockContent content) + { + if (IsFocusTrackingSuspended) + { + ContentActivating = content; + return; + } + + if (content == null) + return; + DockContentHandler handler = content.DockHandler; + if (handler.Form.IsDisposed) + return; // Should not reach here, but better than throwing an exception + if (ContentContains(content, handler.ActiveWindowHandle)) + { + if (!Win32Helper.IsRunningOnMono) + { + NativeMethods.SetFocus(handler.ActiveWindowHandle); + } + } + + if (handler.Form.ContainsFocus) + return; + + if (handler.Form.SelectNextControl(handler.Form.ActiveControl, true, true, true, true)) + return; + + if (Win32Helper.IsRunningOnMono) + return; + + // Since DockContent Form is not selectalbe, use Win32 SetFocus instead + NativeMethods.SetFocus(handler.Form.Handle); + } + + private List m_listContent = new List(); + private List ListContent + { + get { return m_listContent; } + } + public void AddToList(IDockContent content) + { + if (ListContent.Contains(content) || IsInActiveList(content)) + return; + + ListContent.Add(content); + } + + public void RemoveFromList(IDockContent content) + { + if (IsInActiveList(content)) + RemoveFromActiveList(content); + if (ListContent.Contains(content)) + ListContent.Remove(content); + } + + private IDockContent m_lastActiveContent = null; + private IDockContent LastActiveContent + { + get { return m_lastActiveContent; } + set { m_lastActiveContent = value; } + } + + private bool IsInActiveList(IDockContent content) + { + return !(content.DockHandler.NextActive == null && LastActiveContent != content); + } + + private void AddLastToActiveList(IDockContent content) + { + IDockContent last = LastActiveContent; + if (last == content) + return; + + DockContentHandler handler = content.DockHandler; + + if (IsInActiveList(content)) + RemoveFromActiveList(content); + + handler.PreviousActive = last; + handler.NextActive = null; + LastActiveContent = content; + if (last != null) + last.DockHandler.NextActive = LastActiveContent; + } + + private void RemoveFromActiveList(IDockContent content) + { + if (LastActiveContent == content) + LastActiveContent = content.DockHandler.PreviousActive; + + IDockContent prev = content.DockHandler.PreviousActive; + IDockContent next = content.DockHandler.NextActive; + if (prev != null) + prev.DockHandler.NextActive = next; + if (next != null) + next.DockHandler.PreviousActive = prev; + + content.DockHandler.PreviousActive = null; + content.DockHandler.NextActive = null; + } + + public void GiveUpFocus(IDockContent content) + { + DockContentHandler handler = content.DockHandler; + if (!handler.Form.ContainsFocus) + return; + + if (IsFocusTrackingSuspended) + DockPanel.DummyControl.Focus(); + + if (LastActiveContent == content) + { + IDockContent prev = handler.PreviousActive; + if (prev != null) + Activate(prev); + else if (ListContent.Count > 0) + Activate(ListContent[ListContent.Count - 1]); + } + else if (LastActiveContent != null) + Activate(LastActiveContent); + else if (ListContent.Count > 0) + Activate(ListContent[ListContent.Count - 1]); + } + + private static bool ContentContains(IDockContent content, IntPtr hWnd) + { + Control control = Control.FromChildHandle(hWnd); + for (Control parent = control; parent != null; parent = parent.Parent) + if (parent == content.DockHandler.Form) + return true; + + return false; + } + + private int m_countSuspendFocusTracking = 0; + public void SuspendFocusTracking() + { + m_countSuspendFocusTracking++; + if (!Win32Helper.IsRunningOnMono) + sm_localWindowsHook.HookInvoked -= m_hookEventHandler; + } + + public void ResumeFocusTracking() + { + if (m_countSuspendFocusTracking > 0) + m_countSuspendFocusTracking--; + + if (m_countSuspendFocusTracking == 0) + { + if (ContentActivating != null) + { + Activate(ContentActivating); + ContentActivating = null; + } + + if (!Win32Helper.IsRunningOnMono) + sm_localWindowsHook.HookInvoked += m_hookEventHandler; + + if (!InRefreshActiveWindow) + RefreshActiveWindow(); + } + } + + public bool IsFocusTrackingSuspended + { + get { return m_countSuspendFocusTracking != 0; } + } + + // Windows hook event handler + private void HookEventHandler(object sender, HookEventArgs e) + { + Win32.Msgs msg = (Win32.Msgs)Marshal.ReadInt32(e.lParam, IntPtr.Size * 3); + + if (msg == Win32.Msgs.WM_KILLFOCUS) + { + IntPtr wParam = Marshal.ReadIntPtr(e.lParam, IntPtr.Size * 2); + DockPane pane = GetPaneFromHandle(wParam); + if (pane == null) + RefreshActiveWindow(); + } + else if (msg == Win32.Msgs.WM_SETFOCUS) + RefreshActiveWindow(); + } + + private DockPane GetPaneFromHandle(IntPtr hWnd) + { + Control control = Control.FromChildHandle(hWnd); + + IDockContent content = null; + DockPane pane = null; + for (; control != null; control = control.Parent) + { + content = control as IDockContent; + if (content != null) + content.DockHandler.ActiveWindowHandle = hWnd; + + if (content != null && content.DockHandler.DockPanel == DockPanel) + return content.DockHandler.Pane; + + pane = control as DockPane; + if (pane != null && pane.DockPanel == DockPanel) + break; + } + + return pane; + } + + private bool m_inRefreshActiveWindow = false; + private bool InRefreshActiveWindow + { + get { return m_inRefreshActiveWindow; } + } + + private void RefreshActiveWindow() + { + SuspendFocusTracking(); + m_inRefreshActiveWindow = true; + + DockPane oldActivePane = ActivePane; + IDockContent oldActiveContent = ActiveContent; + IDockContent oldActiveDocument = ActiveDocument; + + SetActivePane(); + SetActiveContent(); + SetActiveDocumentPane(); + SetActiveDocument(); + DockPanel.AutoHideWindow.RefreshActivePane(); + + ResumeFocusTracking(); + m_inRefreshActiveWindow = false; + + if (oldActiveContent != ActiveContent) + DockPanel.OnActiveContentChanged(EventArgs.Empty); + if (oldActiveDocument != ActiveDocument) + DockPanel.OnActiveDocumentChanged(EventArgs.Empty); + if (oldActivePane != ActivePane) + DockPanel.OnActivePaneChanged(EventArgs.Empty); + } + + private DockPane m_activePane = null; + public DockPane ActivePane + { + get { return m_activePane; } + } + + private void SetActivePane() + { + DockPane value = Win32Helper.IsRunningOnMono ? null : GetPaneFromHandle(NativeMethods.GetFocus()); + if (m_activePane == value) + return; + + if (m_activePane != null) + m_activePane.SetIsActivated(false); + + m_activePane = value; + + if (m_activePane != null) + m_activePane.SetIsActivated(true); + } + + private IDockContent m_activeContent = null; + public IDockContent ActiveContent + { + get { return m_activeContent; } + } + + internal void SetActiveContent() + { + IDockContent value = ActivePane == null ? null : ActivePane.ActiveContent; + + if (m_activeContent == value) + return; + + if (m_activeContent != null) + m_activeContent.DockHandler.IsActivated = false; + + m_activeContent = value; + + if (m_activeContent != null) + { + m_activeContent.DockHandler.IsActivated = true; + if (!DockHelper.IsDockStateAutoHide((m_activeContent.DockHandler.DockState))) + AddLastToActiveList(m_activeContent); + } + } + + private DockPane m_activeDocumentPane = null; + public DockPane ActiveDocumentPane + { + get { return m_activeDocumentPane; } + } + + private void SetActiveDocumentPane() + { + DockPane value = null; + + if (ActivePane != null && ActivePane.DockState == DockState.Document) + value = ActivePane; + + if (value == null && DockPanel.DockWindows != null) + { + if (ActiveDocumentPane == null) + value = DockPanel.DockWindows[DockState.Document].DefaultPane; + else if (ActiveDocumentPane.DockPanel != DockPanel || ActiveDocumentPane.DockState != DockState.Document) + value = DockPanel.DockWindows[DockState.Document].DefaultPane; + else + value = ActiveDocumentPane; + } + + if (m_activeDocumentPane == value) + return; + + if (m_activeDocumentPane != null) + m_activeDocumentPane.SetIsActiveDocumentPane(false); + + m_activeDocumentPane = value; + + if (m_activeDocumentPane != null) + m_activeDocumentPane.SetIsActiveDocumentPane(true); + } + + private IDockContent m_activeDocument = null; + public IDockContent ActiveDocument + { + get { return m_activeDocument; } + } + + private void SetActiveDocument() + { + IDockContent value = ActiveDocumentPane == null ? null : ActiveDocumentPane.ActiveContent; + + if (m_activeDocument == value) + return; + + m_activeDocument = value; + } + } + + private IFocusManager FocusManager + { + get { return m_focusManager; } + } + + internal IContentFocusManager ContentFocusManager + { + get { return m_focusManager; } + } + + internal void SaveFocus() + { + DummyControl.Focus(); + } + + [Browsable(false)] + public IDockContent ActiveContent + { + get { return FocusManager.ActiveContent; } + } + + [Browsable(false)] + public DockPane ActivePane + { + get { return FocusManager.ActivePane; } + } + + [Browsable(false)] + public IDockContent ActiveDocument + { + get { return FocusManager.ActiveDocument; } + } + + [Browsable(false)] + public DockPane ActiveDocumentPane + { + get { return FocusManager.ActiveDocumentPane; } + } + + private static readonly object ActiveDocumentChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("DockPanel_ActiveDocumentChanged_Description")] + public event EventHandler ActiveDocumentChanged + { + add { Events.AddHandler(ActiveDocumentChangedEvent, value); } + remove { Events.RemoveHandler(ActiveDocumentChangedEvent, value); } + } + protected virtual void OnActiveDocumentChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActiveDocumentChangedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object ActiveContentChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("DockPanel_ActiveContentChanged_Description")] + public event EventHandler ActiveContentChanged + { + add { Events.AddHandler(ActiveContentChangedEvent, value); } + remove { Events.RemoveHandler(ActiveContentChangedEvent, value); } + } + protected void OnActiveContentChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object ActivePaneChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("DockPanel_ActivePaneChanged_Description")] + public event EventHandler ActivePaneChanged + { + add { Events.AddHandler(ActivePaneChangedEvent, value); } + remove { Events.RemoveHandler(ActivePaneChangedEvent, value); } + } + protected virtual void OnActivePaneChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActivePaneChangedEvent]; + if (handler != null) + handler(this, e); + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.MdiClientController.cs b/WinFormsUI/Docking/DockPanel.MdiClientController.cs new file mode 100644 index 0000000000..196b724224 --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.MdiClientController.cs @@ -0,0 +1,438 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPanel + { + // This class comes from Jacob Slusser's MdiClientController class: + // http://www.codeproject.com/cs/miscctrl/mdiclientcontroller.asp + private class MdiClientController : NativeWindow, IComponent, IDisposable + { + private bool m_autoScroll = true; + private BorderStyle m_borderStyle = BorderStyle.Fixed3D; + private MdiClient m_mdiClient = null; + private Form m_parentForm = null; + private ISite m_site = null; + + public MdiClientController() + { + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (Site != null && Site.Container != null) + Site.Container.Remove(this); + + if (Disposed != null) + Disposed(this, EventArgs.Empty); + } + } + + public bool AutoScroll + { + get { return m_autoScroll; } + set + { + // By default the MdiClient control scrolls. It can appear though that + // there are no scrollbars by turning them off when the non-client + // area is calculated. I decided to expose this method following + // the .NET vernacular of an AutoScroll property. + m_autoScroll = value; + if (MdiClient != null) + UpdateStyles(); + } + } + + public BorderStyle BorderStyle + { + set + { + // Error-check the enum. + if (!Enum.IsDefined(typeof(BorderStyle), value)) + throw new InvalidEnumArgumentException(); + + m_borderStyle = value; + + if (MdiClient == null) + return; + + // This property can actually be visible in design-mode, + // but to keep it consistent with the others, + // prevent this from being show at design-time. + if (Site != null && Site.DesignMode) + return; + + // There is no BorderStyle property exposed by the MdiClient class, + // but this can be controlled by Win32 functions. A Win32 ExStyle + // of WS_EX_CLIENTEDGE is equivalent to a Fixed3D border and a + // Style of WS_BORDER is equivalent to a FixedSingle border. + + // This code is inspired Jason Dori's article: + // "Adding designable borders to user controls". + // http://www.codeproject.com/cs/miscctrl/CsAddingBorders.asp + + if (!Win32Helper.IsRunningOnMono) + { + // Get styles using Win32 calls + int style = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE); + int exStyle = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE); + + // Add or remove style flags as necessary. + switch (m_borderStyle) + { + case BorderStyle.Fixed3D: + exStyle |= (int)Win32.WindowExStyles.WS_EX_CLIENTEDGE; + style &= ~((int)Win32.WindowStyles.WS_BORDER); + break; + + case BorderStyle.FixedSingle: + exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE); + style |= (int)Win32.WindowStyles.WS_BORDER; + break; + + case BorderStyle.None: + style &= ~((int)Win32.WindowStyles.WS_BORDER); + exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE); + break; + } + + // Set the styles using Win32 calls + NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE, style); + NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, exStyle); + } + + // Cause an update of the non-client area. + UpdateStyles(); + } + } + + public MdiClient MdiClient + { + get { return m_mdiClient; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Form ParentForm + { + get { return m_parentForm; } + set + { + // If the ParentForm has previously been set, + // unwire events connected to the old parent. + if (m_parentForm != null) + { + m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated); + m_parentForm.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate); + } + + m_parentForm = value; + + if (m_parentForm == null) + return; + + // If the parent form has not been created yet, + // wait to initialize the MDI client until it is. + if (m_parentForm.IsHandleCreated) + { + InitializeMdiClient(); + RefreshProperties(); + } + else + m_parentForm.HandleCreated += new EventHandler(ParentFormHandleCreated); + + m_parentForm.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate); + } + } + + public ISite Site + { + get { return m_site; } + set + { + m_site = value; + + if (m_site == null) + return; + + // If the component is dropped onto a form during design-time, + // set the ParentForm property. + IDesignerHost host = (value.GetService(typeof(IDesignerHost)) as IDesignerHost); + if (host != null) + { + Form parent = host.RootComponent as Form; + if (parent != null) + ParentForm = parent; + } + } + } + + public void RenewMdiClient() + { + // Reinitialize the MdiClient and its properties. + InitializeMdiClient(); + RefreshProperties(); + } + + public event EventHandler Disposed; + + public event EventHandler HandleAssigned; + + public event EventHandler MdiChildActivate; + + public event LayoutEventHandler Layout; + + protected virtual void OnHandleAssigned(EventArgs e) + { + // Raise the HandleAssigned event. + if (HandleAssigned != null) + HandleAssigned(this, e); + } + + protected virtual void OnMdiChildActivate(EventArgs e) + { + // Raise the MdiChildActivate event + if (MdiChildActivate != null) + MdiChildActivate(this, e); + } + + protected virtual void OnLayout(LayoutEventArgs e) + { + // Raise the Layout event + if (Layout != null) + Layout(this, e); + } + + public event PaintEventHandler Paint; + + protected virtual void OnPaint(PaintEventArgs e) + { + // Raise the Paint event. + if (Paint != null) + Paint(this, e); + } + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case (int)Win32.Msgs.WM_NCCALCSIZE: + // If AutoScroll is set to false, hide the scrollbars when the control + // calculates its non-client area. + if (!AutoScroll) + { + if (!Win32Helper.IsRunningOnMono) + { + NativeMethods.ShowScrollBar(m.HWnd, (int)Win32.ScrollBars.SB_BOTH, 0 /*false*/); + } + } + + break; + } + + base.WndProc(ref m); + } + + private void ParentFormHandleCreated(object sender, EventArgs e) + { + // The form has been created, unwire the event, and initialize the MdiClient. + this.m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated); + InitializeMdiClient(); + RefreshProperties(); + } + + private void ParentFormMdiChildActivate(object sender, EventArgs e) + { + OnMdiChildActivate(e); + } + + private void MdiClientLayout(object sender, LayoutEventArgs e) + { + OnLayout(e); + } + + private void MdiClientHandleDestroyed(object sender, EventArgs e) + { + // If the MdiClient handle has been released, drop the reference and + // release the handle. + if (m_mdiClient != null) + { + m_mdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed); + m_mdiClient = null; + } + + ReleaseHandle(); + } + + private void InitializeMdiClient() + { + // If the mdiClient has previously been set, unwire events connected + // to the old MDI. + if (MdiClient != null) + { + MdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed); + MdiClient.Layout -= new LayoutEventHandler(MdiClientLayout); + } + + if (ParentForm == null) + return; + + // Get the MdiClient from the parent form. + foreach (Control control in ParentForm.Controls) + { + // If the form is an MDI container, it will contain an MdiClient control + // just as it would any other control. + + m_mdiClient = control as MdiClient; + if (m_mdiClient == null) + continue; + + // Assign the MdiClient Handle to the NativeWindow. + ReleaseHandle(); + AssignHandle(MdiClient.Handle); + + // Raise the HandleAssigned event. + OnHandleAssigned(EventArgs.Empty); + + // Monitor the MdiClient for when its handle is destroyed. + MdiClient.HandleDestroyed += new EventHandler(MdiClientHandleDestroyed); + MdiClient.Layout += new LayoutEventHandler(MdiClientLayout); + + break; + } + } + + private void RefreshProperties() + { + // Refresh all the properties + BorderStyle = m_borderStyle; + AutoScroll = m_autoScroll; + } + + private void UpdateStyles() + { + // To show style changes, the non-client area must be repainted. Using the + // control's Invalidate method does not affect the non-client area. + // Instead use a Win32 call to signal the style has changed. + if (!Win32Helper.IsRunningOnMono) + NativeMethods.SetWindowPos(MdiClient.Handle, IntPtr.Zero, 0, 0, 0, 0, + Win32.FlagsSetWindowPos.SWP_NOACTIVATE | + Win32.FlagsSetWindowPos.SWP_NOMOVE | + Win32.FlagsSetWindowPos.SWP_NOSIZE | + Win32.FlagsSetWindowPos.SWP_NOZORDER | + Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER | + Win32.FlagsSetWindowPos.SWP_FRAMECHANGED); + } + } + + private MdiClientController m_mdiClientController = null; + private MdiClientController GetMdiClientController() + { + if (m_mdiClientController == null) + { + m_mdiClientController = new MdiClientController(); + m_mdiClientController.HandleAssigned += new EventHandler(MdiClientHandleAssigned); + m_mdiClientController.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate); + m_mdiClientController.Layout += new LayoutEventHandler(MdiClient_Layout); + } + + return m_mdiClientController; + } + + private void ParentFormMdiChildActivate(object sender, EventArgs e) + { + if (GetMdiClientController().ParentForm == null) + return; + + IDockContent content = GetMdiClientController().ParentForm.ActiveMdiChild as IDockContent; + if (content == null) + return; + + if (content.DockHandler.DockPanel == this && content.DockHandler.Pane != null) + content.DockHandler.Pane.ActiveContent = content; + } + + private bool MdiClientExists + { + get { return GetMdiClientController().MdiClient != null; } + } + + private void SetMdiClientBounds(Rectangle bounds) + { + GetMdiClientController().MdiClient.Bounds = bounds; + } + + private void SuspendMdiClientLayout() + { + if (GetMdiClientController().MdiClient != null) + GetMdiClientController().MdiClient.SuspendLayout(); + } + + private void ResumeMdiClientLayout(bool perform) + { + if (GetMdiClientController().MdiClient != null) + GetMdiClientController().MdiClient.ResumeLayout(perform); + } + + private void PerformMdiClientLayout() + { + if (GetMdiClientController().MdiClient != null) + GetMdiClientController().MdiClient.PerformLayout(); + } + + // Called when: + // 1. DockPanel.DocumentStyle changed + // 2. DockPanel.Visible changed + // 3. MdiClientController.Handle assigned + private void SetMdiClient() + { + MdiClientController controller = GetMdiClientController(); + + if (this.DocumentStyle == DocumentStyle.DockingMdi) + { + controller.AutoScroll = false; + controller.BorderStyle = BorderStyle.None; + if (MdiClientExists) + controller.MdiClient.Dock = DockStyle.Fill; + } + else if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow) + { + controller.AutoScroll = true; + controller.BorderStyle = BorderStyle.Fixed3D; + if (MdiClientExists) + controller.MdiClient.Dock = DockStyle.Fill; + } + else if (this.DocumentStyle == DocumentStyle.SystemMdi) + { + controller.AutoScroll = true; + controller.BorderStyle = BorderStyle.Fixed3D; + if (controller.MdiClient != null) + { + controller.MdiClient.Dock = DockStyle.None; + controller.MdiClient.Bounds = SystemMdiClientBounds; + } + } + } + + internal Rectangle RectangleToMdiClient(Rectangle rect) + { + if (MdiClientExists) + return GetMdiClientController().MdiClient.RectangleToClient(rect); + else + return Rectangle.Empty; + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.Persistor.cs b/WinFormsUI/Docking/DockPanel.Persistor.cs new file mode 100644 index 0000000000..06780c2962 --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.Persistor.cs @@ -0,0 +1,801 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; +using System.Drawing; +using WeifenLuo.WinFormsUI.Docking; +using System.IO; +using System.Text; +using System.Xml; +using System.Globalization; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPanel + { + private static class Persistor + { + private const string ConfigFileVersion = "1.0"; + private static string[] CompatibleConfigFileVersions = new string[] { }; + + private class DummyContent : DockContent + { + } + + private struct DockPanelStruct + { + private double m_dockLeftPortion; + public double DockLeftPortion + { + get { return m_dockLeftPortion; } + set { m_dockLeftPortion = value; } + } + + private double m_dockRightPortion; + public double DockRightPortion + { + get { return m_dockRightPortion; } + set { m_dockRightPortion = value; } + } + + private double m_dockTopPortion; + public double DockTopPortion + { + get { return m_dockTopPortion; } + set { m_dockTopPortion = value; } + } + + private double m_dockBottomPortion; + public double DockBottomPortion + { + get { return m_dockBottomPortion; } + set { m_dockBottomPortion = value; } + } + + private int m_indexActiveDocumentPane; + public int IndexActiveDocumentPane + { + get { return m_indexActiveDocumentPane; } + set { m_indexActiveDocumentPane = value; } + } + + private int m_indexActivePane; + public int IndexActivePane + { + get { return m_indexActivePane; } + set { m_indexActivePane = value; } + } + } + + private struct ContentStruct + { + private string m_persistString; + public string PersistString + { + get { return m_persistString; } + set { m_persistString = value; } + } + + private double m_autoHidePortion; + public double AutoHidePortion + { + get { return m_autoHidePortion; } + set { m_autoHidePortion = value; } + } + + private bool m_isHidden; + public bool IsHidden + { + get { return m_isHidden; } + set { m_isHidden = value; } + } + + private bool m_isFloat; + public bool IsFloat + { + get { return m_isFloat; } + set { m_isFloat = value; } + } + } + + private struct PaneStruct + { + private DockState m_dockState; + public DockState DockState + { + get { return m_dockState; } + set { m_dockState = value; } + } + + private int m_indexActiveContent; + public int IndexActiveContent + { + get { return m_indexActiveContent; } + set { m_indexActiveContent = value; } + } + + private int[] m_indexContents; + public int[] IndexContents + { + get { return m_indexContents; } + set { m_indexContents = value; } + } + + private int m_zOrderIndex; + public int ZOrderIndex + { + get { return m_zOrderIndex; } + set { m_zOrderIndex = value; } + } + } + + private struct NestedPane + { + private int m_indexPane; + public int IndexPane + { + get { return m_indexPane; } + set { m_indexPane = value; } + } + + private int m_indexPrevPane; + public int IndexPrevPane + { + get { return m_indexPrevPane; } + set { m_indexPrevPane = value; } + } + + private DockAlignment m_alignment; + public DockAlignment Alignment + { + get { return m_alignment; } + set { m_alignment = value; } + } + + private double m_proportion; + public double Proportion + { + get { return m_proportion; } + set { m_proportion = value; } + } + } + + private struct DockWindowStruct + { + private DockState m_dockState; + public DockState DockState + { + get { return m_dockState; } + set { m_dockState = value; } + } + + private int m_zOrderIndex; + public int ZOrderIndex + { + get { return m_zOrderIndex; } + set { m_zOrderIndex = value; } + } + + private NestedPane[] m_nestedPanes; + public NestedPane[] NestedPanes + { + get { return m_nestedPanes; } + set { m_nestedPanes = value; } + } + } + + private struct FloatWindowStruct + { + private Rectangle m_bounds; + public Rectangle Bounds + { + get { return m_bounds; } + set { m_bounds = value; } + } + + private int m_zOrderIndex; + public int ZOrderIndex + { + get { return m_zOrderIndex; } + set { m_zOrderIndex = value; } + } + + private NestedPane[] m_nestedPanes; + public NestedPane[] NestedPanes + { + get { return m_nestedPanes; } + set { m_nestedPanes = value; } + } + + private bool m_maximized; + public bool Maximized + { + get { return m_maximized; } + set { m_maximized = value; } + } + } + + public static void SaveAsXml(DockPanel dockPanel, string fileName, string userString) + { + SaveAsXml(dockPanel, fileName, userString, Encoding.Unicode); + } + + public static void SaveAsXml(DockPanel dockPanel, string fileName, string userString, Encoding encoding) + { + FileStream fs = new FileStream(fileName, FileMode.Create); + try + { + SaveAsXml(dockPanel, fs, userString, encoding); + } + finally + { + fs.Close(); + } + } + + public static void SaveAsXml(DockPanel dockPanel, Stream stream, string userString, Encoding encoding) + { + SaveAsXml(dockPanel, stream, userString, encoding, false); + } + + public static void SaveAsXml(DockPanel dockPanel, Stream stream, string userString, Encoding encoding, bool upstream) + { + XmlTextWriter xmlOut = new XmlTextWriter(stream, encoding); + + // Use indenting for readability + xmlOut.Formatting = Formatting.Indented; + + if (!upstream) + xmlOut.WriteStartDocument(); + + // Always begin file with identification and warning + xmlOut.WriteComment(Strings.DockPanel_Persistor_XmlFileComment1); + xmlOut.WriteComment(Strings.DockPanel_Persistor_XmlFileComment2); + + // Associate a version number with the root element so that future version of the code + // will be able to be backwards compatible or at least recognise out of date versions + xmlOut.WriteStartElement("DockPanel"); + xmlOut.WriteAttributeString("FormatVersion", ConfigFileVersion); + xmlOut.WriteAttributeString("DockLeftPortion", dockPanel.DockLeftPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockRightPortion", dockPanel.DockRightPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockTopPortion", dockPanel.DockTopPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockBottomPortion", dockPanel.DockBottomPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("UserString", userString); + + if (!Win32Helper.IsRunningOnMono) + { + xmlOut.WriteAttributeString("ActiveDocumentPane", dockPanel.Panes.IndexOf(dockPanel.ActiveDocumentPane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("ActivePane", dockPanel.Panes.IndexOf(dockPanel.ActivePane).ToString(CultureInfo.InvariantCulture)); + } + + // Contents + xmlOut.WriteStartElement("Contents"); + xmlOut.WriteAttributeString("Count", dockPanel.Contents.Count.ToString(CultureInfo.InvariantCulture)); + foreach (IDockContent content in dockPanel.Contents) + { + xmlOut.WriteStartElement("Content"); + xmlOut.WriteAttributeString("ID", dockPanel.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("PersistString", content.DockHandler.PersistString); + xmlOut.WriteAttributeString("AutoHidePortion", content.DockHandler.AutoHidePortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("IsHidden", content.DockHandler.IsHidden.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("IsFloat", content.DockHandler.IsFloat.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + + // Panes + xmlOut.WriteStartElement("Panes"); + xmlOut.WriteAttributeString("Count", dockPanel.Panes.Count.ToString(CultureInfo.InvariantCulture)); + foreach (DockPane pane in dockPanel.Panes) + { + xmlOut.WriteStartElement("Pane"); + xmlOut.WriteAttributeString("ID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockState", pane.DockState.ToString()); + xmlOut.WriteAttributeString("ActiveContent", dockPanel.Contents.IndexOf(pane.ActiveContent).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteStartElement("Contents"); + xmlOut.WriteAttributeString("Count", pane.Contents.Count.ToString(CultureInfo.InvariantCulture)); + foreach (IDockContent content in pane.Contents) + { + xmlOut.WriteStartElement("Content"); + xmlOut.WriteAttributeString("ID", pane.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("RefID", dockPanel.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + + // DockWindows + xmlOut.WriteStartElement("DockWindows"); + int dockWindowId = 0; + foreach (DockWindow dw in dockPanel.DockWindows) + { + xmlOut.WriteStartElement("DockWindow"); + xmlOut.WriteAttributeString("ID", dockWindowId.ToString(CultureInfo.InvariantCulture)); + dockWindowId++; + xmlOut.WriteAttributeString("DockState", dw.DockState.ToString()); + xmlOut.WriteAttributeString("ZOrderIndex", dockPanel.Controls.IndexOf(dw).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteStartElement("NestedPanes"); + xmlOut.WriteAttributeString("Count", dw.NestedPanes.Count.ToString(CultureInfo.InvariantCulture)); + foreach (DockPane pane in dw.NestedPanes) + { + xmlOut.WriteStartElement("Pane"); + xmlOut.WriteAttributeString("ID", dw.NestedPanes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("RefID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + NestedDockingStatus status = pane.NestedDockingStatus; + xmlOut.WriteAttributeString("PrevPane", dockPanel.Panes.IndexOf(status.PreviousPane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Alignment", status.Alignment.ToString()); + xmlOut.WriteAttributeString("Proportion", status.Proportion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + + // FloatWindows + RectangleConverter rectConverter = new RectangleConverter(); + xmlOut.WriteStartElement("FloatWindows"); + xmlOut.WriteAttributeString("Count", dockPanel.FloatWindows.Count.ToString(CultureInfo.InvariantCulture)); + foreach (FloatWindow fw in dockPanel.FloatWindows) + { + xmlOut.WriteStartElement("FloatWindow"); + xmlOut.WriteAttributeString("ID", dockPanel.FloatWindows.IndexOf(fw).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Bounds", rectConverter.ConvertToInvariantString(fw.Bounds)); + xmlOut.WriteAttributeString("ZOrderIndex", fw.DockPanel.FloatWindows.IndexOf(fw).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Maximized", (fw.WindowState == FormWindowState.Maximized).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteStartElement("NestedPanes"); + xmlOut.WriteAttributeString("Count", fw.NestedPanes.Count.ToString(CultureInfo.InvariantCulture)); + foreach (DockPane pane in fw.NestedPanes) + { + xmlOut.WriteStartElement("Pane"); + xmlOut.WriteAttributeString("ID", fw.NestedPanes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("RefID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + NestedDockingStatus status = pane.NestedDockingStatus; + xmlOut.WriteAttributeString("PrevPane", dockPanel.Panes.IndexOf(status.PreviousPane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Alignment", status.Alignment.ToString()); + xmlOut.WriteAttributeString("Proportion", status.Proportion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); // + + xmlOut.WriteEndElement(); + + if (!upstream) + { + xmlOut.WriteEndDocument(); + xmlOut.Close(); + } + else + xmlOut.Flush(); + } + + public static void LoadFromXml(DockPanel dockPanel, string fileName, DeserializeDockContent deserializeContent) + { + FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); + try + { + LoadFromXml(dockPanel, fs, deserializeContent); + } + finally + { + fs.Close(); + } + } + + public static void LoadFromXml(DockPanel dockPanel, Stream stream, DeserializeDockContent deserializeContent) + { + LoadFromXml(dockPanel, stream, deserializeContent, true); + } + + private static ContentStruct[] LoadContents(XmlTextReader xmlIn) + { + int countOfContents = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + ContentStruct[] contents = new ContentStruct[countOfContents]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfContents; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Content" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + contents[i].PersistString = xmlIn.GetAttribute("PersistString"); + contents[i].AutoHidePortion = Convert.ToDouble(xmlIn.GetAttribute("AutoHidePortion"), CultureInfo.InvariantCulture); + contents[i].IsHidden = Convert.ToBoolean(xmlIn.GetAttribute("IsHidden"), CultureInfo.InvariantCulture); + contents[i].IsFloat = Convert.ToBoolean(xmlIn.GetAttribute("IsFloat"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + + return contents; + } + + private static PaneStruct[] LoadPanes(XmlTextReader xmlIn) + { + EnumConverter dockStateConverter = new EnumConverter(typeof(DockState)); + int countOfPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + PaneStruct[] panes = new PaneStruct[countOfPanes]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfPanes; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Pane" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + panes[i].DockState = (DockState)dockStateConverter.ConvertFrom(xmlIn.GetAttribute("DockState")); + panes[i].IndexActiveContent = Convert.ToInt32(xmlIn.GetAttribute("ActiveContent"), CultureInfo.InvariantCulture); + panes[i].ZOrderIndex = -1; + + MoveToNextElement(xmlIn); + if (xmlIn.Name != "Contents") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + int countOfPaneContents = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + panes[i].IndexContents = new int[countOfPaneContents]; + MoveToNextElement(xmlIn); + for (int j = 0; j < countOfPaneContents; j++) + { + int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Content" || id2 != j) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + panes[i].IndexContents[j] = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + } + + return panes; + } + + private static DockWindowStruct[] LoadDockWindows(XmlTextReader xmlIn, DockPanel dockPanel) + { + EnumConverter dockStateConverter = new EnumConverter(typeof(DockState)); + EnumConverter dockAlignmentConverter = new EnumConverter(typeof(DockAlignment)); + int countOfDockWindows = dockPanel.DockWindows.Count; + DockWindowStruct[] dockWindows = new DockWindowStruct[countOfDockWindows]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfDockWindows; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "DockWindow" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + dockWindows[i].DockState = (DockState)dockStateConverter.ConvertFrom(xmlIn.GetAttribute("DockState")); + dockWindows[i].ZOrderIndex = Convert.ToInt32(xmlIn.GetAttribute("ZOrderIndex"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + if (xmlIn.Name != "DockList" && xmlIn.Name != "NestedPanes") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + int countOfNestedPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + dockWindows[i].NestedPanes = new NestedPane[countOfNestedPanes]; + MoveToNextElement(xmlIn); + for (int j = 0; j < countOfNestedPanes; j++) + { + int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Pane" || id2 != j) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + dockWindows[i].NestedPanes[j].IndexPane = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture); + dockWindows[i].NestedPanes[j].IndexPrevPane = Convert.ToInt32(xmlIn.GetAttribute("PrevPane"), CultureInfo.InvariantCulture); + dockWindows[i].NestedPanes[j].Alignment = (DockAlignment)dockAlignmentConverter.ConvertFrom(xmlIn.GetAttribute("Alignment")); + dockWindows[i].NestedPanes[j].Proportion = Convert.ToDouble(xmlIn.GetAttribute("Proportion"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + } + + return dockWindows; + } + + private static FloatWindowStruct[] LoadFloatWindows(XmlTextReader xmlIn) + { + EnumConverter dockAlignmentConverter = new EnumConverter(typeof(DockAlignment)); + RectangleConverter rectConverter = new RectangleConverter(); + int countOfFloatWindows = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + FloatWindowStruct[] floatWindows = new FloatWindowStruct[countOfFloatWindows]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfFloatWindows; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "FloatWindow" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + floatWindows[i].Bounds = (Rectangle)rectConverter.ConvertFromInvariantString(xmlIn.GetAttribute("Bounds")); + floatWindows[i].Maximized = Convert.ToBoolean(xmlIn.GetAttribute("Maximized"), CultureInfo.InvariantCulture); + floatWindows[i].ZOrderIndex = Convert.ToInt32(xmlIn.GetAttribute("ZOrderIndex"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + if (xmlIn.Name != "DockList" && xmlIn.Name != "NestedPanes") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + int countOfNestedPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + floatWindows[i].NestedPanes = new NestedPane[countOfNestedPanes]; + MoveToNextElement(xmlIn); + for (int j = 0; j < countOfNestedPanes; j++) + { + int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Pane" || id2 != j) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + floatWindows[i].NestedPanes[j].IndexPane = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture); + floatWindows[i].NestedPanes[j].IndexPrevPane = Convert.ToInt32(xmlIn.GetAttribute("PrevPane"), CultureInfo.InvariantCulture); + floatWindows[i].NestedPanes[j].Alignment = (DockAlignment)dockAlignmentConverter.ConvertFrom(xmlIn.GetAttribute("Alignment")); + floatWindows[i].NestedPanes[j].Proportion = Convert.ToDouble(xmlIn.GetAttribute("Proportion"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + } + + return floatWindows; + } + + public static void LoadFromXml(DockPanel dockPanel, Stream stream, DeserializeDockContent deserializeContent, bool closeStream) + { + + if (dockPanel.Contents.Count != 0) + throw new InvalidOperationException(Strings.DockPanel_LoadFromXml_AlreadyInitialized); + + XmlTextReader xmlIn = new XmlTextReader(stream); + xmlIn.WhitespaceHandling = WhitespaceHandling.None; + xmlIn.MoveToContent(); + + while (!xmlIn.Name.Equals("DockPanel")) + { + if (!MoveToNextElement(xmlIn)) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + } + + string formatVersion = xmlIn.GetAttribute("FormatVersion"); + if (!IsFormatVersionValid(formatVersion)) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidFormatVersion); + + string userString = xmlIn.GetAttribute("UserString"); + deserializeContent(userString); + + DockPanelStruct dockPanelStruct = new DockPanelStruct(); + dockPanelStruct.DockLeftPortion = Convert.ToDouble(xmlIn.GetAttribute("DockLeftPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.DockRightPortion = Convert.ToDouble(xmlIn.GetAttribute("DockRightPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.DockTopPortion = Convert.ToDouble(xmlIn.GetAttribute("DockTopPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.DockBottomPortion = Convert.ToDouble(xmlIn.GetAttribute("DockBottomPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.IndexActiveDocumentPane = Convert.ToInt32(xmlIn.GetAttribute("ActiveDocumentPane"), CultureInfo.InvariantCulture); + dockPanelStruct.IndexActivePane = Convert.ToInt32(xmlIn.GetAttribute("ActivePane"), CultureInfo.InvariantCulture); + + // Load Contents + MoveToNextElement(xmlIn); + if (xmlIn.Name != "Contents") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + ContentStruct[] contents = LoadContents(xmlIn); + + // Load Panes + if (xmlIn.Name != "Panes") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + PaneStruct[] panes = LoadPanes(xmlIn); + + // Load DockWindows + if (xmlIn.Name != "DockWindows") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + DockWindowStruct[] dockWindows = LoadDockWindows(xmlIn, dockPanel); + + // Load FloatWindows + if (xmlIn.Name != "FloatWindows") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + FloatWindowStruct[] floatWindows = LoadFloatWindows(xmlIn); + + if (closeStream) + xmlIn.Close(); + + dockPanel.SuspendLayout(true); + + dockPanel.DockLeftPortion = dockPanelStruct.DockLeftPortion; + dockPanel.DockRightPortion = dockPanelStruct.DockRightPortion; + dockPanel.DockTopPortion = dockPanelStruct.DockTopPortion; + dockPanel.DockBottomPortion = dockPanelStruct.DockBottomPortion; + + // Set DockWindow ZOrders + int prevMaxDockWindowZOrder = int.MaxValue; + for (int i = 0; i < dockWindows.Length; i++) + { + int maxDockWindowZOrder = -1; + int index = -1; + for (int j = 0; j < dockWindows.Length; j++) + { + if (dockWindows[j].ZOrderIndex > maxDockWindowZOrder && dockWindows[j].ZOrderIndex < prevMaxDockWindowZOrder) + { + maxDockWindowZOrder = dockWindows[j].ZOrderIndex; + index = j; + } + } + + dockPanel.DockWindows[dockWindows[index].DockState].BringToFront(); + prevMaxDockWindowZOrder = maxDockWindowZOrder; + } + + // Create Contents + for (int i = 0; i < contents.Length; i++) + { + IDockContent content = deserializeContent(contents[i].PersistString); + if (content == null) + content = new DummyContent(); + content.DockHandler.DockPanel = dockPanel; + content.DockHandler.AutoHidePortion = contents[i].AutoHidePortion; + content.DockHandler.IsHidden = true; + content.DockHandler.IsFloat = contents[i].IsFloat; + } + + // Create panes + for (int i = 0; i < panes.Length; i++) + { + DockPane pane = null; + for (int j = 0; j < panes[i].IndexContents.Length; j++) + { + IDockContent content = dockPanel.Contents[panes[i].IndexContents[j]]; + if (j == 0) + pane = dockPanel.DockPaneFactory.CreateDockPane(content, panes[i].DockState, false); + else if (panes[i].DockState == DockState.Float) + content.DockHandler.FloatPane = pane; + else + content.DockHandler.PanelPane = pane; + } + } + + // Assign Panes to DockWindows + for (int i = 0; i < dockWindows.Length; i++) + { + for (int j = 0; j < dockWindows[i].NestedPanes.Length; j++) + { + DockWindow dw = dockPanel.DockWindows[dockWindows[i].DockState]; + int indexPane = dockWindows[i].NestedPanes[j].IndexPane; + DockPane pane = dockPanel.Panes[indexPane]; + int indexPrevPane = dockWindows[i].NestedPanes[j].IndexPrevPane; + DockPane prevPane = (indexPrevPane == -1) ? dw.NestedPanes.GetDefaultPreviousPane(pane) : dockPanel.Panes[indexPrevPane]; + DockAlignment alignment = dockWindows[i].NestedPanes[j].Alignment; + double proportion = dockWindows[i].NestedPanes[j].Proportion; + pane.DockTo(dw, prevPane, alignment, proportion); + if (panes[indexPane].DockState == dw.DockState) + panes[indexPane].ZOrderIndex = dockWindows[i].ZOrderIndex; + } + } + + // Create float windows + for (int i = 0; i < floatWindows.Length; i++) + { + FloatWindow fw = null; + for (int j = 0; j < floatWindows[i].NestedPanes.Length; j++) + { + int indexPane = floatWindows[i].NestedPanes[j].IndexPane; + DockPane pane = dockPanel.Panes[indexPane]; + if (j == 0) + fw = dockPanel.FloatWindowFactory.CreateFloatWindow(dockPanel, pane, floatWindows[i].Bounds); + else + { + int indexPrevPane = floatWindows[i].NestedPanes[j].IndexPrevPane; + DockPane prevPane = indexPrevPane == -1 ? null : dockPanel.Panes[indexPrevPane]; + DockAlignment alignment = floatWindows[i].NestedPanes[j].Alignment; + double proportion = floatWindows[i].NestedPanes[j].Proportion; + pane.DockTo(fw, prevPane, alignment, proportion); + } + + if (floatWindows[i].Maximized) + fw.WindowState = FormWindowState.Maximized; + + if (panes[indexPane].DockState == fw.DockState) + panes[indexPane].ZOrderIndex = floatWindows[i].ZOrderIndex; + } + } + + // sort IDockContent by its Pane's ZOrder + int[] sortedContents = null; + if (contents.Length > 0) + { + sortedContents = new int[contents.Length]; + for (int i = 0; i < contents.Length; i++) + sortedContents[i] = i; + + int lastDocument = contents.Length; + for (int i = 0; i < contents.Length - 1; i++) + { + for (int j = i + 1; j < contents.Length; j++) + { + DockPane pane1 = dockPanel.Contents[sortedContents[i]].DockHandler.Pane; + int ZOrderIndex1 = pane1 == null ? 0 : panes[dockPanel.Panes.IndexOf(pane1)].ZOrderIndex; + DockPane pane2 = dockPanel.Contents[sortedContents[j]].DockHandler.Pane; + int ZOrderIndex2 = pane2 == null ? 0 : panes[dockPanel.Panes.IndexOf(pane2)].ZOrderIndex; + if (ZOrderIndex1 > ZOrderIndex2) + { + int temp = sortedContents[i]; + sortedContents[i] = sortedContents[j]; + sortedContents[j] = temp; + } + } + } + } + + // show non-document IDockContent first to avoid screen flickers + for (int i = 0; i < contents.Length; i++) + { + IDockContent content = dockPanel.Contents[sortedContents[i]]; + if (content.DockHandler.Pane != null && content.DockHandler.Pane.DockState != DockState.Document) + content.DockHandler.IsHidden = contents[sortedContents[i]].IsHidden; + } + + // after all non-document IDockContent, show document IDockContent + for (int i = 0; i < contents.Length; i++) + { + IDockContent content = dockPanel.Contents[sortedContents[i]]; + if (content.DockHandler.Pane != null && content.DockHandler.Pane.DockState == DockState.Document) + content.DockHandler.IsHidden = contents[sortedContents[i]].IsHidden; + } + + for (int i = 0; i < panes.Length; i++) + dockPanel.Panes[i].ActiveContent = panes[i].IndexActiveContent == -1 ? null : dockPanel.Contents[panes[i].IndexActiveContent]; + + if (dockPanelStruct.IndexActiveDocumentPane != -1) + dockPanel.Panes[dockPanelStruct.IndexActiveDocumentPane].Activate(); + + if (dockPanelStruct.IndexActivePane != -1) + dockPanel.Panes[dockPanelStruct.IndexActivePane].Activate(); + + for (int i = dockPanel.Contents.Count - 1; i >= 0; i--) + if (dockPanel.Contents[i] is DummyContent) + dockPanel.Contents[i].DockHandler.Form.Close(); + + dockPanel.ResumeLayout(true, true); + } + + private static bool MoveToNextElement(XmlTextReader xmlIn) + { + if (!xmlIn.Read()) + return false; + + while (xmlIn.NodeType == XmlNodeType.EndElement) + { + if (!xmlIn.Read()) + return false; + } + + return true; + } + + private static bool IsFormatVersionValid(string formatVersion) + { + if (formatVersion == ConfigFileVersion) + return true; + + foreach (string s in CompatibleConfigFileVersions) + if (s == formatVersion) + return true; + + return false; + } + } + + public void SaveAsXml(string fileName, string userString) + { + Persistor.SaveAsXml(this, fileName, userString); + } + + public void SaveAsXml(string fileName, string userString, Encoding encoding) + { + Persistor.SaveAsXml(this, fileName, userString, encoding); + } + + public void SaveAsXml(Stream stream, string userString, Encoding encoding) + { + Persistor.SaveAsXml(this, stream, userString, encoding); + } + + public void SaveAsXml(Stream stream, string userString, Encoding encoding, bool upstream) + { + Persistor.SaveAsXml(this, stream, userString, encoding, upstream); + } + + public void LoadFromXml(string fileName, DeserializeDockContent deserializeContent) + { + Persistor.LoadFromXml(this, fileName, deserializeContent); + } + + public void LoadFromXml(Stream stream, DeserializeDockContent deserializeContent) + { + Persistor.LoadFromXml(this, stream, deserializeContent); + } + + public void LoadFromXml(Stream stream, DeserializeDockContent deserializeContent, bool closeStream) + { + Persistor.LoadFromXml(this, stream, deserializeContent, closeStream); + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.SplitterDragHandler.cs b/WinFormsUI/Docking/DockPanel.SplitterDragHandler.cs new file mode 100644 index 0000000000..8689e166fd --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.SplitterDragHandler.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + partial class DockPanel + { + private sealed class SplitterDragHandler : DragHandler + { + private class SplitterOutline + { + public SplitterOutline() + { + m_dragForm = new DragForm(); + SetDragForm(Rectangle.Empty); + DragForm.BackColor = Color.Black; + DragForm.Opacity = 0.7; + DragForm.Show(false); + } + + DragForm m_dragForm; + private DragForm DragForm + { + get { return m_dragForm; } + } + + public void Show(Rectangle rect) + { + SetDragForm(rect); + } + + public void Close() + { + DragForm.Close(); + } + + private void SetDragForm(Rectangle rect) + { + DragForm.Bounds = rect; + if (rect == Rectangle.Empty) + DragForm.Region = new Region(Rectangle.Empty); + else if (DragForm.Region != null) + DragForm.Region = null; + } + } + + public SplitterDragHandler(DockPanel dockPanel) + : base(dockPanel) + { + } + + public new ISplitterDragSource DragSource + { + get { return base.DragSource as ISplitterDragSource; } + private set { base.DragSource = value; } + } + + private SplitterOutline m_outline; + private SplitterOutline Outline + { + get { return m_outline; } + set { m_outline = value; } + } + + private Rectangle m_rectSplitter; + private Rectangle RectSplitter + { + get { return m_rectSplitter; } + set { m_rectSplitter = value; } + } + + public void BeginDrag(ISplitterDragSource dragSource, Rectangle rectSplitter) + { + DragSource = dragSource; + RectSplitter = rectSplitter; + + if (!BeginDrag()) + { + DragSource = null; + return; + } + + Outline = new SplitterOutline(); + Outline.Show(rectSplitter); + DragSource.BeginDrag(rectSplitter); + } + + protected override void OnDragging() + { + Outline.Show(GetSplitterOutlineBounds(Control.MousePosition)); + } + + protected override void OnEndDrag(bool abort) + { + DockPanel.SuspendLayout(true); + + Outline.Close(); + + if (!abort) + DragSource.MoveSplitter(GetMovingOffset(Control.MousePosition)); + + DragSource.EndDrag(); + DockPanel.ResumeLayout(true, true); + } + + private int GetMovingOffset(Point ptMouse) + { + Rectangle rect = GetSplitterOutlineBounds(ptMouse); + if (DragSource.IsVertical) + return rect.X - RectSplitter.X; + else + return rect.Y - RectSplitter.Y; + } + + private Rectangle GetSplitterOutlineBounds(Point ptMouse) + { + Rectangle rectLimit = DragSource.DragLimitBounds; + + Rectangle rect = RectSplitter; + if (rectLimit.Width <= 0 || rectLimit.Height <= 0) + return rect; + + if (DragSource.IsVertical) + { + rect.X += ptMouse.X - StartMousePosition.X; + rect.Height = rectLimit.Height; + } + else + { + rect.Y += ptMouse.Y - StartMousePosition.Y; + rect.Width = rectLimit.Width; + } + + if (rect.Left < rectLimit.Left) + rect.X = rectLimit.X; + if (rect.Top < rectLimit.Top) + rect.Y = rectLimit.Y; + if (rect.Right > rectLimit.Right) + rect.X -= rect.Right - rectLimit.Right; + if (rect.Bottom > rectLimit.Bottom) + rect.Y -= rect.Bottom - rectLimit.Bottom; + + return rect; + } + } + + private SplitterDragHandler m_splitterDragHandler = null; + private SplitterDragHandler GetSplitterDragHandler() + { + if (m_splitterDragHandler == null) + m_splitterDragHandler = new SplitterDragHandler(this); + return m_splitterDragHandler; + } + + internal void BeginDrag(ISplitterDragSource dragSource, Rectangle rectSplitter) + { + GetSplitterDragHandler().BeginDrag(dragSource, rectSplitter); + } + } +} diff --git a/WinFormsUI/Docking/DockPanel.bmp b/WinFormsUI/Docking/DockPanel.bmp new file mode 100644 index 0000000000..10d6858f94 Binary files /dev/null and b/WinFormsUI/Docking/DockPanel.bmp differ diff --git a/WinFormsUI/Docking/DockPanel.cs b/WinFormsUI/Docking/DockPanel.cs new file mode 100644 index 0000000000..0e32476a87 --- /dev/null +++ b/WinFormsUI/Docking/DockPanel.cs @@ -0,0 +1,1121 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.IO; +using System.Text; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; + +// To simplify the process of finding the toolbox bitmap resource: +// #1 Create an internal class called "resfinder" outside of the root namespace. +// #2 Use "resfinder" in the toolbox bitmap attribute instead of the control name. +// #3 use the "." string to locate the resource. +// See: http://www.bobpowell.net/toolboxbitmap.htm +internal class resfinder +{ +} + +namespace WeifenLuo.WinFormsUI.Docking +{ + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "0#")] + public delegate IDockContent DeserializeDockContent(string persistString); + + [LocalizedDescription("DockPanel_Description")] + [Designer("System.Windows.Forms.Design.ControlDesigner, System.Design")] + [ToolboxBitmap(typeof(resfinder), "WeifenLuo.WinFormsUI.Docking.DockPanel.bmp")] + [DefaultProperty("DocumentStyle")] + [DefaultEvent("ActiveContentChanged")] + public partial class DockPanel : Panel + { + private readonly FocusManagerImpl m_focusManager; + private readonly DockPanelExtender m_extender; + private readonly DockPaneCollection m_panes; + private readonly FloatWindowCollection m_floatWindows; + private readonly AutoHideWindowControl m_autoHideWindow; + private readonly DockWindowCollection m_dockWindows; + private readonly DockContent m_dummyContent; + private readonly Control m_dummyControl; + + public DockPanel() + { + ShowAutoHideContentOnHover = true; + + m_focusManager = new FocusManagerImpl(this); + m_extender = new DockPanelExtender(this); + m_panes = new DockPaneCollection(); + m_floatWindows = new FloatWindowCollection(); + + SuspendLayout(); + + m_autoHideWindow = new AutoHideWindowControl(this); + m_autoHideWindow.Visible = false; + m_autoHideWindow.ActiveContentChanged += m_autoHideWindow_ActiveContentChanged; + SetAutoHideWindowParent(); + + m_dummyControl = new DummyControl(); + m_dummyControl.Bounds = new Rectangle(0, 0, 1, 1); + Controls.Add(m_dummyControl); + + m_dockWindows = new DockWindowCollection(this); + Controls.AddRange(new Control[] { + DockWindows[DockState.Document], + DockWindows[DockState.DockLeft], + DockWindows[DockState.DockRight], + DockWindows[DockState.DockTop], + DockWindows[DockState.DockBottom] + }); + + m_dummyContent = new DockContent(); + ResumeLayout(); + } + + private Color m_BackColor; + /// + /// Determines the color with which the client rectangle will be drawn. + /// If this property is used instead of the BackColor it will not have any influence on the borders to the surrounding controls (DockPane). + /// The BackColor property changes the borders of surrounding controls (DockPane). + /// Alternatively both properties may be used (BackColor to draw and define the color of the borders and DockBackColor to define the color of the client rectangle). + /// For Backgroundimages: Set your prefered Image, then set the DockBackColor and the BackColor to the same Color (Control) + /// + [Description("Determines the color with which the client rectangle will be drawn.\r\n" + + "If this property is used instead of the BackColor it will not have any influence on the borders to the surrounding controls (DockPane).\r\n" + + "The BackColor property changes the borders of surrounding controls (DockPane).\r\n" + + "Alternatively both properties may be used (BackColor to draw and define the color of the borders and DockBackColor to define the color of the client rectangle).\r\n" + + "For Backgroundimages: Set your prefered Image, then set the DockBackColor and the BackColor to the same Color (Control).")] + public Color DockBackColor + { + get + { + return !m_BackColor.IsEmpty ? m_BackColor : base.BackColor; + } + set + { + if (m_BackColor != value) + { + m_BackColor = value; + this.Refresh(); + } + } + } + + private bool ShouldSerializeDockBackColor() + { + return !m_BackColor.IsEmpty; + } + + private void ResetDockBackColor() + { + DockBackColor = Color.Empty; + } + + private AutoHideStripBase m_autoHideStripControl = null; + internal AutoHideStripBase AutoHideStripControl + { + get + { + if (m_autoHideStripControl == null) + { + m_autoHideStripControl = AutoHideStripFactory.CreateAutoHideStrip(this); + Controls.Add(m_autoHideStripControl); + } + return m_autoHideStripControl; + } + } + internal void ResetAutoHideStripControl() + { + if (m_autoHideStripControl != null) + m_autoHideStripControl.Dispose(); + + m_autoHideStripControl = null; + } + + private void MdiClientHandleAssigned(object sender, EventArgs e) + { + SetMdiClient(); + PerformLayout(); + } + + private void MdiClient_Layout(object sender, LayoutEventArgs e) + { + if (DocumentStyle != DocumentStyle.DockingMdi) + return; + + foreach (DockPane pane in Panes) + if (pane.DockState == DockState.Document) + pane.SetContentBounds(); + + InvalidateWindowRegion(); + } + + private bool m_disposed = false; + protected override void Dispose(bool disposing) + { + if (!m_disposed && disposing) + { + m_focusManager.Dispose(); + if (m_mdiClientController != null) + { + m_mdiClientController.HandleAssigned -= new EventHandler(MdiClientHandleAssigned); + m_mdiClientController.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate); + m_mdiClientController.Layout -= new LayoutEventHandler(MdiClient_Layout); + m_mdiClientController.Dispose(); + } + FloatWindows.Dispose(); + Panes.Dispose(); + DummyContent.Dispose(); + + m_disposed = true; + } + + base.Dispose(disposing); + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDockContent ActiveAutoHideContent + { + get { return AutoHideWindow.ActiveContent; } + set { AutoHideWindow.ActiveContent = value; } + } + + private bool m_allowEndUserDocking = !Win32Helper.IsRunningOnMono; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_AllowEndUserDocking_Description")] + [DefaultValue(true)] + public bool AllowEndUserDocking + { + get + { + if (Win32Helper.IsRunningOnMono && m_allowEndUserDocking) + m_allowEndUserDocking = false; + + return m_allowEndUserDocking; + } + set + { + if (Win32Helper.IsRunningOnMono && value) + throw new InvalidOperationException("AllowEndUserDocking can only be false if running on Mono"); + + m_allowEndUserDocking = value; + } + } + + + private bool m_raiseTabsOnDragOver = true; + [LocalizedCategory("Category_Docking")] + [Description("Raises tabs in a document pane when dragging over them")] + [DefaultValue(true)] + public bool RaiseTabsOnDragOver + { + get + { + return m_raiseTabsOnDragOver; + } + set + { + m_raiseTabsOnDragOver = value; + } + } + + private bool m_closeTabsToLeft = true; + [LocalizedCategory("Category_Docking")] + [Description("When closing the active tab, select next to the left")] + [DefaultValue(true)] + public bool CloseTabsToLeft + { + get + { + return m_closeTabsToLeft; + } + set + { + m_closeTabsToLeft = value; + } + } + + private bool m_allowEndUserNestedDocking = !Win32Helper.IsRunningOnMono; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_AllowEndUserNestedDocking_Description")] + [DefaultValue(true)] + public bool AllowEndUserNestedDocking + { + get + { + if (Win32Helper.IsRunningOnMono && m_allowEndUserDocking) + m_allowEndUserDocking = false; + return m_allowEndUserNestedDocking; + } + set + { + if (Win32Helper.IsRunningOnMono && value) + throw new InvalidOperationException("AllowEndUserNestedDocking can only be false if running on Mono"); + + m_allowEndUserNestedDocking = value; + } + } + + private DockContentCollection m_contents = new DockContentCollection(); + [Browsable(false)] + public DockContentCollection Contents + { + get { return m_contents; } + } + + internal DockContent DummyContent + { + get { return m_dummyContent; } + } + + private bool m_rightToLeftLayout = false; + [DefaultValue(false)] + [LocalizedCategory("Appearance")] + [LocalizedDescription("DockPanel_RightToLeftLayout_Description")] + public bool RightToLeftLayout + { + get { return m_rightToLeftLayout; } + set + { + if (m_rightToLeftLayout == value) + return; + + m_rightToLeftLayout = value; + foreach (FloatWindow floatWindow in FloatWindows) + floatWindow.RightToLeftLayout = value; + } + } + + protected override void OnRightToLeftChanged(EventArgs e) + { + base.OnRightToLeftChanged(e); + foreach (FloatWindow floatWindow in FloatWindows) + { + if (floatWindow.RightToLeft != RightToLeft) + floatWindow.RightToLeft = RightToLeft; + } + } + + private bool m_showDocumentIcon = false; + [DefaultValue(false)] + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_ShowDocumentIcon_Description")] + public bool ShowDocumentIcon + { + get { return m_showDocumentIcon; } + set + { + if (m_showDocumentIcon == value) + return; + + m_showDocumentIcon = value; + Refresh(); + } + } + + private DocumentTabStripLocation m_documentTabStripLocation = DocumentTabStripLocation.Top; + [DefaultValue(DocumentTabStripLocation.Top)] + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DocumentTabStripLocation")] + public DocumentTabStripLocation DocumentTabStripLocation + { + get { return m_documentTabStripLocation; } + set { m_documentTabStripLocation = value; } + } + + [Browsable(false)] + public DockPanelExtender Extender + { + get { return m_extender; } + } + + [Browsable(false)] + public DockPanelExtender.IDockPaneFactory DockPaneFactory + { + get { return Extender.DockPaneFactory; } + } + + [Browsable(false)] + public DockPanelExtender.IFloatWindowFactory FloatWindowFactory + { + get { return Extender.FloatWindowFactory; } + } + + internal DockPanelExtender.IDockPaneCaptionFactory DockPaneCaptionFactory + { + get { return Extender.DockPaneCaptionFactory; } + } + + internal DockPanelExtender.IDockPaneStripFactory DockPaneStripFactory + { + get { return Extender.DockPaneStripFactory; } + } + + internal DockPanelExtender.IAutoHideStripFactory AutoHideStripFactory + { + get { return Extender.AutoHideStripFactory; } + } + + [Browsable(false)] + public DockPaneCollection Panes + { + get { return m_panes; } + } + + internal Rectangle DockArea + { + get + { + return new Rectangle(DockPadding.Left, DockPadding.Top, + ClientRectangle.Width - DockPadding.Left - DockPadding.Right, + ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom); + } + } + + private double m_dockBottomPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockBottomPortion_Description")] + [DefaultValue(0.25)] + public double DockBottomPortion + { + get { return m_dockBottomPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockBottomPortion) + return; + + m_dockBottomPortion = value; + + if (m_dockBottomPortion < 1 && m_dockTopPortion < 1) + { + if (m_dockTopPortion + m_dockBottomPortion > 1) + m_dockTopPortion = 1 - m_dockBottomPortion; + } + + PerformLayout(); + } + } + + private double m_dockLeftPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockLeftPortion_Description")] + [DefaultValue(0.25)] + public double DockLeftPortion + { + get { return m_dockLeftPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockLeftPortion) + return; + + m_dockLeftPortion = value; + + if (m_dockLeftPortion < 1 && m_dockRightPortion < 1) + { + if (m_dockLeftPortion + m_dockRightPortion > 1) + m_dockRightPortion = 1 - m_dockLeftPortion; + } + PerformLayout(); + } + } + + private double m_dockRightPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockRightPortion_Description")] + [DefaultValue(0.25)] + public double DockRightPortion + { + get { return m_dockRightPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockRightPortion) + return; + + m_dockRightPortion = value; + + if (m_dockLeftPortion < 1 && m_dockRightPortion < 1) + { + if (m_dockLeftPortion + m_dockRightPortion > 1) + m_dockLeftPortion = 1 - m_dockRightPortion; + } + PerformLayout(); + } + } + + private double m_dockTopPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockTopPortion_Description")] + [DefaultValue(0.25)] + public double DockTopPortion + { + get { return m_dockTopPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockTopPortion) + return; + + m_dockTopPortion = value; + + if (m_dockTopPortion < 1 && m_dockBottomPortion < 1) + { + if (m_dockTopPortion + m_dockBottomPortion > 1) + m_dockBottomPortion = 1 - m_dockTopPortion; + } + PerformLayout(); + } + } + + [Browsable(false)] + public DockWindowCollection DockWindows + { + get { return m_dockWindows; } + } + + public void UpdateDockWindowZOrder(DockStyle dockStyle, bool fullPanelEdge) + { + if (dockStyle == DockStyle.Left) + { + if (fullPanelEdge) + DockWindows[DockState.DockLeft].SendToBack(); + else + DockWindows[DockState.DockLeft].BringToFront(); + } + else if (dockStyle == DockStyle.Right) + { + if (fullPanelEdge) + DockWindows[DockState.DockRight].SendToBack(); + else + DockWindows[DockState.DockRight].BringToFront(); + } + else if (dockStyle == DockStyle.Top) + { + if (fullPanelEdge) + DockWindows[DockState.DockTop].SendToBack(); + else + DockWindows[DockState.DockTop].BringToFront(); + } + else if (dockStyle == DockStyle.Bottom) + { + if (fullPanelEdge) + DockWindows[DockState.DockBottom].SendToBack(); + else + DockWindows[DockState.DockBottom].BringToFront(); + } + } + + [Browsable(false)] + public int DocumentsCount + { + get + { + int count = 0; + foreach (IDockContent content in Documents) + count++; + + return count; + } + } + + public IDockContent[] DocumentsToArray() + { + int count = DocumentsCount; + IDockContent[] documents = new IDockContent[count]; + int i = 0; + foreach (IDockContent content in Documents) + { + documents[i] = content; + i++; + } + + return documents; + } + + [Browsable(false)] + public IEnumerable Documents + { + get + { + foreach (IDockContent content in Contents) + { + if (content.DockHandler.DockState == DockState.Document) + yield return content; + } + } + } + + private Control DummyControl + { + get { return m_dummyControl; } + } + + [Browsable(false)] + public FloatWindowCollection FloatWindows + { + get { return m_floatWindows; } + } + + private Size m_defaultFloatWindowSize = new Size(300, 300); + [Category("Layout")] + [LocalizedDescription("DockPanel_DefaultFloatWindowSize_Description")] + public Size DefaultFloatWindowSize + { + get { return m_defaultFloatWindowSize; } + set { m_defaultFloatWindowSize = value; } + } + private bool ShouldSerializeDefaultFloatWindowSize() + { + return DefaultFloatWindowSize != new Size(300, 300); + } + private void ResetDefaultFloatWindowSize() + { + DefaultFloatWindowSize = new Size(300, 300); + } + + private DocumentStyle m_documentStyle = DocumentStyle.DockingMdi; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DocumentStyle_Description")] + [DefaultValue(DocumentStyle.DockingMdi)] + public DocumentStyle DocumentStyle + { + get { return m_documentStyle; } + set + { + if (value == m_documentStyle) + return; + + if (!Enum.IsDefined(typeof(DocumentStyle), value)) + throw new InvalidEnumArgumentException(); + + if (value == DocumentStyle.SystemMdi && DockWindows[DockState.Document].VisibleNestedPanes.Count > 0) + throw new InvalidEnumArgumentException(); + + m_documentStyle = value; + + SuspendLayout(true); + + SetAutoHideWindowParent(); + SetMdiClient(); + InvalidateWindowRegion(); + + foreach (IDockContent content in Contents) + { + if (content.DockHandler.DockState == DockState.Document) + content.DockHandler.SetPaneAndVisible(content.DockHandler.Pane); + } + + PerformMdiClientLayout(); + + ResumeLayout(true, true); + } + } + + private bool _supprtDeeplyNestedContent = false; + [LocalizedCategory("Category_Performance")] + [LocalizedDescription("DockPanel_SupportDeeplyNestedContent_Description")] + [DefaultValue(false)] + public bool SupportDeeplyNestedContent + { + get { return _supprtDeeplyNestedContent; } + set { _supprtDeeplyNestedContent = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_ShowAutoHideContentOnHover_Description")] + [DefaultValue(true)] + public bool ShowAutoHideContentOnHover { get; set; } + + private int GetDockWindowSize(DockState dockState) + { + if (dockState == DockState.DockLeft || dockState == DockState.DockRight) + { + int width = ClientRectangle.Width - DockPadding.Left - DockPadding.Right; + int dockLeftSize = m_dockLeftPortion >= 1 ? (int)m_dockLeftPortion : (int)(width * m_dockLeftPortion); + int dockRightSize = m_dockRightPortion >= 1 ? (int)m_dockRightPortion : (int)(width * m_dockRightPortion); + + if (dockLeftSize < MeasurePane.MinSize) + dockLeftSize = MeasurePane.MinSize; + if (dockRightSize < MeasurePane.MinSize) + dockRightSize = MeasurePane.MinSize; + + if (dockLeftSize + dockRightSize > width - MeasurePane.MinSize) + { + int adjust = (dockLeftSize + dockRightSize) - (width - MeasurePane.MinSize); + dockLeftSize -= adjust / 2; + dockRightSize -= adjust / 2; + } + + return dockState == DockState.DockLeft ? dockLeftSize : dockRightSize; + } + else if (dockState == DockState.DockTop || dockState == DockState.DockBottom) + { + int height = ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom; + int dockTopSize = m_dockTopPortion >= 1 ? (int)m_dockTopPortion : (int)(height * m_dockTopPortion); + int dockBottomSize = m_dockBottomPortion >= 1 ? (int)m_dockBottomPortion : (int)(height * m_dockBottomPortion); + + if (dockTopSize < MeasurePane.MinSize) + dockTopSize = MeasurePane.MinSize; + if (dockBottomSize < MeasurePane.MinSize) + dockBottomSize = MeasurePane.MinSize; + + if (dockTopSize + dockBottomSize > height - MeasurePane.MinSize) + { + int adjust = (dockTopSize + dockBottomSize) - (height - MeasurePane.MinSize); + dockTopSize -= adjust / 2; + dockBottomSize -= adjust / 2; + } + + return dockState == DockState.DockTop ? dockTopSize : dockBottomSize; + } + else + return 0; + } + + protected override void OnLayout(LayoutEventArgs levent) + { + SuspendLayout(true); + + AutoHideStripControl.Bounds = ClientRectangle; + + CalculateDockPadding(); + + DockWindows[DockState.DockLeft].Width = GetDockWindowSize(DockState.DockLeft); + DockWindows[DockState.DockRight].Width = GetDockWindowSize(DockState.DockRight); + DockWindows[DockState.DockTop].Height = GetDockWindowSize(DockState.DockTop); + DockWindows[DockState.DockBottom].Height = GetDockWindowSize(DockState.DockBottom); + + AutoHideWindow.Bounds = GetAutoHideWindowBounds(AutoHideWindowRectangle); + + DockWindows[DockState.Document].BringToFront(); + AutoHideWindow.BringToFront(); + + base.OnLayout(levent); + + if (DocumentStyle == DocumentStyle.SystemMdi && MdiClientExists) + { + SetMdiClientBounds(SystemMdiClientBounds); + InvalidateWindowRegion(); + } + else if (DocumentStyle == DocumentStyle.DockingMdi) + InvalidateWindowRegion(); + + ResumeLayout(true, true); + } + + internal Rectangle GetTabStripRectangle(DockState dockState) + { + return AutoHideStripControl.GetTabStripRectangle(dockState); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (DockBackColor == BackColor) return; + + Graphics g = e.Graphics; + SolidBrush bgBrush = new SolidBrush(DockBackColor); + g.FillRectangle(bgBrush, ClientRectangle); + } + + internal void AddContent(IDockContent content) + { + if (content == null) + throw(new ArgumentNullException()); + + if (!Contents.Contains(content)) + { + Contents.Add(content); + OnContentAdded(new DockContentEventArgs(content)); + } + } + + internal void AddPane(DockPane pane) + { + if (Panes.Contains(pane)) + return; + + Panes.Add(pane); + } + + internal void AddFloatWindow(FloatWindow floatWindow) + { + if (FloatWindows.Contains(floatWindow)) + return; + + FloatWindows.Add(floatWindow); + } + + private void CalculateDockPadding() + { + DockPadding.All = 0; + + int height = AutoHideStripControl.MeasureHeight(); + + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockLeftAutoHide) > 0) + DockPadding.Left = height; + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockRightAutoHide) > 0) + DockPadding.Right = height; + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockTopAutoHide) > 0) + DockPadding.Top = height; + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockBottomAutoHide) > 0) + DockPadding.Bottom = height; + } + + internal void RemoveContent(IDockContent content) + { + if (content == null) + throw(new ArgumentNullException()); + + if (Contents.Contains(content)) + { + Contents.Remove(content); + OnContentRemoved(new DockContentEventArgs(content)); + } + } + + internal void RemovePane(DockPane pane) + { + if (!Panes.Contains(pane)) + return; + + Panes.Remove(pane); + } + + internal void RemoveFloatWindow(FloatWindow floatWindow) + { + if (!FloatWindows.Contains(floatWindow)) + return; + + FloatWindows.Remove(floatWindow); + if (FloatWindows.Count != 0) + return; + + if (ParentForm == null) + return; + + ParentForm.Focus(); + } + + public void SetPaneIndex(DockPane pane, int index) + { + int oldIndex = Panes.IndexOf(pane); + if (oldIndex == -1) + throw(new ArgumentException(Strings.DockPanel_SetPaneIndex_InvalidPane)); + + if (index < 0 || index > Panes.Count - 1) + if (index != -1) + throw(new ArgumentOutOfRangeException(Strings.DockPanel_SetPaneIndex_InvalidIndex)); + + if (oldIndex == index) + return; + if (oldIndex == Panes.Count - 1 && index == -1) + return; + + Panes.Remove(pane); + if (index == -1) + Panes.Add(pane); + else if (oldIndex < index) + Panes.AddAt(pane, index - 1); + else + Panes.AddAt(pane, index); + } + + public void SuspendLayout(bool allWindows) + { + FocusManager.SuspendFocusTracking(); + SuspendLayout(); + if (allWindows) + SuspendMdiClientLayout(); + } + + public void ResumeLayout(bool performLayout, bool allWindows) + { + FocusManager.ResumeFocusTracking(); + ResumeLayout(performLayout); + if (allWindows) + ResumeMdiClientLayout(performLayout); + } + + internal Form ParentForm + { + get + { + if (!IsParentFormValid()) + throw new InvalidOperationException(Strings.DockPanel_ParentForm_Invalid); + + return GetMdiClientController().ParentForm; + } + } + + private bool IsParentFormValid() + { + if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow) + return true; + + if (!MdiClientExists) + GetMdiClientController().RenewMdiClient(); + + return (MdiClientExists); + } + + protected override void OnParentChanged(EventArgs e) + { + SetAutoHideWindowParent(); + GetMdiClientController().ParentForm = (this.Parent as Form); + base.OnParentChanged (e); + } + + private void SetAutoHideWindowParent() + { + Control parent; + if (DocumentStyle == DocumentStyle.DockingMdi || + DocumentStyle == DocumentStyle.SystemMdi) + parent = this.Parent; + else + parent = this; + if (AutoHideWindow.Parent != parent) + { + AutoHideWindow.Parent = parent; + AutoHideWindow.BringToFront(); + } + } + + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged (e); + + if (Visible) + SetMdiClient(); + } + + private Rectangle SystemMdiClientBounds + { + get + { + if (!IsParentFormValid() || !Visible) + return Rectangle.Empty; + + Rectangle rect = ParentForm.RectangleToClient(RectangleToScreen(DocumentWindowBounds)); + return rect; + } + } + + internal Rectangle DocumentWindowBounds + { + get + { + Rectangle rectDocumentBounds = DisplayRectangle; + if (DockWindows[DockState.DockLeft].Visible) + { + rectDocumentBounds.X += DockWindows[DockState.DockLeft].Width; + rectDocumentBounds.Width -= DockWindows[DockState.DockLeft].Width; + } + if (DockWindows[DockState.DockRight].Visible) + rectDocumentBounds.Width -= DockWindows[DockState.DockRight].Width; + if (DockWindows[DockState.DockTop].Visible) + { + rectDocumentBounds.Y += DockWindows[DockState.DockTop].Height; + rectDocumentBounds.Height -= DockWindows[DockState.DockTop].Height; + } + if (DockWindows[DockState.DockBottom].Visible) + rectDocumentBounds.Height -= DockWindows[DockState.DockBottom].Height; + + return rectDocumentBounds; + + } + } + + private PaintEventHandler m_dummyControlPaintEventHandler = null; + private void InvalidateWindowRegion() + { + if (DesignMode) + return; + + if (m_dummyControlPaintEventHandler == null) + m_dummyControlPaintEventHandler = new PaintEventHandler(DummyControl_Paint); + + DummyControl.Paint += m_dummyControlPaintEventHandler; + DummyControl.Invalidate(); + } + + void DummyControl_Paint(object sender, PaintEventArgs e) + { + DummyControl.Paint -= m_dummyControlPaintEventHandler; + UpdateWindowRegion(); + } + + private void UpdateWindowRegion() + { + if (this.DocumentStyle == DocumentStyle.DockingMdi) + UpdateWindowRegion_ClipContent(); + else if (this.DocumentStyle == DocumentStyle.DockingSdi || + this.DocumentStyle == DocumentStyle.DockingWindow) + UpdateWindowRegion_FullDocumentArea(); + else if (this.DocumentStyle == DocumentStyle.SystemMdi) + UpdateWindowRegion_EmptyDocumentArea(); + } + + private void UpdateWindowRegion_FullDocumentArea() + { + SetRegion(null); + } + + private void UpdateWindowRegion_EmptyDocumentArea() + { + Rectangle rect = DocumentWindowBounds; + SetRegion(new Rectangle[] { rect }); + } + + private void UpdateWindowRegion_ClipContent() + { + int count = 0; + foreach (DockPane pane in this.Panes) + { + if (!pane.Visible || pane.DockState != DockState.Document) + continue; + + count ++; + } + + if (count == 0) + { + SetRegion(null); + return; + } + + Rectangle[] rects = new Rectangle[count]; + int i = 0; + foreach (DockPane pane in this.Panes) + { + if (!pane.Visible || pane.DockState != DockState.Document) + continue; + + rects[i] = RectangleToClient(pane.RectangleToScreen(pane.ContentRectangle)); + i++; + } + + SetRegion(rects); + } + + private Rectangle[] m_clipRects = null; + private void SetRegion(Rectangle[] clipRects) + { + if (!IsClipRectsChanged(clipRects)) + return; + + m_clipRects = clipRects; + + if (m_clipRects == null || m_clipRects.GetLength(0) == 0) + Region = null; + else + { + Region region = new Region(new Rectangle(0, 0, this.Width, this.Height)); + foreach (Rectangle rect in m_clipRects) + region.Exclude(rect); + Region = region; + } + } + + private bool IsClipRectsChanged(Rectangle[] clipRects) + { + if (clipRects == null && m_clipRects == null) + return false; + else if ((clipRects == null) != (m_clipRects == null)) + return true; + + foreach (Rectangle rect in clipRects) + { + bool matched = false; + foreach (Rectangle rect2 in m_clipRects) + { + if (rect == rect2) + { + matched = true; + break; + } + } + if (!matched) + return true; + } + + foreach (Rectangle rect2 in m_clipRects) + { + bool matched = false; + foreach (Rectangle rect in clipRects) + { + if (rect == rect2) + { + matched = true; + break; + } + } + if (!matched) + return true; + } + return false; + } + + private static readonly object ActiveAutoHideContentChangedEvent = new object(); + [LocalizedCategory("Category_DockingNotification")] + [LocalizedDescription("DockPanel_ActiveAutoHideContentChanged_Description")] + public event EventHandler ActiveAutoHideContentChanged + { + add { Events.AddHandler(ActiveAutoHideContentChangedEvent, value); } + remove { Events.RemoveHandler(ActiveAutoHideContentChangedEvent, value); } + } + protected virtual void OnActiveAutoHideContentChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActiveAutoHideContentChangedEvent]; + if (handler != null) + handler(this, e); + } + private void m_autoHideWindow_ActiveContentChanged(object sender, EventArgs e) + { + OnActiveAutoHideContentChanged(e); + } + + + private static readonly object ContentAddedEvent = new object(); + [LocalizedCategory("Category_DockingNotification")] + [LocalizedDescription("DockPanel_ContentAdded_Description")] + public event EventHandler ContentAdded + { + add { Events.AddHandler(ContentAddedEvent, value); } + remove { Events.RemoveHandler(ContentAddedEvent, value); } + } + protected virtual void OnContentAdded(DockContentEventArgs e) + { + EventHandler handler = (EventHandler)Events[ContentAddedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object ContentRemovedEvent = new object(); + [LocalizedCategory("Category_DockingNotification")] + [LocalizedDescription("DockPanel_ContentRemoved_Description")] + public event EventHandler ContentRemoved + { + add { Events.AddHandler(ContentRemovedEvent, value); } + remove { Events.RemoveHandler(ContentRemovedEvent, value); } + } + protected virtual void OnContentRemoved(DockContentEventArgs e) + { + EventHandler handler = (EventHandler)Events[ContentRemovedEvent]; + if (handler != null) + handler(this, e); + } + } +} diff --git a/WinFormsUI/Docking/DockPanelExtender.cs b/WinFormsUI/Docking/DockPanelExtender.cs new file mode 100644 index 0000000000..534af20880 --- /dev/null +++ b/WinFormsUI/Docking/DockPanelExtender.cs @@ -0,0 +1,225 @@ +using System; +using System.Drawing; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public sealed class DockPanelExtender + { + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IDockPaneFactory + { + DockPane CreateDockPane(IDockContent content, DockState visibleState, bool show); + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")] + DockPane CreateDockPane(IDockContent content, FloatWindow floatWindow, bool show); + DockPane CreateDockPane(IDockContent content, DockPane previousPane, DockAlignment alignment, double proportion, bool show); + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")] + DockPane CreateDockPane(IDockContent content, Rectangle floatWindowBounds, bool show); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IFloatWindowFactory + { + FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane); + FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IDockPaneCaptionFactory + { + DockPaneCaptionBase CreateDockPaneCaption(DockPane pane); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IDockPaneStripFactory + { + DockPaneStripBase CreateDockPaneStrip(DockPane pane); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IAutoHideStripFactory + { + AutoHideStripBase CreateAutoHideStrip(DockPanel panel); + } + + #region DefaultDockPaneFactory + private class DefaultDockPaneFactory : IDockPaneFactory + { + public DockPane CreateDockPane(IDockContent content, DockState visibleState, bool show) + { + return new DockPane(content, visibleState, show); + } + + public DockPane CreateDockPane(IDockContent content, FloatWindow floatWindow, bool show) + { + return new DockPane(content, floatWindow, show); + } + + public DockPane CreateDockPane(IDockContent content, DockPane prevPane, DockAlignment alignment, double proportion, bool show) + { + return new DockPane(content, prevPane, alignment, proportion, show); + } + + public DockPane CreateDockPane(IDockContent content, Rectangle floatWindowBounds, bool show) + { + return new DockPane(content, floatWindowBounds, show); + } + } + #endregion + + #region DefaultFloatWindowFactory + private class DefaultFloatWindowFactory : IFloatWindowFactory + { + public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane) + { + return new FloatWindow(dockPanel, pane); + } + + public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds) + { + return new FloatWindow(dockPanel, pane, bounds); + } + } + #endregion + + #region DefaultDockPaneCaptionFactory + private class DefaultDockPaneCaptionFactory : IDockPaneCaptionFactory + { + public DockPaneCaptionBase CreateDockPaneCaption(DockPane pane) + { + return new VS2005DockPaneCaption(pane); + } + } + #endregion + + #region DefaultDockPaneTabStripFactory + private class DefaultDockPaneStripFactory : IDockPaneStripFactory + { + public DockPaneStripBase CreateDockPaneStrip(DockPane pane) + { + return new VS2005DockPaneStrip(pane); + } + } + #endregion + + #region DefaultAutoHideStripFactory + private class DefaultAutoHideStripFactory : IAutoHideStripFactory + { + public AutoHideStripBase CreateAutoHideStrip(DockPanel panel) + { + return new VS2005AutoHideStrip(panel); + } + } + #endregion + + internal DockPanelExtender(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + } + + private DockPanel m_dockPanel; + private DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private IDockPaneFactory m_dockPaneFactory = null; + public IDockPaneFactory DockPaneFactory + { + get + { + if (m_dockPaneFactory == null) + m_dockPaneFactory = new DefaultDockPaneFactory(); + + return m_dockPaneFactory; + } + set + { + if (DockPanel.Panes.Count > 0) + throw new InvalidOperationException(); + + m_dockPaneFactory = value; + } + } + + private IFloatWindowFactory m_floatWindowFactory = null; + public IFloatWindowFactory FloatWindowFactory + { + get + { + if (m_floatWindowFactory == null) + m_floatWindowFactory = new DefaultFloatWindowFactory(); + + return m_floatWindowFactory; + } + set + { + if (DockPanel.FloatWindows.Count > 0) + throw new InvalidOperationException(); + + m_floatWindowFactory = value; + } + } + + private IDockPaneCaptionFactory m_dockPaneCaptionFactory = null; + public IDockPaneCaptionFactory DockPaneCaptionFactory + { + get + { + if (m_dockPaneCaptionFactory == null) + m_dockPaneCaptionFactory = new DefaultDockPaneCaptionFactory(); + + return m_dockPaneCaptionFactory; + } + set + { + if (DockPanel.Panes.Count > 0) + throw new InvalidOperationException(); + + m_dockPaneCaptionFactory = value; + } + } + + private IDockPaneStripFactory m_dockPaneStripFactory = null; + public IDockPaneStripFactory DockPaneStripFactory + { + get + { + if (m_dockPaneStripFactory == null) + m_dockPaneStripFactory = new DefaultDockPaneStripFactory(); + + return m_dockPaneStripFactory; + } + set + { + if (DockPanel.Contents.Count > 0) + throw new InvalidOperationException(); + + m_dockPaneStripFactory = value; + } + } + + private IAutoHideStripFactory m_autoHideStripFactory = null; + public IAutoHideStripFactory AutoHideStripFactory + { + get + { + if (m_autoHideStripFactory == null) + m_autoHideStripFactory = new DefaultAutoHideStripFactory(); + + return m_autoHideStripFactory; + } + set + { + if (DockPanel.Contents.Count > 0) + throw new InvalidOperationException(); + + if (m_autoHideStripFactory == value) + return; + + m_autoHideStripFactory = value; + DockPanel.ResetAutoHideStripControl(); + } + } + } +} diff --git a/WinFormsUI/Docking/DockPanelSkin.cs b/WinFormsUI/Docking/DockPanelSkin.cs new file mode 100644 index 0000000000..b6c5476cab --- /dev/null +++ b/WinFormsUI/Docking/DockPanelSkin.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Design; +using System.Windows.Forms.Design; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + #region DockPanelSkin classes + /// + /// The skin to use when displaying the DockPanel. + /// The skin allows custom gradient color schemes to be used when drawing the + /// DockStrips and Tabs. + /// + [TypeConverter(typeof(DockPanelSkinConverter))] + public class DockPanelSkin + { + private AutoHideStripSkin m_autoHideStripSkin = new AutoHideStripSkin(); + private DockPaneStripSkin m_dockPaneStripSkin = new DockPaneStripSkin(); + + /// + /// The skin used to display the auto hide strips and tabs. + /// + public AutoHideStripSkin AutoHideStripSkin + { + get { return m_autoHideStripSkin; } + set { m_autoHideStripSkin = value; } + } + + /// + /// The skin used to display the Document and ToolWindow style DockStrips and Tabs. + /// + public DockPaneStripSkin DockPaneStripSkin + { + get { return m_dockPaneStripSkin; } + set { m_dockPaneStripSkin = value; } + } + } + + /// + /// The skin used to display the auto hide strip and tabs. + /// + [TypeConverter(typeof(AutoHideStripConverter))] + public class AutoHideStripSkin + { + private DockPanelGradient m_dockStripGradient = new DockPanelGradient(); + private TabGradient m_TabGradient = new TabGradient(); + private Font m_textFont = SystemFonts.MenuFont; + + /// + /// The gradient color skin for the DockStrips. + /// + public DockPanelGradient DockStripGradient + { + get { return m_dockStripGradient; } + set { m_dockStripGradient = value; } + } + + /// + /// The gradient color skin for the Tabs. + /// + public TabGradient TabGradient + { + get { return m_TabGradient; } + set { m_TabGradient = value; } + } + + /// + /// Font used in AutoHideStrip elements. + /// + [DefaultValue(typeof(SystemFonts), "MenuFont")] + public Font TextFont + { + get { return m_textFont; } + set { m_textFont = value; } + } + } + + /// + /// The skin used to display the document and tool strips and tabs. + /// + [TypeConverter(typeof(DockPaneStripConverter))] + public class DockPaneStripSkin + { + private DockPaneStripGradient m_DocumentGradient = new DockPaneStripGradient(); + private DockPaneStripToolWindowGradient m_ToolWindowGradient = new DockPaneStripToolWindowGradient(); + private Font m_textFont = SystemFonts.MenuFont; + + /// + /// The skin used to display the Document style DockPane strip and tab. + /// + public DockPaneStripGradient DocumentGradient + { + get { return m_DocumentGradient; } + set { m_DocumentGradient = value; } + } + + /// + /// The skin used to display the ToolWindow style DockPane strip and tab. + /// + public DockPaneStripToolWindowGradient ToolWindowGradient + { + get { return m_ToolWindowGradient; } + set { m_ToolWindowGradient = value; } + } + + /// + /// Font used in DockPaneStrip elements. + /// + [DefaultValue(typeof(SystemFonts), "MenuFont")] + public Font TextFont + { + get { return m_textFont; } + set { m_textFont = value; } + } + } + + /// + /// The skin used to display the DockPane ToolWindow strip and tab. + /// + [TypeConverter(typeof(DockPaneStripGradientConverter))] + public class DockPaneStripToolWindowGradient : DockPaneStripGradient + { + private TabGradient m_activeCaptionGradient = new TabGradient(); + private TabGradient m_inactiveCaptionGradient = new TabGradient(); + + /// + /// The skin used to display the active ToolWindow caption. + /// + public TabGradient ActiveCaptionGradient + { + get { return m_activeCaptionGradient; } + set { m_activeCaptionGradient = value; } + } + + /// + /// The skin used to display the inactive ToolWindow caption. + /// + public TabGradient InactiveCaptionGradient + { + get { return m_inactiveCaptionGradient; } + set { m_inactiveCaptionGradient = value; } + } + } + + /// + /// The skin used to display the DockPane strip and tab. + /// + [TypeConverter(typeof(DockPaneStripGradientConverter))] + public class DockPaneStripGradient + { + private DockPanelGradient m_dockStripGradient = new DockPanelGradient(); + private TabGradient m_activeTabGradient = new TabGradient(); + private TabGradient m_inactiveTabGradient = new TabGradient(); + + /// + /// The gradient color skin for the DockStrip. + /// + public DockPanelGradient DockStripGradient + { + get { return m_dockStripGradient; } + set { m_dockStripGradient = value; } + } + + /// + /// The skin used to display the active DockPane tabs. + /// + public TabGradient ActiveTabGradient + { + get { return m_activeTabGradient; } + set { m_activeTabGradient = value; } + } + + /// + /// The skin used to display the inactive DockPane tabs. + /// + public TabGradient InactiveTabGradient + { + get { return m_inactiveTabGradient; } + set { m_inactiveTabGradient = value; } + } + } + + /// + /// The skin used to display the dock pane tab + /// + [TypeConverter(typeof(DockPaneTabGradientConverter))] + public class TabGradient : DockPanelGradient + { + private Color m_textColor = SystemColors.ControlText; + + /// + /// The text color. + /// + [DefaultValue(typeof(SystemColors), "ControlText")] + public Color TextColor + { + get { return m_textColor; } + set { m_textColor = value; } + } + } + + /// + /// The gradient color skin. + /// + [TypeConverter(typeof(DockPanelGradientConverter))] + public class DockPanelGradient + { + private Color m_startColor = SystemColors.Control; + private Color m_endColor = SystemColors.Control; + private LinearGradientMode m_linearGradientMode = LinearGradientMode.Horizontal; + + /// + /// The beginning gradient color. + /// + [DefaultValue(typeof(SystemColors), "Control")] + public Color StartColor + { + get { return m_startColor; } + set { m_startColor = value; } + } + + /// + /// The ending gradient color. + /// + [DefaultValue(typeof(SystemColors), "Control")] + public Color EndColor + { + get { return m_endColor; } + set { m_endColor = value; } + } + + /// + /// The gradient mode to display the colors. + /// + [DefaultValue(LinearGradientMode.Horizontal)] + public LinearGradientMode LinearGradientMode + { + get { return m_linearGradientMode; } + set { m_linearGradientMode = value; } + } + } + + #endregion + + #region Converters + public class DockPanelSkinConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPanelSkin)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPanelSkin) + { + return "DockPanelSkin"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPanelGradientConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPanelGradient)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPanelGradient) + { + return "DockPanelGradient"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class AutoHideStripConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(AutoHideStripSkin)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is AutoHideStripSkin) + { + return "AutoHideStripSkin"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPaneStripConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPaneStripSkin)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPaneStripSkin) + { + return "DockPaneStripSkin"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPaneStripGradientConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPaneStripGradient)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPaneStripGradient) + { + return "DockPaneStripGradient"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPaneTabGradientConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(TabGradient)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + TabGradient val = value as TabGradient; + if (destinationType == typeof(String) && val != null) + { + return "DockPaneTabGradient"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + #endregion +} diff --git a/WinFormsUI/Docking/DockWindow.SplitterControl.cs b/WinFormsUI/Docking/DockWindow.SplitterControl.cs new file mode 100644 index 0000000000..3eaa653907 --- /dev/null +++ b/WinFormsUI/Docking/DockWindow.SplitterControl.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public partial class DockWindow + { + private class SplitterControl : SplitterBase + { + protected override int SplitterSize + { + get { return Measures.SplitterSize; } + } + + protected override void StartDrag() + { + DockWindow window = Parent as DockWindow; + if (window == null) + return; + + window.DockPanel.BeginDrag(window, window.RectangleToScreen(Bounds)); + } + } + } +} diff --git a/WinFormsUI/Docking/DockWindow.cs b/WinFormsUI/Docking/DockWindow.cs new file mode 100644 index 0000000000..9d12bc8362 --- /dev/null +++ b/WinFormsUI/Docking/DockWindow.cs @@ -0,0 +1,243 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Runtime.InteropServices; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + [ToolboxItem(false)] + public partial class DockWindow : Panel, INestedPanesContainer, ISplitterDragSource + { + private DockPanel m_dockPanel; + private DockState m_dockState; + private SplitterControl m_splitter; + private NestedPaneCollection m_nestedPanes; + + internal DockWindow(DockPanel dockPanel, DockState dockState) + { + m_nestedPanes = new NestedPaneCollection(this); + m_dockPanel = dockPanel; + m_dockState = dockState; + Visible = false; + + SuspendLayout(); + + if (DockState == DockState.DockLeft || DockState == DockState.DockRight || + DockState == DockState.DockTop || DockState == DockState.DockBottom) + { + m_splitter = new SplitterControl(); + Controls.Add(m_splitter); + } + + if (DockState == DockState.DockLeft) + { + Dock = DockStyle.Left; + m_splitter.Dock = DockStyle.Right; + } + else if (DockState == DockState.DockRight) + { + Dock = DockStyle.Right; + m_splitter.Dock = DockStyle.Left; + } + else if (DockState == DockState.DockTop) + { + Dock = DockStyle.Top; + m_splitter.Dock = DockStyle.Bottom; + } + else if (DockState == DockState.DockBottom) + { + Dock = DockStyle.Bottom; + m_splitter.Dock = DockStyle.Top; + } + else if (DockState == DockState.Document) + { + Dock = DockStyle.Fill; + } + + ResumeLayout(); + } + + public VisibleNestedPaneCollection VisibleNestedPanes + { + get { return NestedPanes.VisibleNestedPanes; } + } + + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + public DockState DockState + { + get { return m_dockState; } + } + + public bool IsFloat + { + get { return DockState == DockState.Float; } + } + + internal DockPane DefaultPane + { + get { return VisibleNestedPanes.Count == 0 ? null : VisibleNestedPanes[0]; } + } + + public virtual Rectangle DisplayingRectangle + { + get + { + Rectangle rect = ClientRectangle; + // if DockWindow is document, exclude the border + if (DockState == DockState.Document) + { + rect.X += 1; + rect.Y += 1; + rect.Width -= 2; + rect.Height -= 2; + } + // exclude the splitter + else if (DockState == DockState.DockLeft) + rect.Width -= Measures.SplitterSize; + else if (DockState == DockState.DockRight) + { + rect.X += Measures.SplitterSize; + rect.Width -= Measures.SplitterSize; + } + else if (DockState == DockState.DockTop) + rect.Height -= Measures.SplitterSize; + else if (DockState == DockState.DockBottom) + { + rect.Y += Measures.SplitterSize; + rect.Height -= Measures.SplitterSize; + } + + return rect; + } + } + + protected override void OnPaint(PaintEventArgs e) + { + // if DockWindow is document, draw the border + if (DockState == DockState.Document) + e.Graphics.DrawRectangle(SystemPens.ControlDark, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1); + + base.OnPaint(e); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + VisibleNestedPanes.Refresh(); + if (VisibleNestedPanes.Count == 0) + { + if (Visible) + Visible = false; + } + else if (!Visible) + { + Visible = true; + VisibleNestedPanes.Refresh(); + } + + base.OnLayout (levent); + } + + #region ISplitterDragSource Members + + void ISplitterDragSource.BeginDrag(Rectangle rectSplitter) + { + } + + void ISplitterDragSource.EndDrag() + { + } + + bool ISplitterDragSource.IsVertical + { + get { return (DockState == DockState.DockLeft || DockState == DockState.DockRight); } + } + + Rectangle ISplitterDragSource.DragLimitBounds + { + get + { + Rectangle rectLimit = DockPanel.DockArea; + Point location; + if ((Control.ModifierKeys & Keys.Shift) == 0) + location = Location; + else + location = DockPanel.DockArea.Location; + + if (((ISplitterDragSource)this).IsVertical) + { + rectLimit.X += MeasurePane.MinSize; + rectLimit.Width -= 2 * MeasurePane.MinSize; + rectLimit.Y = location.Y; + if ((Control.ModifierKeys & Keys.Shift) == 0) + rectLimit.Height = Height; + } + else + { + rectLimit.Y += MeasurePane.MinSize; + rectLimit.Height -= 2 * MeasurePane.MinSize; + rectLimit.X = location.X; + if ((Control.ModifierKeys & Keys.Shift) == 0) + rectLimit.Width = Width; + } + + return DockPanel.RectangleToScreen(rectLimit); + } + } + + void ISplitterDragSource.MoveSplitter(int offset) + { + if ((Control.ModifierKeys & Keys.Shift) != 0) + SendToBack(); + + Rectangle rectDockArea = DockPanel.DockArea; + if (DockState == DockState.DockLeft && rectDockArea.Width > 0) + { + if (DockPanel.DockLeftPortion > 1) + DockPanel.DockLeftPortion = Width + offset; + else + DockPanel.DockLeftPortion += ((double)offset) / (double)rectDockArea.Width; + } + else if (DockState == DockState.DockRight && rectDockArea.Width > 0) + { + if (DockPanel.DockRightPortion > 1) + DockPanel.DockRightPortion = Width - offset; + else + DockPanel.DockRightPortion -= ((double)offset) / (double)rectDockArea.Width; + } + else if (DockState == DockState.DockBottom && rectDockArea.Height > 0) + { + if (DockPanel.DockBottomPortion > 1) + DockPanel.DockBottomPortion = Height - offset; + else + DockPanel.DockBottomPortion -= ((double)offset) / (double)rectDockArea.Height; + } + else if (DockState == DockState.DockTop && rectDockArea.Height > 0) + { + if (DockPanel.DockTopPortion > 1) + DockPanel.DockTopPortion = Height + offset; + else + DockPanel.DockTopPortion += ((double)offset) / (double)rectDockArea.Height; + } + } + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + #endregion + } +} diff --git a/WinFormsUI/Docking/DockWindowCollection.cs b/WinFormsUI/Docking/DockWindowCollection.cs new file mode 100644 index 0000000000..3e0b1c1e21 --- /dev/null +++ b/WinFormsUI/Docking/DockWindowCollection.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class DockWindowCollection : ReadOnlyCollection + { + internal DockWindowCollection(DockPanel dockPanel) + : base(new List()) + { + Items.Add(new DockWindow(dockPanel, DockState.Document)); + Items.Add(new DockWindow(dockPanel, DockState.DockLeft)); + Items.Add(new DockWindow(dockPanel, DockState.DockRight)); + Items.Add(new DockWindow(dockPanel, DockState.DockTop)); + Items.Add(new DockWindow(dockPanel, DockState.DockBottom)); + } + + public DockWindow this [DockState dockState] + { + get + { + if (dockState == DockState.Document) + return Items[0]; + else if (dockState == DockState.DockLeft || dockState == DockState.DockLeftAutoHide) + return Items[1]; + else if (dockState == DockState.DockRight || dockState == DockState.DockRightAutoHide) + return Items[2]; + else if (dockState == DockState.DockTop || dockState == DockState.DockTopAutoHide) + return Items[3]; + else if (dockState == DockState.DockBottom || dockState == DockState.DockBottomAutoHide) + return Items[4]; + + throw (new ArgumentOutOfRangeException()); + } + } + } +} diff --git a/WinFormsUI/Docking/DragForm.cs b/WinFormsUI/Docking/DragForm.cs new file mode 100644 index 0000000000..c40a9aa7f7 --- /dev/null +++ b/WinFormsUI/Docking/DragForm.cs @@ -0,0 +1,69 @@ +using System; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + // Inspired by Chris Sano's article: + // http://msdn.microsoft.com/smartclient/default.aspx?pull=/library/en-us/dnwinforms/html/colorpicker.asp + // In Sano's article, the DragForm needs to meet the following criteria: + // (1) it was not to show up in the task bar; + // ShowInTaskBar = false + // (2) it needed to be the top-most window; + // TopMost = true + // (3) its icon could not show up in the ALT+TAB window if the user pressed ALT+TAB during a drag-and-drop; + // FormBorderStyle = FormBorderStyle.None; + // Create with WS_EX_TOOLWINDOW window style. + // Compares with the solution in the artile by setting FormBorderStyle as FixedToolWindow, + // and then clip the window caption and border, this way is much simplier. + // (4) it was not to steal focus from the application when displayed. + // User Win32 ShowWindow API with SW_SHOWNOACTIVATE + // In addition, this form should only for display and therefore should act as transparent, otherwise + // WindowFromPoint will return this form, instead of the control beneath. Need BOTH of the following to + // achieve this (don't know why, spent hours to try it out :( ): + // 1. Enabled = false; + // 2. WM_NCHITTEST returns HTTRANSPARENT + internal class DragForm : Form + { + public DragForm() + { + FormBorderStyle = FormBorderStyle.None; + ShowInTaskbar = false; + SetStyle(ControlStyles.Selectable, false); + Enabled = false; + TopMost = true; + } + + protected override CreateParams CreateParams + { + get + { + CreateParams createParams = base.CreateParams; + createParams.ExStyle |= (int)(Win32.WindowExStyles.WS_EX_NOACTIVATE | Win32.WindowExStyles.WS_EX_TOOLWINDOW); + return createParams; + } + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_NCHITTEST) + { + m.Result = (IntPtr)Win32.HitTest.HTTRANSPARENT; + return; + } + + base.WndProc(ref m); + } + //The form can be still activated by explicity calling Activate + protected override bool ShowWithoutActivation + { + get { return true; } + } + public virtual void Show(bool bActivate) + { + Show(); + + if (bActivate) + Activate(); + } + } +} diff --git a/WinFormsUI/Docking/DummyControl.cs b/WinFormsUI/Docking/DummyControl.cs new file mode 100644 index 0000000000..6c04ecd0b7 --- /dev/null +++ b/WinFormsUI/Docking/DummyControl.cs @@ -0,0 +1,13 @@ +using System; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal class DummyControl : Control + { + public DummyControl() + { + SetStyle(ControlStyles.Selectable, false); + } + } +} diff --git a/WinFormsUI/Docking/Enums.cs b/WinFormsUI/Docking/Enums.cs new file mode 100644 index 0000000000..36b076b229 --- /dev/null +++ b/WinFormsUI/Docking/Enums.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + [Flags] + [Serializable] + [Editor(typeof(DockAreasEditor), typeof(System.Drawing.Design.UITypeEditor))] + public enum DockAreas + { + Float = 1, + DockLeft = 2, + DockRight = 4, + DockTop = 8, + DockBottom = 16, + Document = 32 + } + + public enum DockState + { + Unknown = 0, + Float = 1, + DockTopAutoHide = 2, + DockLeftAutoHide = 3, + DockBottomAutoHide = 4, + DockRightAutoHide = 5, + Document = 6, + DockTop = 7, + DockLeft = 8, + DockBottom = 9, + DockRight = 10, + Hidden = 11 + } + + public enum DockAlignment + { + Left, + Right, + Top, + Bottom + } + + public enum DocumentStyle + { + DockingMdi, + DockingWindow, + DockingSdi, + SystemMdi, + } + + /// + /// The location to draw the DockPaneStrip for Document style windows. + /// + public enum DocumentTabStripLocation + { + Top, + Bottom + } +} diff --git a/WinFormsUI/Docking/FloatWindow.cs b/WinFormsUI/Docking/FloatWindow.cs new file mode 100644 index 0000000000..c032710099 --- /dev/null +++ b/WinFormsUI/Docking/FloatWindow.cs @@ -0,0 +1,482 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Diagnostics.CodeAnalysis; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class FloatWindow : Form, INestedPanesContainer, IDockDragSource + { + private NestedPaneCollection m_nestedPanes; + internal const int WM_CHECKDISPOSE = (int)(Win32.Msgs.WM_USER + 1); + + internal protected FloatWindow(DockPanel dockPanel, DockPane pane) + { + InternalConstruct(dockPanel, pane, false, Rectangle.Empty); + } + + internal protected FloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds) + { + InternalConstruct(dockPanel, pane, true, bounds); + } + + private void InternalConstruct(DockPanel dockPanel, DockPane pane, bool boundsSpecified, Rectangle bounds) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.FloatWindow_Constructor_NullDockPanel)); + + m_nestedPanes = new NestedPaneCollection(this); + + FormBorderStyle = FormBorderStyle.SizableToolWindow; + ShowInTaskbar = false; + if (dockPanel.RightToLeft != RightToLeft) + RightToLeft = dockPanel.RightToLeft; + if (RightToLeftLayout != dockPanel.RightToLeftLayout) + RightToLeftLayout = dockPanel.RightToLeftLayout; + + SuspendLayout(); + if (boundsSpecified) + { + Bounds = bounds; + StartPosition = FormStartPosition.Manual; + } + else + { + StartPosition = FormStartPosition.WindowsDefaultLocation; + Size = dockPanel.DefaultFloatWindowSize; + } + + m_dockPanel = dockPanel; + Owner = DockPanel.FindForm(); + DockPanel.AddFloatWindow(this); + if (pane != null) + pane.FloatWindow = this; + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (DockPanel != null) + DockPanel.RemoveFloatWindow(this); + m_dockPanel = null; + } + base.Dispose(disposing); + } + + private bool m_allowEndUserDocking = true; + public bool AllowEndUserDocking + { + get { return m_allowEndUserDocking; } + set { m_allowEndUserDocking = value; } + } + + private bool m_doubleClickTitleBarToDock = false; + public bool DoubleClickTitleBarToDock + { + get { return m_doubleClickTitleBarToDock; } + set { m_doubleClickTitleBarToDock = value; } + } + + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + public VisibleNestedPaneCollection VisibleNestedPanes + { + get { return NestedPanes.VisibleNestedPanes; } + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + public DockState DockState + { + get { return DockState.Float; } + } + + public bool IsFloat + { + get { return DockState == DockState.Float; } + } + + internal bool IsDockStateValid(DockState dockState) + { + foreach (DockPane pane in NestedPanes) + foreach (IDockContent content in pane.Contents) + if (!DockHelper.IsDockStateValid(dockState, content.DockHandler.DockAreas)) + return false; + + return true; + } + + protected override void OnActivated(EventArgs e) + { + DockPanel.FloatWindows.BringWindowToFront(this); + base.OnActivated (e); + // Propagate the Activated event to the visible panes content objects + foreach (DockPane pane in VisibleNestedPanes) + foreach (IDockContent content in pane.Contents) + content.OnActivated(e); + } + + protected override void OnDeactivate(EventArgs e) + { + base.OnDeactivate(e); + // Propagate the Deactivate event to the visible panes content objects + foreach (DockPane pane in VisibleNestedPanes) + foreach (IDockContent content in pane.Contents) + content.OnDeactivate(e); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + VisibleNestedPanes.Refresh(); + RefreshChanges(); + Visible = (VisibleNestedPanes.Count > 0); + SetText(); + + base.OnLayout(levent); + } + + + [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.Windows.Forms.Control.set_Text(System.String)")] + internal void SetText() + { + DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null; + + if (theOnlyPane == null || theOnlyPane.ActiveContent == null) + { + Text = " "; // use " " instead of string.Empty because the whole title bar will disappear when ControlBox is set to false. + Icon = null; + } + else + { + Text = theOnlyPane.ActiveContent.DockHandler.TabText; + Icon = theOnlyPane.ActiveContent.DockHandler.Icon; + } + } + + protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) + { + Rectangle rectWorkArea = SystemInformation.VirtualScreen; + + if (y + height > rectWorkArea.Bottom) + y -= (y + height) - rectWorkArea.Bottom; + + if (y < rectWorkArea.Top) + y += rectWorkArea.Top - y; + + base.SetBoundsCore (x, y, width, height, specified); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case (int)Win32.Msgs.WM_NCLBUTTONDOWN: + { + if (IsDisposed) + return; + + uint result = Win32Helper.IsRunningOnMono ? 0 : NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam); + if (result == 2 && DockPanel.AllowEndUserDocking && this.AllowEndUserDocking) // HITTEST_CAPTION + { + Activate(); + m_dockPanel.BeginDrag(this); + } + else + base.WndProc(ref m); + + return; + } + case (int)Win32.Msgs.WM_NCRBUTTONDOWN: + { + uint result = Win32Helper.IsRunningOnMono ? 0 : NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam); + if (result == 2) // HITTEST_CAPTION + { + DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null; + if (theOnlyPane != null && theOnlyPane.ActiveContent != null) + { + theOnlyPane.ShowTabPageContextMenu(this, PointToClient(Control.MousePosition)); + return; + } + } + + base.WndProc(ref m); + return; + } + case (int)Win32.Msgs.WM_CLOSE: + if (NestedPanes.Count == 0) + { + base.WndProc(ref m); + return; + } + for (int i = NestedPanes.Count - 1; i >= 0; i--) + { + DockContentCollection contents = NestedPanes[i].Contents; + for (int j = contents.Count - 1; j >= 0; j--) + { + IDockContent content = contents[j]; + if (content.DockHandler.DockState != DockState.Float) + continue; + + if (!content.DockHandler.CloseButton) + continue; + + if (content.DockHandler.HideOnClose) + content.DockHandler.Hide(); + else + content.DockHandler.Close(); + } + } + return; + case (int)Win32.Msgs.WM_NCLBUTTONDBLCLK: + { + uint result = !DoubleClickTitleBarToDock || Win32Helper.IsRunningOnMono + ? 0 + : NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam); + + if (result != 2) // HITTEST_CAPTION + { + base.WndProc(ref m); + return; + } + + DockPanel.SuspendLayout(true); + + // Restore to panel + foreach (DockPane pane in NestedPanes) + { + if (pane.DockState != DockState.Float) + continue; + pane.RestoreToPanel(); + } + + + DockPanel.ResumeLayout(true, true); + return; + } + case WM_CHECKDISPOSE: + if (NestedPanes.Count == 0) + Dispose(); + return; + } + + base.WndProc(ref m); + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + if (VisibleNestedPanes.Count == 0) + { + ControlBox = true; + return; + } + + for (int i=VisibleNestedPanes.Count - 1; i>=0; i--) + { + DockContentCollection contents = VisibleNestedPanes[i].Contents; + for (int j=contents.Count - 1; j>=0; j--) + { + IDockContent content = contents[j]; + if (content.DockHandler.DockState != DockState.Float) + continue; + + if (content.DockHandler.CloseButton && content.DockHandler.CloseButtonVisible) + { + ControlBox = true; + return; + } + } + } + //Only if there is a ControlBox do we turn it off + //old code caused a flash of the window. + if (ControlBox) + ControlBox = false; + } + + public virtual Rectangle DisplayingRectangle + { + get { return ClientRectangle; } + } + + internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline) + { + if (VisibleNestedPanes.Count == 1) + { + DockPane pane = VisibleNestedPanes[0]; + if (!dragSource.CanDockTo(pane)) + return; + + Point ptMouse = Control.MousePosition; + uint lParam = Win32Helper.MakeLong(ptMouse.X, ptMouse.Y); + if (!Win32Helper.IsRunningOnMono) + { + if (NativeMethods.SendMessage(Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, lParam) == (uint)Win32.HitTest.HTCAPTION) + { + dockOutline.Show(VisibleNestedPanes[0], -1); + } + } + } + } + + #region IDockDragSource Members + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + + bool IDockDragSource.IsDockStateValid(DockState dockState) + { + return IsDockStateValid(dockState); + } + + bool IDockDragSource.CanDockTo(DockPane pane) + { + if (!IsDockStateValid(pane.DockState)) + return false; + + if (pane.FloatWindow == this) + return false; + + return true; + } + + private int m_preDragExStyle; + + Rectangle IDockDragSource.BeginDrag(Point ptMouse) + { + m_preDragExStyle = NativeMethods.GetWindowLong(this.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE); + NativeMethods.SetWindowLong(this.Handle, + (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, + m_preDragExStyle | (int)(Win32.WindowExStyles.WS_EX_TRANSPARENT | Win32.WindowExStyles.WS_EX_LAYERED) ); + return Bounds; + } + + void IDockDragSource.EndDrag() + { + NativeMethods.SetWindowLong(this.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, m_preDragExStyle); + + Invalidate(true); + NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCPAINT, 1, 0); + } + + public void FloatAt(Rectangle floatWindowBounds) + { + Bounds = floatWindowBounds; + } + + public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex) + { + if (dockStyle == DockStyle.Fill) + { + for (int i = NestedPanes.Count - 1; i >= 0; i--) + { + DockPane paneFrom = NestedPanes[i]; + for (int j = paneFrom.Contents.Count - 1; j >= 0; j--) + { + IDockContent c = paneFrom.Contents[j]; + c.DockHandler.Pane = pane; + if (contentIndex != -1) + pane.SetContentIndex(c, contentIndex); + c.DockHandler.Activate(); + } + } + } + else + { + DockAlignment alignment = DockAlignment.Left; + if (dockStyle == DockStyle.Left) + alignment = DockAlignment.Left; + else if (dockStyle == DockStyle.Right) + alignment = DockAlignment.Right; + else if (dockStyle == DockStyle.Top) + alignment = DockAlignment.Top; + else if (dockStyle == DockStyle.Bottom) + alignment = DockAlignment.Bottom; + + MergeNestedPanes(VisibleNestedPanes, pane.NestedPanesContainer.NestedPanes, pane, alignment, 0.5); + } + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + if (panel != DockPanel) + throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel"); + + NestedPaneCollection nestedPanesTo = null; + + if (dockStyle == DockStyle.Top) + nestedPanesTo = DockPanel.DockWindows[DockState.DockTop].NestedPanes; + else if (dockStyle == DockStyle.Bottom) + nestedPanesTo = DockPanel.DockWindows[DockState.DockBottom].NestedPanes; + else if (dockStyle == DockStyle.Left) + nestedPanesTo = DockPanel.DockWindows[DockState.DockLeft].NestedPanes; + else if (dockStyle == DockStyle.Right) + nestedPanesTo = DockPanel.DockWindows[DockState.DockRight].NestedPanes; + else if (dockStyle == DockStyle.Fill) + nestedPanesTo = DockPanel.DockWindows[DockState.Document].NestedPanes; + + DockPane prevPane = null; + for (int i = nestedPanesTo.Count - 1; i >= 0; i--) + if (nestedPanesTo[i] != VisibleNestedPanes[0]) + prevPane = nestedPanesTo[i]; + MergeNestedPanes(VisibleNestedPanes, nestedPanesTo, prevPane, DockAlignment.Left, 0.5); + } + + private static void MergeNestedPanes(VisibleNestedPaneCollection nestedPanesFrom, NestedPaneCollection nestedPanesTo, DockPane prevPane, DockAlignment alignment, double proportion) + { + if (nestedPanesFrom.Count == 0) + return; + + int count = nestedPanesFrom.Count; + DockPane[] panes = new DockPane[count]; + DockPane[] prevPanes = new DockPane[count]; + DockAlignment[] alignments = new DockAlignment[count]; + double[] proportions = new double[count]; + + for (int i = 0; i < count; i++) + { + panes[i] = nestedPanesFrom[i]; + prevPanes[i] = nestedPanesFrom[i].NestedDockingStatus.PreviousPane; + alignments[i] = nestedPanesFrom[i].NestedDockingStatus.Alignment; + proportions[i] = nestedPanesFrom[i].NestedDockingStatus.Proportion; + } + + DockPane pane = panes[0].DockTo(nestedPanesTo.Container, prevPane, alignment, proportion); + panes[0].DockState = nestedPanesTo.DockState; + + for (int i = 1; i < count; i++) + { + for (int j = i; j < count; j++) + { + if (prevPanes[j] == panes[i - 1]) + prevPanes[j] = pane; + } + pane = panes[i].DockTo(nestedPanesTo.Container, prevPanes[i], alignments[i], proportions[i]); + panes[i].DockState = nestedPanesTo.DockState; + } + } + + #endregion + } +} diff --git a/WinFormsUI/Docking/FloatWindowCollection.cs b/WinFormsUI/Docking/FloatWindowCollection.cs new file mode 100644 index 0000000000..e0fd0b68c6 --- /dev/null +++ b/WinFormsUI/Docking/FloatWindowCollection.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public class FloatWindowCollection : ReadOnlyCollection + { + internal FloatWindowCollection() + : base(new List()) + { + } + + internal int Add(FloatWindow fw) + { + if (Items.Contains(fw)) + return Items.IndexOf(fw); + + Items.Add(fw); + return Count - 1; + } + + internal void Dispose() + { + for (int i=Count - 1; i>=0; i--) + this[i].Close(); + } + + internal void Remove(FloatWindow fw) + { + Items.Remove(fw); + } + + internal void BringWindowToFront(FloatWindow fw) + { + Items.Remove(fw); + Items.Add(fw); + } + } +} diff --git a/WinFormsUI/Docking/Helpers/DockHelper.cs b/WinFormsUI/Docking/Helpers/DockHelper.cs new file mode 100644 index 0000000000..d5b59d8a38 --- /dev/null +++ b/WinFormsUI/Docking/Helpers/DockHelper.cs @@ -0,0 +1,105 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal static class DockHelper + { + public static bool IsDockStateAutoHide(DockState dockState) + { + if (dockState == DockState.DockLeftAutoHide || + dockState == DockState.DockRightAutoHide || + dockState == DockState.DockTopAutoHide || + dockState == DockState.DockBottomAutoHide) + return true; + else + return false; + } + + public static bool IsDockStateValid(DockState dockState, DockAreas dockableAreas) + { + if (((dockableAreas & DockAreas.Float) == 0) && + (dockState == DockState.Float)) + return false; + else if (((dockableAreas & DockAreas.Document) == 0) && + (dockState == DockState.Document)) + return false; + else if (((dockableAreas & DockAreas.DockLeft) == 0) && + (dockState == DockState.DockLeft || dockState == DockState.DockLeftAutoHide)) + return false; + else if (((dockableAreas & DockAreas.DockRight) == 0) && + (dockState == DockState.DockRight || dockState == DockState.DockRightAutoHide)) + return false; + else if (((dockableAreas & DockAreas.DockTop) == 0) && + (dockState == DockState.DockTop || dockState == DockState.DockTopAutoHide)) + return false; + else if (((dockableAreas & DockAreas.DockBottom) == 0) && + (dockState == DockState.DockBottom || dockState == DockState.DockBottomAutoHide)) + return false; + else + return true; + } + + public static bool IsDockWindowState(DockState state) + { + if (state == DockState.DockTop || state == DockState.DockBottom || state == DockState.DockLeft || + state == DockState.DockRight || state == DockState.Document) + return true; + else + return false; + } + + public static DockState ToggleAutoHideState(DockState state) + { + if (state == DockState.DockLeft) + return DockState.DockLeftAutoHide; + else if (state == DockState.DockRight) + return DockState.DockRightAutoHide; + else if (state == DockState.DockTop) + return DockState.DockTopAutoHide; + else if (state == DockState.DockBottom) + return DockState.DockBottomAutoHide; + else if (state == DockState.DockLeftAutoHide) + return DockState.DockLeft; + else if (state == DockState.DockRightAutoHide) + return DockState.DockRight; + else if (state == DockState.DockTopAutoHide) + return DockState.DockTop; + else if (state == DockState.DockBottomAutoHide) + return DockState.DockBottom; + else + return state; + } + + public static DockPane PaneAtPoint(Point pt, DockPanel dockPanel) + { + if (!Win32Helper.IsRunningOnMono) + for (Control control = Win32Helper.ControlAtPoint(pt); control != null; control = control.Parent) + { + IDockContent content = control as IDockContent; + if (content != null && content.DockHandler.DockPanel == dockPanel) + return content.DockHandler.Pane; + + DockPane pane = control as DockPane; + if (pane != null && pane.DockPanel == dockPanel) + return pane; + } + + return null; + } + + public static FloatWindow FloatWindowAtPoint(Point pt, DockPanel dockPanel) + { + if (!Win32Helper.IsRunningOnMono) + for (Control control = Win32Helper.ControlAtPoint(pt); control != null; control = control.Parent) + { + FloatWindow floatWindow = control as FloatWindow; + if (floatWindow != null && floatWindow.DockPanel == dockPanel) + return floatWindow; + } + + return null; + } + } +} diff --git a/WinFormsUI/Docking/Helpers/DrawHelper.cs b/WinFormsUI/Docking/Helpers/DrawHelper.cs new file mode 100644 index 0000000000..d92fbbdc71 --- /dev/null +++ b/WinFormsUI/Docking/Helpers/DrawHelper.cs @@ -0,0 +1,88 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal static class DrawHelper + { + public static Point RtlTransform(Control control, Point point) + { + if (control.RightToLeft != RightToLeft.Yes) + return point; + else + return new Point(control.Right - point.X, point.Y); + } + + public static Rectangle RtlTransform(Control control, Rectangle rectangle) + { + if (control.RightToLeft != RightToLeft.Yes) + return rectangle; + else + return new Rectangle(control.ClientRectangle.Right - rectangle.Right, rectangle.Y, rectangle.Width, rectangle.Height); + } + + public static GraphicsPath GetRoundedCornerTab(GraphicsPath graphicsPath, Rectangle rect, bool upCorner) + { + if (graphicsPath == null) + graphicsPath = new GraphicsPath(); + else + graphicsPath.Reset(); + + int curveSize = 6; + if (upCorner) + { + graphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Top + curveSize / 2); + graphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); + graphicsPath.AddLine(rect.Left + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top); + graphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90); + graphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom); + } + else + { + graphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Bottom - curveSize / 2); + graphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom - curveSize, curveSize, curveSize), 0, 90); + graphicsPath.AddLine(rect.Right - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom); + graphicsPath.AddArc(new Rectangle(rect.Left, rect.Bottom - curveSize, curveSize, curveSize), 90, 90); + graphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top); + } + + return graphicsPath; + } + + public static GraphicsPath CalculateGraphicsPathFromBitmap(Bitmap bitmap) + { + return CalculateGraphicsPathFromBitmap(bitmap, Color.Empty); + } + + // From http://edu.cnzz.cn/show_3281.html + public static GraphicsPath CalculateGraphicsPathFromBitmap(Bitmap bitmap, Color colorTransparent) + { + GraphicsPath graphicsPath = new GraphicsPath(); + if (colorTransparent == Color.Empty) + colorTransparent = bitmap.GetPixel(0, 0); + + for(int row = 0; row < bitmap.Height; row ++) + { + int colOpaquePixel = 0; + for(int col = 0; col < bitmap.Width; col ++) + { + if(bitmap.GetPixel(col, row) != colorTransparent) + { + colOpaquePixel = col; + int colNext = col; + for(colNext = colOpaquePixel; colNext < bitmap.Width; colNext ++) + if(bitmap.GetPixel(colNext, row) == colorTransparent) + break; + + graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1)); + col = colNext; + } + } + } + return graphicsPath; + } + } +} diff --git a/WinFormsUI/Docking/Helpers/ResourceHelper.cs b/WinFormsUI/Docking/Helpers/ResourceHelper.cs new file mode 100644 index 0000000000..5620908afb --- /dev/null +++ b/WinFormsUI/Docking/Helpers/ResourceHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.Drawing; +using System.Reflection; +using System.Resources; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal static class ResourceHelper + { + private static ResourceManager _resourceManager = null; + + private static ResourceManager ResourceManager + { + get + { + if (_resourceManager == null) + _resourceManager = new ResourceManager("WeifenLuo.WinFormsUI.Docking.Strings", typeof(ResourceHelper).Assembly); + return _resourceManager; + } + + } + + public static string GetString(string name) + { + return ResourceManager.GetString(name); + } + } +} diff --git a/WinFormsUI/Docking/Helpers/Win32Helper.cs b/WinFormsUI/Docking/Helpers/Win32Helper.cs new file mode 100644 index 0000000000..a5d467c1c2 --- /dev/null +++ b/WinFormsUI/Docking/Helpers/Win32Helper.cs @@ -0,0 +1,23 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public static class Win32Helper + { + private static readonly bool _isRunningOnMono = Type.GetType("Mono.Runtime") != null; + + public static bool IsRunningOnMono { get { return _isRunningOnMono; } } + + internal static Control ControlAtPoint(Point pt) + { + return Control.FromChildHandle(NativeMethods.WindowFromPoint(pt)); + } + + internal static uint MakeLong(int low, int high) + { + return (uint)((high << 16) + low); + } + } +} diff --git a/WinFormsUI/Docking/InertButtonBase.cs b/WinFormsUI/Docking/InertButtonBase.cs new file mode 100644 index 0000000000..92d5731d71 --- /dev/null +++ b/WinFormsUI/Docking/InertButtonBase.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Imaging; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal abstract class InertButtonBase : Control + { + protected InertButtonBase() + { + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + BackColor = Color.Transparent; + } + + public abstract Bitmap Image + { + get; + } + + private bool m_isMouseOver = false; + protected bool IsMouseOver + { + get { return m_isMouseOver; } + private set + { + if (m_isMouseOver == value) + return; + + m_isMouseOver = value; + Invalidate(); + } + } + + protected override Size DefaultSize + { + get { return Resources.DockPane_Close.Size; } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + bool over = ClientRectangle.Contains(e.X, e.Y); + if (IsMouseOver != over) + IsMouseOver = over; + } + + protected override void OnMouseEnter(EventArgs e) + { + base.OnMouseEnter(e); + if (!IsMouseOver) + IsMouseOver = true; + } + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + if (IsMouseOver) + IsMouseOver = false; + } + + protected override void OnPaint(PaintEventArgs e) + { + if (IsMouseOver && Enabled) + { + using (Pen pen = new Pen(ForeColor)) + { + e.Graphics.DrawRectangle(pen, Rectangle.Inflate(ClientRectangle, -1, -1)); + } + } + + using (ImageAttributes imageAttributes = new ImageAttributes()) + { + ColorMap[] colorMap = new ColorMap[2]; + colorMap[0] = new ColorMap(); + colorMap[0].OldColor = Color.FromArgb(0, 0, 0); + colorMap[0].NewColor = ForeColor; + colorMap[1] = new ColorMap(); + colorMap[1].OldColor = Image.GetPixel(0, 0); + colorMap[1].NewColor = Color.Transparent; + + imageAttributes.SetRemapTable(colorMap); + + e.Graphics.DrawImage( + Image, + new Rectangle(0, 0, Image.Width, Image.Height), + 0, 0, + Image.Width, + Image.Height, + GraphicsUnit.Pixel, + imageAttributes); + } + + base.OnPaint(e); + } + + public void RefreshChanges() + { + if (IsDisposed) + return; + + bool mouseOver = ClientRectangle.Contains(PointToClient(Control.MousePosition)); + if (mouseOver != IsMouseOver) + IsMouseOver = mouseOver; + + OnRefreshChanges(); + } + + protected virtual void OnRefreshChanges() + { + } + } +} diff --git a/WinFormsUI/Docking/Interfaces.cs b/WinFormsUI/Docking/Interfaces.cs new file mode 100644 index 0000000000..91bdc0b859 --- /dev/null +++ b/WinFormsUI/Docking/Interfaces.cs @@ -0,0 +1,47 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public interface IDockContent + { + DockContentHandler DockHandler { get; } + void OnActivated(EventArgs e); + void OnDeactivate(EventArgs e); + } + + public interface INestedPanesContainer + { + DockState DockState { get; } + Rectangle DisplayingRectangle { get; } + NestedPaneCollection NestedPanes { get; } + VisibleNestedPaneCollection VisibleNestedPanes { get; } + bool IsFloat { get; } + } + + internal interface IDragSource + { + Control DragControl { get; } + } + + internal interface IDockDragSource : IDragSource + { + Rectangle BeginDrag(Point ptMouse); + void EndDrag(); + bool IsDockStateValid(DockState dockState); + bool CanDockTo(DockPane pane); + void FloatAt(Rectangle floatWindowBounds); + void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex); + void DockTo(DockPanel panel, DockStyle dockStyle); + } + + internal interface ISplitterDragSource : IDragSource + { + void BeginDrag(Rectangle rectSplitter); + void EndDrag(); + bool IsVertical { get; } + Rectangle DragLimitBounds { get; } + void MoveSplitter(int offset); + } +} diff --git a/WinFormsUI/Docking/Localization.cs b/WinFormsUI/Docking/Localization.cs new file mode 100644 index 0000000000..bfe73db283 --- /dev/null +++ b/WinFormsUI/Docking/Localization.cs @@ -0,0 +1,46 @@ +using System; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + [AttributeUsage(AttributeTargets.All)] + internal sealed class LocalizedDescriptionAttribute : DescriptionAttribute + { + private bool m_initialized = false; + + public LocalizedDescriptionAttribute(string key) : base(key) + { + } + + public override string Description + { + get + { + if (!m_initialized) + { + string key = base.Description; + DescriptionValue = ResourceHelper.GetString(key); + if (DescriptionValue == null) + DescriptionValue = String.Empty; + + m_initialized = true; + } + + return DescriptionValue; + } + } + } + + [AttributeUsage(AttributeTargets.All)] + internal sealed class LocalizedCategoryAttribute : CategoryAttribute + { + public LocalizedCategoryAttribute(string key) : base(key) + { + } + + protected override string GetLocalizedString(string key) + { + return ResourceHelper.GetString(key); + } + } +} diff --git a/WinFormsUI/Docking/Measures.cs b/WinFormsUI/Docking/Measures.cs new file mode 100644 index 0000000000..e1afb14d89 --- /dev/null +++ b/WinFormsUI/Docking/Measures.cs @@ -0,0 +1,14 @@ +using System; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal static class Measures + { + public const int SplitterSize = 4; + } + + internal static class MeasurePane + { + public const int MinSize = 24; + } +} diff --git a/WinFormsUI/Docking/NestedDockingStatus.cs b/WinFormsUI/Docking/NestedDockingStatus.cs new file mode 100644 index 0000000000..717e194d9f --- /dev/null +++ b/WinFormsUI/Docking/NestedDockingStatus.cs @@ -0,0 +1,108 @@ +using System; +using System.Drawing; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public sealed class NestedDockingStatus + { + internal NestedDockingStatus(DockPane pane) + { + m_dockPane = pane; + } + + private DockPane m_dockPane = null; + public DockPane DockPane + { + get { return m_dockPane; } + } + + private NestedPaneCollection m_nestedPanes = null; + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + private DockPane m_previousPane = null; + public DockPane PreviousPane + { + get { return m_previousPane; } + } + + private DockAlignment m_alignment = DockAlignment.Left; + public DockAlignment Alignment + { + get { return m_alignment; } + } + + private double m_proportion = 0.5; + public double Proportion + { + get { return m_proportion; } + } + + private bool m_isDisplaying = false; + public bool IsDisplaying + { + get { return m_isDisplaying; } + } + + private DockPane m_displayingPreviousPane = null; + public DockPane DisplayingPreviousPane + { + get { return m_displayingPreviousPane; } + } + + private DockAlignment m_displayingAlignment = DockAlignment.Left; + public DockAlignment DisplayingAlignment + { + get { return m_displayingAlignment; } + } + + private double m_displayingProportion = 0.5; + public double DisplayingProportion + { + get { return m_displayingProportion; } + } + + private Rectangle m_logicalBounds = Rectangle.Empty; + public Rectangle LogicalBounds + { + get { return m_logicalBounds; } + } + + private Rectangle m_paneBounds = Rectangle.Empty; + public Rectangle PaneBounds + { + get { return m_paneBounds; } + } + + private Rectangle m_splitterBounds = Rectangle.Empty; + public Rectangle SplitterBounds + { + get { return m_splitterBounds; } + } + + internal void SetStatus(NestedPaneCollection nestedPanes, DockPane previousPane, DockAlignment alignment, double proportion) + { + m_nestedPanes = nestedPanes; + m_previousPane = previousPane; + m_alignment = alignment; + m_proportion = proportion; + } + + internal void SetDisplayingStatus(bool isDisplaying, DockPane displayingPreviousPane, DockAlignment displayingAlignment, double displayingProportion) + { + m_isDisplaying = isDisplaying; + m_displayingPreviousPane = displayingPreviousPane; + m_displayingAlignment = displayingAlignment; + m_displayingProportion = displayingProportion; + } + + internal void SetDisplayingBounds(Rectangle logicalBounds, Rectangle paneBounds, Rectangle splitterBounds) + { + m_logicalBounds = logicalBounds; + m_paneBounds = paneBounds; + m_splitterBounds = splitterBounds; + } + } +} diff --git a/WinFormsUI/Docking/NestedPaneCollection.cs b/WinFormsUI/Docking/NestedPaneCollection.cs new file mode 100644 index 0000000000..7e425756ab --- /dev/null +++ b/WinFormsUI/Docking/NestedPaneCollection.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public sealed class NestedPaneCollection : ReadOnlyCollection + { + private INestedPanesContainer m_container; + private VisibleNestedPaneCollection m_visibleNestedPanes; + + internal NestedPaneCollection(INestedPanesContainer container) + : base(new List()) + { + m_container = container; + m_visibleNestedPanes = new VisibleNestedPaneCollection(this); + } + + public INestedPanesContainer Container + { + get { return m_container; } + } + + public VisibleNestedPaneCollection VisibleNestedPanes + { + get { return m_visibleNestedPanes; } + } + + public DockState DockState + { + get { return Container.DockState; } + } + + public bool IsFloat + { + get { return DockState == DockState.Float; } + } + + internal void Add(DockPane pane) + { + if (pane == null) + return; + + NestedPaneCollection oldNestedPanes = (pane.NestedPanesContainer == null) ? null : pane.NestedPanesContainer.NestedPanes; + if (oldNestedPanes != null) + oldNestedPanes.InternalRemove(pane); + Items.Add(pane); + if (oldNestedPanes != null) + oldNestedPanes.CheckFloatWindowDispose(); + } + + private void CheckFloatWindowDispose() + { + if (Count != 0 || Container.DockState != DockState.Float) + return; + + FloatWindow floatWindow = (FloatWindow)Container; + if (floatWindow.Disposing || floatWindow.IsDisposed) + return; + + if (Win32Helper.IsRunningOnMono) + return; + + NativeMethods.PostMessage(((FloatWindow)Container).Handle, FloatWindow.WM_CHECKDISPOSE, 0, 0); + } + + /// + /// Switches a pane with its first child in the pane hierarchy. (The actual hiding happens elsewhere.) + /// + /// Pane to switch + internal void SwitchPaneWithFirstChild(DockPane pane) + { + if (!Contains(pane)) + return; + + NestedDockingStatus statusPane = pane.NestedDockingStatus; + DockPane lastNestedPane = null; + for (int i = Count - 1; i > IndexOf(pane); i--) + { + if (this[i].NestedDockingStatus.PreviousPane == pane) + { + lastNestedPane = this[i]; + break; + } + } + + if (lastNestedPane != null) + { + int indexLastNestedPane = IndexOf(lastNestedPane); + Items[IndexOf(pane)] = lastNestedPane; + Items[indexLastNestedPane] = pane; + NestedDockingStatus lastNestedDock = lastNestedPane.NestedDockingStatus; + + DockAlignment newAlignment; + if (lastNestedDock.Alignment == DockAlignment.Left) + newAlignment = DockAlignment.Right; + else if (lastNestedDock.Alignment == DockAlignment.Right) + newAlignment = DockAlignment.Left; + else if (lastNestedDock.Alignment == DockAlignment.Top) + newAlignment = DockAlignment.Bottom; + else + newAlignment = DockAlignment.Top; + double newProportion = 1 - lastNestedDock.Proportion; + + lastNestedDock.SetStatus(this, statusPane.PreviousPane, statusPane.Alignment, statusPane.Proportion); + for (int i = indexLastNestedPane - 1; i > IndexOf(lastNestedPane); i--) + { + NestedDockingStatus status = this[i].NestedDockingStatus; + if (status.PreviousPane == pane) + status.SetStatus(this, lastNestedPane, status.Alignment, status.Proportion); + } + + statusPane.SetStatus(this, lastNestedPane, newAlignment, newProportion); + } + } + + internal void Remove(DockPane pane) + { + InternalRemove(pane); + CheckFloatWindowDispose(); + } + + private void InternalRemove(DockPane pane) + { + if (!Contains(pane)) + return; + + NestedDockingStatus statusPane = pane.NestedDockingStatus; + DockPane lastNestedPane = null; + for (int i=Count - 1; i> IndexOf(pane); i--) + { + if (this[i].NestedDockingStatus.PreviousPane == pane) + { + lastNestedPane = this[i]; + break; + } + } + + if (lastNestedPane != null) + { + int indexLastNestedPane = IndexOf(lastNestedPane); + Items.Remove(lastNestedPane); + Items[IndexOf(pane)] = lastNestedPane; + NestedDockingStatus lastNestedDock = lastNestedPane.NestedDockingStatus; + lastNestedDock.SetStatus(this, statusPane.PreviousPane, statusPane.Alignment, statusPane.Proportion); + for (int i=indexLastNestedPane - 1; i>IndexOf(lastNestedPane); i--) + { + NestedDockingStatus status = this[i].NestedDockingStatus; + if (status.PreviousPane == pane) + status.SetStatus(this, lastNestedPane, status.Alignment, status.Proportion); + } + } + else + Items.Remove(pane); + + statusPane.SetStatus(null, null, DockAlignment.Left, 0.5); + statusPane.SetDisplayingStatus(false, null, DockAlignment.Left, 0.5); + statusPane.SetDisplayingBounds(Rectangle.Empty, Rectangle.Empty, Rectangle.Empty); + } + + public DockPane GetDefaultPreviousPane(DockPane pane) + { + for (int i=Count-1; i>=0; i--) + if (this[i] != pane) + return this[i]; + + return null; + } + } +} diff --git a/WinFormsUI/Docking/Resources.Designer.cs b/WinFormsUI/Docking/Resources.Designer.cs new file mode 100644 index 0000000000..59dc959084 --- /dev/null +++ b/WinFormsUI/Docking/Resources.Designer.cs @@ -0,0 +1,224 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4952 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WeifenLuo.WinFormsUI.Docking { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WeifenLuo.WinFormsUI.Docking.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Bottom { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Bottom", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Fill { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Fill", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_HotSpot { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_HotSpot", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_HotSpotIndex { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_HotSpotIndex", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Left { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Left", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Right { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Right", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Top { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Top", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelBottom { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelBottom", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelBottom_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelBottom_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelFill { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelFill", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelFill_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelFill_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelLeft { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelLeft", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelLeft_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelLeft_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelRight { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelRight", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelRight_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelRight_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelTop { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelTop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelTop_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelTop_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_AutoHide { + get { + object obj = ResourceManager.GetObject("DockPane_AutoHide", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_Close { + get { + object obj = ResourceManager.GetObject("DockPane_Close", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_Dock { + get { + object obj = ResourceManager.GetObject("DockPane_Dock", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_Option { + get { + object obj = ResourceManager.GetObject("DockPane_Option", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_OptionOverflow { + get { + object obj = ResourceManager.GetObject("DockPane_OptionOverflow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/WinFormsUI/Docking/Resources.resx b/WinFormsUI/Docking/Resources.resx new file mode 100644 index 0000000000..c92c94f500 --- /dev/null +++ b/WinFormsUI/Docking/Resources.resx @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\DockIndicator_PaneDiamond.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Bottom.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\Dockindicator_PaneDiamond_Fill.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Hotspot.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_HotspotIndex.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Left.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Right.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Top.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelBottom.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelBottom_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelFill.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelFill_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelLeft.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelLeft_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelRight.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelRight_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelTop.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelTop_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_AutoHide.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_Close.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_Dock.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_Option.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_OptionOverflow.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond.bmp new file mode 100644 index 0000000000..70e70e288d Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Bottom.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Bottom.bmp new file mode 100644 index 0000000000..d95ec69720 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Bottom.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Hotspot.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Hotspot.bmp new file mode 100644 index 0000000000..e801d382d7 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Hotspot.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_HotspotIndex.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_HotspotIndex.bmp new file mode 100644 index 0000000000..e5ef472c56 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_HotspotIndex.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Left.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Left.bmp new file mode 100644 index 0000000000..1fbda61c08 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Left.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Right.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Right.bmp new file mode 100644 index 0000000000..1de97a0986 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Right.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Top.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Top.bmp new file mode 100644 index 0000000000..95122a0f31 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PaneDiamond_Top.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelBottom.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelBottom.bmp new file mode 100644 index 0000000000..ad851ea183 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelBottom.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelBottom_Active.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelBottom_Active.bmp new file mode 100644 index 0000000000..212fb0d366 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelBottom_Active.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelFill.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelFill.bmp new file mode 100644 index 0000000000..21a1b274d7 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelFill.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelFill_Active.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelFill_Active.bmp new file mode 100644 index 0000000000..d58b00f9df Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelFill_Active.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelLeft.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelLeft.bmp new file mode 100644 index 0000000000..f6cdce04c0 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelLeft.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelLeft_Active.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelLeft_Active.bmp new file mode 100644 index 0000000000..d6843f844d Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelLeft_Active.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelRight.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelRight.bmp new file mode 100644 index 0000000000..b5d80a7278 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelRight.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelRight_Active.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelRight_Active.bmp new file mode 100644 index 0000000000..9bd4bc04db Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelRight_Active.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelTop.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelTop.bmp new file mode 100644 index 0000000000..f6293fd2bc Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelTop.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockIndicator_PanelTop_Active.bmp b/WinFormsUI/Docking/Resources/DockIndicator_PanelTop_Active.bmp new file mode 100644 index 0000000000..563549eba1 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockIndicator_PanelTop_Active.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockPane_AutoHide.bmp b/WinFormsUI/Docking/Resources/DockPane_AutoHide.bmp new file mode 100644 index 0000000000..2f395fc010 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockPane_AutoHide.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockPane_Close.bmp b/WinFormsUI/Docking/Resources/DockPane_Close.bmp new file mode 100644 index 0000000000..a7748a672e Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockPane_Close.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockPane_Dock.bmp b/WinFormsUI/Docking/Resources/DockPane_Dock.bmp new file mode 100644 index 0000000000..6a9d145e09 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockPane_Dock.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockPane_Option.bmp b/WinFormsUI/Docking/Resources/DockPane_Option.bmp new file mode 100644 index 0000000000..0d9927a7ce Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockPane_Option.bmp differ diff --git a/WinFormsUI/Docking/Resources/DockPane_OptionOverflow.bmp b/WinFormsUI/Docking/Resources/DockPane_OptionOverflow.bmp new file mode 100644 index 0000000000..02e4bf2905 Binary files /dev/null and b/WinFormsUI/Docking/Resources/DockPane_OptionOverflow.bmp differ diff --git a/WinFormsUI/Docking/Resources/Dockindicator_PaneDiamond_Fill.bmp b/WinFormsUI/Docking/Resources/Dockindicator_PaneDiamond_Fill.bmp new file mode 100644 index 0000000000..cbe0a156ab Binary files /dev/null and b/WinFormsUI/Docking/Resources/Dockindicator_PaneDiamond_Fill.bmp differ diff --git a/WinFormsUI/Docking/Skins/DockPanelSkinBuilder.cs b/WinFormsUI/Docking/Skins/DockPanelSkinBuilder.cs new file mode 100644 index 0000000000..b9ec114123 --- /dev/null +++ b/WinFormsUI/Docking/Skins/DockPanelSkinBuilder.cs @@ -0,0 +1,57 @@ +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace WeifenLuo.WinFormsUI.Docking.Skins +{ + internal static class DockPanelSkinBuilder + { + public static DockPanelSkin Create(Style style) + { + switch (style) + { + case Style.VisualStudio2005: + default: + return CreateVisualStudio2005(); + } + } + + private static DockPanelSkin CreateVisualStudio2005() + { + DockPanelSkin skin = new DockPanelSkin(); + + skin.AutoHideStripSkin.DockStripGradient.StartColor = SystemColors.ControlLight; + skin.AutoHideStripSkin.DockStripGradient.EndColor = SystemColors.ControlLight; + skin.AutoHideStripSkin.TabGradient.TextColor = SystemColors.ControlDarkDark; + + skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.StartColor = SystemColors.Control; + skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.EndColor = SystemColors.Control; + skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.StartColor = SystemColors.ControlLightLight; + skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.EndColor = SystemColors.ControlLightLight; + skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.StartColor = SystemColors.ControlLight; + skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.EndColor = SystemColors.ControlLight; + + skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.StartColor = SystemColors.ControlLight; + skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.EndColor = SystemColors.ControlLight; + + skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor = SystemColors.Control; + skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor = SystemColors.Control; + + skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor = Color.Transparent; + skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor = Color.Transparent; + skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor = SystemColors.ControlDarkDark; + + skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.StartColor = SystemColors.GradientActiveCaption; + skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.EndColor = SystemColors.ActiveCaption; + skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.LinearGradientMode = LinearGradientMode.Vertical; + skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor = SystemColors.ActiveCaptionText; + + skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.StartColor = SystemColors.GradientInactiveCaption; + skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.EndColor = SystemColors.InactiveCaption; + skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.LinearGradientMode = LinearGradientMode.Vertical; + skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor = SystemColors.InactiveCaptionText; + + return skin; + } + + } +} diff --git a/WinFormsUI/Docking/Skins/Style.cs b/WinFormsUI/Docking/Skins/Style.cs new file mode 100644 index 0000000000..ba75b14fcc --- /dev/null +++ b/WinFormsUI/Docking/Skins/Style.cs @@ -0,0 +1,7 @@ +namespace WeifenLuo.WinFormsUI.Docking.Skins +{ + public enum Style + { + VisualStudio2005 = 1 + } +} diff --git a/WinFormsUI/Docking/SplitterBase.cs b/WinFormsUI/Docking/SplitterBase.cs new file mode 100644 index 0000000000..78448ea987 --- /dev/null +++ b/WinFormsUI/Docking/SplitterBase.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal class SplitterBase : Control + { + public SplitterBase() + { + SetStyle(ControlStyles.Selectable, false); + } + + public override DockStyle Dock + { + get { return base.Dock; } + set + { + SuspendLayout(); + base.Dock = value; + + if (Dock == DockStyle.Left || Dock == DockStyle.Right) + Width = SplitterSize; + else if (Dock == DockStyle.Top || Dock == DockStyle.Bottom) + Height = SplitterSize; + else + Bounds = Rectangle.Empty; + + if (Dock == DockStyle.Left || Dock == DockStyle.Right) + Cursor = Cursors.VSplit; + else if (Dock == DockStyle.Top || Dock == DockStyle.Bottom) + Cursor = Cursors.HSplit; + else + Cursor = Cursors.Default; + + ResumeLayout(); + } + } + + protected virtual int SplitterSize + { + get { return 0; } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button != MouseButtons.Left) + return; + + StartDrag(); + } + + protected virtual void StartDrag() + { + } + + protected override void WndProc(ref Message m) + { + // eat the WM_MOUSEACTIVATE message + if (m.Msg == (int)Win32.Msgs.WM_MOUSEACTIVATE) + return; + + base.WndProc(ref m); + } + } +} diff --git a/WinFormsUI/Docking/Strings.Designer.cs b/WinFormsUI/Docking/Strings.Designer.cs new file mode 100644 index 0000000000..9a4acad983 --- /dev/null +++ b/WinFormsUI/Docking/Strings.Designer.cs @@ -0,0 +1,819 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18033 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WeifenLuo.WinFormsUI.Docking { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WeifenLuo.WinFormsUI.Docking.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Docking. + /// + internal static string Category_Docking { + get { + return ResourceManager.GetString("Category_Docking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Docking Notification. + /// + internal static string Category_DockingNotification { + get { + return ResourceManager.GetString("Category_DockingNotification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance. + /// + internal static string Category_Performance { + get { + return ResourceManager.GetString("Category_Performance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Property Changed. + /// + internal static string Category_PropertyChanged { + get { + return ResourceManager.GetString("Category_PropertyChanged", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (Float). + /// + internal static string DockAreaEditor_FloatCheckBoxText { + get { + return ResourceManager.GetString("DockAreaEditor_FloatCheckBoxText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if end user drag and drop docking is allowed.. + /// + internal static string DockContent_AllowEndUserDocking_Description { + get { + return ResourceManager.GetString("DockContent_AllowEndUserDocking_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The size to display the content in auto hide mode. Value < 1 to specify the size in portion; value >= 1 to specify the size in pixel.. + /// + internal static string DockContent_AutoHidePortion_Description { + get { + return ResourceManager.GetString("DockContent_AutoHidePortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable/Disable the close button of the content.. + /// + internal static string DockContent_CloseButton_Description { + get { + return ResourceManager.GetString("DockContent_CloseButton_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows or hides the close button of the content. This property does not function with System MDI Document Style.. + /// + internal static string DockContent_CloseButtonVisible_Description { + get { + return ResourceManager.GetString("DockContent_CloseButtonVisible_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The form must be of type IDockContent.. + /// + internal static string DockContent_Constructor_InvalidForm { + get { + return ResourceManager.GetString("DockContent_Constructor_InvalidForm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gets or sets a value indicating in which area of the DockPanel the content allowed to show.. + /// + internal static string DockContent_DockAreas_Description { + get { + return ResourceManager.GetString("DockContent_DockAreas_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of DockState property changed.. + /// + internal static string DockContent_DockStateChanged_Description { + get { + return ResourceManager.GetString("DockContent_DockStateChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indicates the content will be hidden instead of being closed.. + /// + internal static string DockContent_HideOnClose_Description { + get { + return ResourceManager.GetString("DockContent_HideOnClose_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The desired docking state when first showing.. + /// + internal static string DockContent_ShowHint_Description { + get { + return ResourceManager.GetString("DockContent_ShowHint_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Context menu displayed for the dock pane tab strip.. + /// + internal static string DockContent_TabPageContextMenu_Description { + get { + return ResourceManager.GetString("DockContent_TabPageContextMenu_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tab text displayed in the dock pane. If not set, the Text property will be used.. + /// + internal static string DockContent_TabText_Description { + get { + return ResourceManager.GetString("DockContent_TabText_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The text displayed when mouse hovers over the tab.. + /// + internal static string DockContent_ToolTipText_Description { + get { + return ResourceManager.GetString("DockContent_ToolTipText_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The provided value is out of range.. + /// + internal static string DockContentHandler_AutoHidePortion_OutOfRange { + get { + return ResourceManager.GetString("DockContentHandler_AutoHidePortion_OutOfRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Value: The value of DockAreas conflicts with current DockState.. + /// + internal static string DockContentHandler_DockAreas_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_DockAreas_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane.. + /// + internal static string DockContentHandler_DockPane_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_DockPane_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane.. + /// + internal static string DockContentHandler_FloatPane_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_FloatPane_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value, conflicts with DockableAreas property.. + /// + internal static string DockContentHandler_IsFloat_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_IsFloat_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The dock state is invalid.. + /// + internal static string DockContentHandler_SetDockState_InvalidState { + get { + return ResourceManager.GetString("DockContentHandler_SetDockState_InvalidState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The dock panel is null.. + /// + internal static string DockContentHandler_SetDockState_NullPanel { + get { + return ResourceManager.GetString("DockContentHandler_SetDockState_NullPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid beforeContent, it must be contained by the pane.. + /// + internal static string DockContentHandler_Show_InvalidBeforeContent { + get { + return ResourceManager.GetString("DockContentHandler_Show_InvalidBeforeContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid DockState: Content can not be showed as "Unknown" or "Hidden".. + /// + internal static string DockContentHandler_Show_InvalidDockState { + get { + return ResourceManager.GetString("DockContentHandler_Show_InvalidDockState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane is invalid. It can not be null, and its docking state must not be auto-hide.. + /// + internal static string DockContentHandler_Show_InvalidPrevPane { + get { + return ResourceManager.GetString("DockContentHandler_Show_InvalidPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DockPanel can not be null.. + /// + internal static string DockContentHandler_Show_NullDockPanel { + get { + return ResourceManager.GetString("DockContentHandler_Show_NullDockPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Pane can not be null.. + /// + internal static string DockContentHandler_Show_NullPane { + get { + return ResourceManager.GetString("DockContentHandler_Show_NullPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value, check DockableAreas property.. + /// + internal static string DockContentHandler_ShowHint_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_ShowHint_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Context menu displayed for the dock pane tab strip.. + /// + internal static string DockHandler_TabPageContextMenuStrip_Description { + get { + return ResourceManager.GetString("DockHandler_TabPageContextMenuStrip_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Press SHIFT for docking to full side.. + /// + internal static string DockIndicator_ToolTipText { + get { + return ResourceManager.GetString("DockIndicator_ToolTipText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content.. + /// + internal static string DockPane_ActiveContent_InvalidValue { + get { + return ResourceManager.GetString("DockPane_ActiveContent_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: Content can not be "null".. + /// + internal static string DockPane_Constructor_NullContent { + get { + return ResourceManager.GetString("DockPane_Constructor_NullContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: The content's DockPanel can not be "null".. + /// + internal static string DockPane_Constructor_NullDockPanel { + get { + return ResourceManager.GetString("DockPane_Constructor_NullDockPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified container conflicts with the IsFloat property.. + /// + internal static string DockPane_DockTo_InvalidContainer { + get { + return ResourceManager.GetString("DockPane_DockTo_InvalidContainer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane does not exist in the nested docking pane collection.. + /// + internal static string DockPane_DockTo_NoPrevPane { + get { + return ResourceManager.GetString("DockPane_DockTo_NoPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The container can not be null.. + /// + internal static string DockPane_DockTo_NullContainer { + get { + return ResourceManager.GetString("DockPane_DockTo_NullContainer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane can not be null when the nested docking pane collection is not empty.. + /// + internal static string DockPane_DockTo_NullPrevPane { + get { + return ResourceManager.GetString("DockPane_DockTo_NullPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane can not be itself.. + /// + internal static string DockPane_DockTo_SelfPrevPane { + get { + return ResourceManager.GetString("DockPane_DockTo_SelfPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FloatWindow property can not be set to "null" when DockState is DockState.Float.. + /// + internal static string DockPane_FloatWindow_InvalidValue { + get { + return ResourceManager.GetString("DockPane_FloatWindow_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Content: Content not within the collection.. + /// + internal static string DockPane_SetContentIndex_InvalidContent { + get { + return ResourceManager.GetString("DockPane_SetContentIndex_InvalidContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Index: The index is out of range.. + /// + internal static string DockPane_SetContentIndex_InvalidIndex { + get { + return ResourceManager.GetString("DockPane_SetContentIndex_InvalidIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The state for the dock pane is invalid.. + /// + internal static string DockPane_SetDockState_InvalidState { + get { + return ResourceManager.GetString("DockPane_SetDockState_InvalidState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Auto Hide. + /// + internal static string DockPaneCaption_ToolTipAutoHide { + get { + return ResourceManager.GetString("DockPaneCaption_ToolTipAutoHide", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close. + /// + internal static string DockPaneCaption_ToolTipClose { + get { + return ResourceManager.GetString("DockPaneCaption_ToolTipClose", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Options. + /// + internal static string DockPaneCaption_ToolTipOptions { + get { + return ResourceManager.GetString("DockPaneCaption_ToolTipOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Content: The content must be auto-hide state and associates with this DockPanel.. + /// + internal static string DockPanel_ActiveAutoHideContent_InvalidValue { + get { + return ResourceManager.GetString("DockPanel_ActiveAutoHideContent_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of the AutoHideWindow's ActiveContent changed.. + /// + internal static string DockPanel_ActiveAutoHideContentChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActiveAutoHideContentChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of ActiveContentProperty changed.. + /// + internal static string DockPanel_ActiveContentChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActiveContentChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of ActiveDocument property changed.. + /// + internal static string DockPanel_ActiveDocumentChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActiveDocumentChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of ActivePane property changed.. + /// + internal static string DockPanel_ActivePaneChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActivePaneChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if the drag and drop docking is allowed.. + /// + internal static string DockPanel_AllowEndUserDocking_Description { + get { + return ResourceManager.GetString("DockPanel_AllowEndUserDocking_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if the drag and drop nested docking is allowed.. + /// + internal static string DockPanel_AllowEndUserNestedDocking_Description { + get { + return ResourceManager.GetString("DockPanel_AllowEndUserNestedDocking_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when a content added to the DockPanel.. + /// + internal static string DockPanel_ContentAdded_Description { + get { + return ResourceManager.GetString("DockPanel_ContentAdded_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when a content removed from the DockPanel.. + /// + internal static string DockPanel_ContentRemoved_Description { + get { + return ResourceManager.GetString("DockPanel_ContentRemoved_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The default size of float window.. + /// + internal static string DockPanel_DefaultFloatWindowSize_Description { + get { + return ResourceManager.GetString("DockPanel_DefaultFloatWindowSize_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provides Visual Studio .Net style docking.. + /// + internal static string DockPanel_Description { + get { + return ResourceManager.GetString("DockPanel_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the bottom docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockBottomPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockBottomPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the left docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockLeftPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockLeftPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The visual skin to use when displaying the docked windows.. + /// + internal static string DockPanel_DockPanelSkin { + get { + return ResourceManager.GetString("DockPanel_DockPanelSkin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The predefined style used as the base for the skin.. + /// + internal static string DockPanel_DockPanelSkinStyle { + get { + return ResourceManager.GetString("DockPanel_DockPanelSkinStyle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the right docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockRightPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockRightPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the top docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockTopPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockTopPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The style of the document window.. + /// + internal static string DockPanel_DocumentStyle_Description { + get { + return ResourceManager.GetString("DockPanel_DocumentStyle_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines where the tab strip for Document style content is drawn.. + /// + internal static string DockPanel_DocumentTabStripLocation { + get { + return ResourceManager.GetString("DockPanel_DocumentTabStripLocation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The DockPanel has already been initialized.. + /// + internal static string DockPanel_LoadFromXml_AlreadyInitialized { + get { + return ResourceManager.GetString("DockPanel_LoadFromXml_AlreadyInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The configuration file's version is invalid.. + /// + internal static string DockPanel_LoadFromXml_InvalidFormatVersion { + get { + return ResourceManager.GetString("DockPanel_LoadFromXml_InvalidFormatVersion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The XML file format is invalid.. + /// + internal static string DockPanel_LoadFromXml_InvalidXmlFormat { + get { + return ResourceManager.GetString("DockPanel_LoadFromXml_InvalidXmlFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid parent form. When using DockingMdi or SystemMdi document style, the DockPanel control must be the child control of the main MDI container form.. + /// + internal static string DockPanel_ParentForm_Invalid { + get { + return ResourceManager.GetString("DockPanel_ParentForm_Invalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DockPanel configuration file. Author: Weifen Luo, all rights reserved.. + /// + internal static string DockPanel_Persistor_XmlFileComment1 { + get { + return ResourceManager.GetString("DockPanel_Persistor_XmlFileComment1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!!. + /// + internal static string DockPanel_Persistor_XmlFileComment2 { + get { + return ResourceManager.GetString("DockPanel_Persistor_XmlFileComment2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indicates whether the control layout is right-to-left when the RightToLeft property is set to Yes.. + /// + internal static string DockPanel_RightToLeftLayout_Description { + get { + return ResourceManager.GetString("DockPanel_RightToLeftLayout_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Index: The index is out of range.. + /// + internal static string DockPanel_SetPaneIndex_InvalidIndex { + get { + return ResourceManager.GetString("DockPanel_SetPaneIndex_InvalidIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Pane: DockPane not within the collection.. + /// + internal static string DockPanel_SetPaneIndex_InvalidPane { + get { + return ResourceManager.GetString("DockPanel_SetPaneIndex_InvalidPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows the hidden autohide content when hovering over the tab. When disabled, the tab must be clicked to show the content.. + /// + internal static string DockPanel_ShowAutoHideContentOnHover_Description { + get { + return ResourceManager.GetString("DockPanel_ShowAutoHideContentOnHover_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if the document icon will be displayed in the tab strip.. + /// + internal static string DockPanel_ShowDocumentIcon_Description { + get { + return ResourceManager.GetString("DockPanel_ShowDocumentIcon_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Support deeply nested controls. Disabling this setting may improve resize performance but may cause heavily nested content not to resize.. + /// + internal static string DockPanel_SupportDeeplyNestedContent_Description { + get { + return ResourceManager.GetString("DockPanel_SupportDeeplyNestedContent_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close. + /// + internal static string DockPaneStrip_ToolTipClose { + get { + return ResourceManager.GetString("DockPaneStrip_ToolTipClose", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Window List. + /// + internal static string DockPaneStrip_ToolTipWindowList { + get { + return ResourceManager.GetString("DockPaneStrip_ToolTipWindowList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: DockPanel can not be "null".. + /// + internal static string FloatWindow_Constructor_NullDockPanel { + get { + return ResourceManager.GetString("FloatWindow_Constructor_NullDockPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Index: The index is out of range.. + /// + internal static string FloatWindow_SetPaneIndex_InvalidIndex { + get { + return ResourceManager.GetString("FloatWindow_SetPaneIndex_InvalidIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Pane: DockPane not within the collection.. + /// + internal static string FloatWindow_SetPaneIndex_InvalidPane { + get { + return ResourceManager.GetString("FloatWindow_SetPaneIndex_InvalidPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid DockPanel.. + /// + internal static string IDockDragSource_DockTo_InvalidPanel { + get { + return ResourceManager.GetString("IDockDragSource_DockTo_InvalidPanel", resourceCulture); + } + } + } +} diff --git a/WinFormsUI/Docking/Strings.resx b/WinFormsUI/Docking/Strings.resx new file mode 100644 index 0000000000..d0056d279c --- /dev/null +++ b/WinFormsUI/Docking/Strings.resx @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Docking + + + Docking Notification + + + Property Changed + + + (Float) + + + Determines if end user drag and drop docking is allowed. + + + The size to display the content in auto hide mode. Value < 1 to specify the size in portion; value >= 1 to specify the size in pixel. + + + Enable/Disable the close button of the content. + + + The form must be of type IDockContent. + + + Gets or sets a value indicating in which area of the DockPanel the content allowed to show. + + + Occurs when the value of DockState property changed. + + + Indicates the content will be hidden instead of being closed. + + + The desired docking state when first showing. + + + Context menu displayed for the dock pane tab strip. + + + The tab text displayed in the dock pane. If not set, the Text property will be used. + + + The text displayed when mouse hovers over the tab. + + + The provided value is out of range. + + + Invalid Value: The value of DockAreas conflicts with current DockState. + + + The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane. + + + The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane. + + + Invalid value, conflicts with DockableAreas property. + + + The dock state is invalid. + + + The dock panel is null. + + + Invalid beforeContent, it must be contained by the pane. + + + Invalid DockState: Content can not be showed as "Unknown" or "Hidden". + + + The previous pane is invalid. It can not be null, and its docking state must not be auto-hide. + + + DockPanel can not be null. + + + The Pane can not be null. + + + Invalid value, check DockableAreas property. + + + Context menu displayed for the dock pane tab strip. + + + Press SHIFT for docking to full side. + + + Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content. + + + Invalid argument: Content can not be "null". + + + Invalid argument: The content's DockPanel can not be "null". + + + The specified container conflicts with the IsFloat property. + + + The previous pane does not exist in the nested docking pane collection. + + + The container can not be null. + + + The previous pane can not be null when the nested docking pane collection is not empty. + + + The previous pane can not be itself. + + + FloatWindow property can not be set to "null" when DockState is DockState.Float. + + + Invalid Content: Content not within the collection. + + + Invalid Index: The index is out of range. + + + The state for the dock pane is invalid. + + + Auto Hide + + + Close + + + Options + + + Invalid Content: The content must be auto-hide state and associates with this DockPanel. + + + Occurs when the value of ActiveContentProperty changed. + + + Occurs when the value of ActiveDocument property changed. + + + Occurs when the value of ActivePane property changed. + + + Determines if the drag and drop docking is allowed. + + + Determines if the drag and drop nested docking is allowed. + + + Occurs when the value of the AutoHideWindow's ActiveContent changed. + + + Occurs when a content added to the DockPanel. + + + Occurs when a content removed from the DockPanel. + + + The default size of float window. + + + Provides Visual Studio .Net style docking. + + + Size of the bottom docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + Size of the left docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + Size of the right docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + Size of the top docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + The style of the document window. + + + The DockPanel has already been initialized. + + + The configuration file's version is invalid. + + + The XML file format is invalid. + + + Invalid parent form. When using DockingMdi or SystemMdi document style, the DockPanel control must be the child control of the main MDI container form. + + + DockPanel configuration file. Author: Weifen Luo, all rights reserved. + + + !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!! + + + Indicates whether the control layout is right-to-left when the RightToLeft property is set to Yes. + + + Invalid Index: The index is out of range. + + + Invalid Pane: DockPane not within the collection. + + + Determines if the document icon will be displayed in the tab strip. + + + Close + + + Window List + + + Invalid argument: DockPanel can not be "null". + + + Invalid Index: The index is out of range. + + + Invalid Pane: DockPane not within the collection. + + + Invalid DockPanel. + + + Shows or hides the close button of the content. This property does not function with System MDI Document Style. + + + The visual skin to use when displaying the docked windows. + + + The predefined style used as the base for the skin. + + + Determines where the tab strip for Document style content is drawn. + + + Performance + + + Support deeply nested controls. Disabling this setting may improve resize performance but may cause heavily nested content not to resize. + + + Shows the hidden autohide content when hovering over the tab. When disabled, the tab must be clicked to show the content. + + \ No newline at end of file diff --git a/WinFormsUI/Docking/VS2005AutoHideStrip.cs b/WinFormsUI/Docking/VS2005AutoHideStrip.cs new file mode 100644 index 0000000000..eee1dd8db8 --- /dev/null +++ b/WinFormsUI/Docking/VS2005AutoHideStrip.cs @@ -0,0 +1,529 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal class VS2005AutoHideStrip : AutoHideStripBase + { + private class TabVS2005 : Tab + { + internal TabVS2005(IDockContent content) + : base(content) + { + } + + private int m_tabX = 0; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } + + private int m_tabWidth = 0; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } + + } + + private const int _ImageHeight = 16; + private const int _ImageWidth = 16; + private const int _ImageGapTop = 2; + private const int _ImageGapLeft = 4; + private const int _ImageGapRight = 2; + private const int _ImageGapBottom = 2; + private const int _TextGapLeft = 0; + private const int _TextGapRight = 0; + private const int _TabGapTop = 3; + private const int _TabGapLeft = 4; + private const int _TabGapBetween = 10; + + #region Customizable Properties + public Font TextFont + { + get { return DockPanel.Skin.AutoHideStripSkin.TextFont; } + } + + private static StringFormat _stringFormatTabHorizontal; + private StringFormat StringFormatTabHorizontal + { + get + { + if (_stringFormatTabHorizontal == null) + { + _stringFormatTabHorizontal = new StringFormat(); + _stringFormatTabHorizontal.Alignment = StringAlignment.Near; + _stringFormatTabHorizontal.LineAlignment = StringAlignment.Center; + _stringFormatTabHorizontal.FormatFlags = StringFormatFlags.NoWrap; + _stringFormatTabHorizontal.Trimming = StringTrimming.None; + } + + if (RightToLeft == RightToLeft.Yes) + _stringFormatTabHorizontal.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + _stringFormatTabHorizontal.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + return _stringFormatTabHorizontal; + } + } + + private static StringFormat _stringFormatTabVertical; + private StringFormat StringFormatTabVertical + { + get + { + if (_stringFormatTabVertical == null) + { + _stringFormatTabVertical = new StringFormat(); + _stringFormatTabVertical.Alignment = StringAlignment.Near; + _stringFormatTabVertical.LineAlignment = StringAlignment.Center; + _stringFormatTabVertical.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.DirectionVertical; + _stringFormatTabVertical.Trimming = StringTrimming.None; + } + if (RightToLeft == RightToLeft.Yes) + _stringFormatTabVertical.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + _stringFormatTabVertical.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + return _stringFormatTabVertical; + } + } + + private static int ImageHeight + { + get { return _ImageHeight; } + } + + private static int ImageWidth + { + get { return _ImageWidth; } + } + + private static int ImageGapTop + { + get { return _ImageGapTop; } + } + + private static int ImageGapLeft + { + get { return _ImageGapLeft; } + } + + private static int ImageGapRight + { + get { return _ImageGapRight; } + } + + private static int ImageGapBottom + { + get { return _ImageGapBottom; } + } + + private static int TextGapLeft + { + get { return _TextGapLeft; } + } + + private static int TextGapRight + { + get { return _TextGapRight; } + } + + private static int TabGapTop + { + get { return _TabGapTop; } + } + + private static int TabGapLeft + { + get { return _TabGapLeft; } + } + + private static int TabGapBetween + { + get { return _TabGapBetween; } + } + + private static Pen PenTabBorder + { + get { return SystemPens.GrayText; } + } + #endregion + + private static Matrix _matrixIdentity = new Matrix(); + private static Matrix MatrixIdentity + { + get { return _matrixIdentity; } + } + + private static DockState[] _dockStates; + private static DockState[] DockStates + { + get + { + if (_dockStates == null) + { + _dockStates = new DockState[4]; + _dockStates[0] = DockState.DockLeftAutoHide; + _dockStates[1] = DockState.DockRightAutoHide; + _dockStates[2] = DockState.DockTopAutoHide; + _dockStates[3] = DockState.DockBottomAutoHide; + } + return _dockStates; + } + } + + private static GraphicsPath _graphicsPath; + internal static GraphicsPath GraphicsPath + { + get + { + if (_graphicsPath == null) + _graphicsPath = new GraphicsPath(); + + return _graphicsPath; + } + } + + public VS2005AutoHideStrip(DockPanel panel) + : base(panel) + { + SetStyle(ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); + BackColor = SystemColors.ControlLight; + } + + protected override void OnPaint(PaintEventArgs e) + { + Graphics g = e.Graphics; + + Color startColor = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.StartColor; + Color endColor = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + g.FillRectangle(brush, ClientRectangle); + } + + DrawTabStrip(g); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + CalculateTabs(); + base.OnLayout(levent); + } + + private void DrawTabStrip(Graphics g) + { + DrawTabStrip(g, DockState.DockTopAutoHide); + DrawTabStrip(g, DockState.DockBottomAutoHide); + DrawTabStrip(g, DockState.DockLeftAutoHide); + DrawTabStrip(g, DockState.DockRightAutoHide); + } + + private void DrawTabStrip(Graphics g, DockState dockState) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + if (rectTabStrip.IsEmpty) + return; + + Matrix matrixIdentity = g.Transform; + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + { + Matrix matrixRotated = new Matrix(); + matrixRotated.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, + (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + g.Transform = matrixRotated; + } + + foreach (Pane pane in GetPanes(dockState)) + { + foreach (TabVS2005 tab in pane.AutoHideTabs) + DrawTab(g, tab); + } + g.Transform = matrixIdentity; + } + + private void CalculateTabs() + { + CalculateTabs(DockState.DockTopAutoHide); + CalculateTabs(DockState.DockBottomAutoHide); + CalculateTabs(DockState.DockLeftAutoHide); + CalculateTabs(DockState.DockRightAutoHide); + } + + private void CalculateTabs(DockState dockState) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + int imageHeight = rectTabStrip.Height - ImageGapTop - ImageGapBottom; + int imageWidth = ImageWidth; + if (imageHeight > ImageHeight) + imageWidth = ImageWidth * (imageHeight / ImageHeight); + + int x = TabGapLeft + rectTabStrip.X; + foreach (Pane pane in GetPanes(dockState)) + { + foreach (TabVS2005 tab in pane.AutoHideTabs) + { + int width = imageWidth + ImageGapLeft + ImageGapRight + + TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width + + TextGapLeft + TextGapRight; + tab.TabX = x; + tab.TabWidth = width; + x += width; + } + + x += TabGapBetween; + } + } + + private Rectangle RtlTransform(Rectangle rect, DockState dockState) + { + Rectangle rectTransformed; + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + rectTransformed = rect; + else + rectTransformed = DrawHelper.RtlTransform(this, rect); + + return rectTransformed; + } + + private GraphicsPath GetTabOutline(TabVS2005 tab, bool transformed, bool rtlTransform) + { + DockState dockState = tab.Content.DockHandler.DockState; + Rectangle rectTab = GetTabRectangle(tab, transformed); + if (rtlTransform) + rectTab = RtlTransform(rectTab, dockState); + bool upTab = (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockBottomAutoHide); + DrawHelper.GetRoundedCornerTab(GraphicsPath, rectTab, upTab); + + return GraphicsPath; + } + + private void DrawTab(Graphics g, TabVS2005 tab) + { + Rectangle rectTabOrigin = GetTabRectangle(tab); + if (rectTabOrigin.IsEmpty) + return; + + DockState dockState = tab.Content.DockHandler.DockState; + IDockContent content = tab.Content; + + GraphicsPath path = GetTabOutline(tab, false, true); + + Color startColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.StartColor; + Color endColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.EndColor; + LinearGradientMode gradientMode = DockPanel.Skin.AutoHideStripSkin.TabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTabOrigin, startColor, endColor, gradientMode), path); + g.DrawPath(PenTabBorder, path); + + // Set no rotate for drawing icon and text + Matrix matrixRotate = g.Transform; + g.Transform = MatrixIdentity; + + // Draw the icon + Rectangle rectImage = rectTabOrigin; + rectImage.X += ImageGapLeft; + rectImage.Y += ImageGapTop; + int imageHeight = rectTabOrigin.Height - ImageGapTop - ImageGapBottom; + int imageWidth = ImageWidth; + if (imageHeight > ImageHeight) + imageWidth = ImageWidth * (imageHeight / ImageHeight); + rectImage.Height = imageHeight; + rectImage.Width = imageWidth; + rectImage = GetTransformedRectangle(dockState, rectImage); + + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + { + // The DockState is DockLeftAutoHide or DockRightAutoHide, so rotate the image 90 degrees to the right. + Rectangle rectTransform = RtlTransform(rectImage, dockState); + Point[] rotationPoints = + { + new Point(rectTransform.X + rectTransform.Width, rectTransform.Y), + new Point(rectTransform.X + rectTransform.Width, rectTransform.Y + rectTransform.Height), + new Point(rectTransform.X, rectTransform.Y) + }; + + using (Icon rotatedIcon = new Icon(((Form)content).Icon, 16, 16)) + { + g.DrawImage(rotatedIcon.ToBitmap(), rotationPoints); + } + } + else + { + // Draw the icon normally without any rotation. + g.DrawIcon(((Form)content).Icon, RtlTransform(rectImage, dockState)); + } + + // Draw the text + Rectangle rectText = rectTabOrigin; + rectText.X += ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; + rectText.Width -= ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; + rectText = RtlTransform(GetTransformedRectangle(dockState, rectText), dockState); + + Color textColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.TextColor; + + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabVertical); + else + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabHorizontal); + + // Set rotate back + g.Transform = matrixRotate; + } + + private Rectangle GetLogicalTabStripRectangle(DockState dockState) + { + return GetLogicalTabStripRectangle(dockState, false); + } + + private Rectangle GetLogicalTabStripRectangle(DockState dockState, bool transformed) + { + if (!DockHelper.IsDockStateAutoHide(dockState)) + return Rectangle.Empty; + + int leftPanes = GetPanes(DockState.DockLeftAutoHide).Count; + int rightPanes = GetPanes(DockState.DockRightAutoHide).Count; + int topPanes = GetPanes(DockState.DockTopAutoHide).Count; + int bottomPanes = GetPanes(DockState.DockBottomAutoHide).Count; + + int x, y, width, height; + + height = MeasureHeight(); + if (dockState == DockState.DockLeftAutoHide && leftPanes > 0) + { + x = 0; + y = (topPanes == 0) ? 0 : height; + width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockRightAutoHide && rightPanes > 0) + { + x = Width - height; + if (leftPanes != 0 && x < height) + x = height; + y = (topPanes == 0) ? 0 : height; + width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockTopAutoHide && topPanes > 0) + { + x = leftPanes == 0 ? 0 : height; + y = 0; + width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockBottomAutoHide && bottomPanes > 0) + { + x = leftPanes == 0 ? 0 : height; + y = Height - height; + if (topPanes != 0 && y < height) + y = height; + width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height); + } + else + return Rectangle.Empty; + + if (width == 0 || height == 0) + { + return Rectangle.Empty; + } + + var rect = new Rectangle(x, y, width, height); + return transformed ? GetTransformedRectangle(dockState, rect) : rect; + } + + private Rectangle GetTabRectangle(TabVS2005 tab) + { + return GetTabRectangle(tab, false); + } + + private Rectangle GetTabRectangle(TabVS2005 tab, bool transformed) + { + DockState dockState = tab.Content.DockHandler.DockState; + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + if (rectTabStrip.IsEmpty) + return Rectangle.Empty; + + int x = tab.TabX; + int y = rectTabStrip.Y + + (dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide ? + 0 : TabGapTop); + int width = tab.TabWidth; + int height = rectTabStrip.Height - TabGapTop; + + if (!transformed) + return new Rectangle(x, y, width, height); + else + return GetTransformedRectangle(dockState, new Rectangle(x, y, width, height)); + } + + private Rectangle GetTransformedRectangle(DockState dockState, Rectangle rect) + { + if (dockState != DockState.DockLeftAutoHide && dockState != DockState.DockRightAutoHide) + return rect; + + PointF[] pts = new PointF[1]; + // the center of the rectangle + pts[0].X = (float)rect.X + (float)rect.Width / 2; + pts[0].Y = (float)rect.Y + (float)rect.Height / 2; + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + Matrix matrix = new Matrix(); + matrix.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, + (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + matrix.TransformPoints(pts); + + return new Rectangle((int)(pts[0].X - (float)rect.Height / 2 + .5F), + (int)(pts[0].Y - (float)rect.Width / 2 + .5F), + rect.Height, rect.Width); + } + + protected override IDockContent HitTest(Point ptMouse) + { + foreach (DockState state in DockStates) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(state, true); + if (!rectTabStrip.Contains(ptMouse)) + continue; + + foreach (Pane pane in GetPanes(state)) + { + foreach (TabVS2005 tab in pane.AutoHideTabs) + { + GraphicsPath path = GetTabOutline(tab, true, true); + if (path.IsVisible(ptMouse)) + return tab.Content; + } + } + } + + return null; + } + + protected internal override int MeasureHeight() + { + return Math.Max(ImageGapBottom + + ImageGapTop + ImageHeight, + TextFont.Height) + TabGapTop; + } + + protected override void OnRefreshChanges() + { + CalculateTabs(); + Invalidate(); + } + + protected override AutoHideStripBase.Tab CreateTab(IDockContent content) + { + return new TabVS2005(content); + } + } +} diff --git a/WinFormsUI/Docking/VS2005DockPaneCaption.cs b/WinFormsUI/Docking/VS2005DockPaneCaption.cs new file mode 100644 index 0000000000..c7a0134bf6 --- /dev/null +++ b/WinFormsUI/Docking/VS2005DockPaneCaption.cs @@ -0,0 +1,480 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.ComponentModel; +using System.Windows.Forms.VisualStyles; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal class VS2005DockPaneCaption : DockPaneCaptionBase + { + private sealed class InertButton : InertButtonBase + { + private Bitmap m_image, m_imageAutoHide; + + public InertButton(VS2005DockPaneCaption dockPaneCaption, Bitmap image, Bitmap imageAutoHide) + : base() + { + m_dockPaneCaption = dockPaneCaption; + m_image = image; + m_imageAutoHide = imageAutoHide; + RefreshChanges(); + } + + private VS2005DockPaneCaption m_dockPaneCaption; + private VS2005DockPaneCaption DockPaneCaption + { + get { return m_dockPaneCaption; } + } + + public bool IsAutoHide + { + get { return DockPaneCaption.DockPane.IsAutoHide; } + } + + public override Bitmap Image + { + get { return IsAutoHide ? m_imageAutoHide : m_image; } + } + + protected override void OnRefreshChanges() + { + if (DockPaneCaption.DockPane.DockPanel != null) + { + if (DockPaneCaption.TextColor != ForeColor) + { + ForeColor = DockPaneCaption.TextColor; + Invalidate(); + } + } + } + } + + #region consts + private const int _TextGapTop = 2; + private const int _TextGapBottom = 0; + private const int _TextGapLeft = 3; + private const int _TextGapRight = 3; + private const int _ButtonGapTop = 2; + private const int _ButtonGapBottom = 1; + private const int _ButtonGapBetween = 1; + private const int _ButtonGapLeft = 1; + private const int _ButtonGapRight = 2; + #endregion + + private static Bitmap _imageButtonClose; + private static Bitmap ImageButtonClose + { + get + { + if (_imageButtonClose == null) + _imageButtonClose = Resources.DockPane_Close; + + return _imageButtonClose; + } + } + + private InertButton m_buttonClose; + private InertButton ButtonClose + { + get + { + if (m_buttonClose == null) + { + m_buttonClose = new InertButton(this, ImageButtonClose, ImageButtonClose); + m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); + m_buttonClose.Click += new EventHandler(Close_Click); + Controls.Add(m_buttonClose); + } + + return m_buttonClose; + } + } + + private static Bitmap _imageButtonAutoHide; + private static Bitmap ImageButtonAutoHide + { + get + { + if (_imageButtonAutoHide == null) + _imageButtonAutoHide = Resources.DockPane_AutoHide; + + return _imageButtonAutoHide; + } + } + + private static Bitmap _imageButtonDock; + private static Bitmap ImageButtonDock + { + get + { + if (_imageButtonDock == null) + _imageButtonDock = Resources.DockPane_Dock; + + return _imageButtonDock; + } + } + + private InertButton m_buttonAutoHide; + private InertButton ButtonAutoHide + { + get + { + if (m_buttonAutoHide == null) + { + m_buttonAutoHide = new InertButton(this, ImageButtonDock, ImageButtonAutoHide); + m_toolTip.SetToolTip(m_buttonAutoHide, ToolTipAutoHide); + m_buttonAutoHide.Click += new EventHandler(AutoHide_Click); + Controls.Add(m_buttonAutoHide); + } + + return m_buttonAutoHide; + } + } + + private static Bitmap _imageButtonOptions; + private static Bitmap ImageButtonOptions + { + get + { + if (_imageButtonOptions == null) + _imageButtonOptions = Resources.DockPane_Option; + + return _imageButtonOptions; + } + } + + private InertButton m_buttonOptions; + private InertButton ButtonOptions + { + get + { + if (m_buttonOptions == null) + { + m_buttonOptions = new InertButton(this, ImageButtonOptions, ImageButtonOptions); + m_toolTip.SetToolTip(m_buttonOptions, ToolTipOptions); + m_buttonOptions.Click += new EventHandler(Options_Click); + Controls.Add(m_buttonOptions); + } + return m_buttonOptions; + } + } + + private IContainer m_components; + private IContainer Components + { + get { return m_components; } + } + + private ToolTip m_toolTip; + + public VS2005DockPaneCaption(DockPane pane) : base(pane) + { + SuspendLayout(); + + m_components = new Container(); + m_toolTip = new ToolTip(Components); + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + Components.Dispose(); + base.Dispose(disposing); + } + + private static int TextGapTop + { + get { return _TextGapTop; } + } + + public Font TextFont + { + get { return DockPane.DockPanel.Skin.DockPaneStripSkin.TextFont; } + } + + private static int TextGapBottom + { + get { return _TextGapBottom; } + } + + private static int TextGapLeft + { + get { return _TextGapLeft; } + } + + private static int TextGapRight + { + get { return _TextGapRight; } + } + + private static int ButtonGapTop + { + get { return _ButtonGapTop; } + } + + private static int ButtonGapBottom + { + get { return _ButtonGapBottom; } + } + + private static int ButtonGapLeft + { + get { return _ButtonGapLeft; } + } + + private static int ButtonGapRight + { + get { return _ButtonGapRight; } + } + + private static int ButtonGapBetween + { + get { return _ButtonGapBetween; } + } + + private static string _toolTipClose; + private static string ToolTipClose + { + get + { + if (_toolTipClose == null) + _toolTipClose = Strings.DockPaneCaption_ToolTipClose; + return _toolTipClose; + } + } + + private static string _toolTipOptions; + private static string ToolTipOptions + { + get + { + if (_toolTipOptions == null) + _toolTipOptions = Strings.DockPaneCaption_ToolTipOptions; + + return _toolTipOptions; + } + } + + private static string _toolTipAutoHide; + private static string ToolTipAutoHide + { + get + { + if (_toolTipAutoHide == null) + _toolTipAutoHide = Strings.DockPaneCaption_ToolTipAutoHide; + return _toolTipAutoHide; + } + } + + private static Blend _activeBackColorGradientBlend; + private static Blend ActiveBackColorGradientBlend + { + get + { + if (_activeBackColorGradientBlend == null) + { + Blend blend = new Blend(2); + + blend.Factors = new float[]{0.5F, 1.0F}; + blend.Positions = new float[]{0.0F, 1.0F}; + _activeBackColorGradientBlend = blend; + } + + return _activeBackColorGradientBlend; + } + } + + private Color TextColor + { + get + { + if (DockPane.IsActivated) + return DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor; + else + return DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor; + } + } + + private static TextFormatFlags _textFormat = + TextFormatFlags.SingleLine | + TextFormatFlags.EndEllipsis | + TextFormatFlags.VerticalCenter; + private TextFormatFlags TextFormat + { + get + { + if (RightToLeft == RightToLeft.No) + return _textFormat; + else + return _textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; + } + } + + protected internal override int MeasureHeight() + { + int height = TextFont.Height + TextGapTop + TextGapBottom; + + if (height < ButtonClose.Image.Height + ButtonGapTop + ButtonGapBottom) + height = ButtonClose.Image.Height + ButtonGapTop + ButtonGapBottom; + + return height; + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint (e); + DrawCaption(e.Graphics); + } + + private void DrawCaption(Graphics g) + { + if (ClientRectangle.Width == 0 || ClientRectangle.Height == 0) + return; + + if (DockPane.IsActivated) + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + brush.Blend = ActiveBackColorGradientBlend; + g.FillRectangle(brush, ClientRectangle); + } + } + else + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + g.FillRectangle(brush, ClientRectangle); + } + } + + Rectangle rectCaption = ClientRectangle; + + Rectangle rectCaptionText = rectCaption; + rectCaptionText.X += TextGapLeft; + rectCaptionText.Width -= TextGapLeft + TextGapRight; + rectCaptionText.Width -= ButtonGapLeft + ButtonClose.Width + ButtonGapRight; + if (ShouldShowAutoHideButton) + rectCaptionText.Width -= ButtonAutoHide.Width + ButtonGapBetween; + if (HasTabPageContextMenu) + rectCaptionText.Width -= ButtonOptions.Width + ButtonGapBetween; + rectCaptionText.Y += TextGapTop; + rectCaptionText.Height -= TextGapTop + TextGapBottom; + + Color colorText; + if (DockPane.IsActivated) + colorText = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor; + else + colorText = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor; + + TextRenderer.DrawText(g, DockPane.CaptionText, TextFont, DrawHelper.RtlTransform(this, rectCaptionText), colorText, TextFormat); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + SetButtonsPosition(); + base.OnLayout (levent); + } + + protected override void OnRefreshChanges() + { + SetButtons(); + Invalidate(); + } + + private bool CloseButtonEnabled + { + get { return (DockPane.ActiveContent != null)? DockPane.ActiveContent.DockHandler.CloseButton : false; } + } + + /// + /// Determines whether the close button is visible on the content + /// + private bool CloseButtonVisible + { + get { return (DockPane.ActiveContent != null) ? DockPane.ActiveContent.DockHandler.CloseButtonVisible : false; } + } + + private bool ShouldShowAutoHideButton + { + get { return !DockPane.IsFloat; } + } + + private void SetButtons() + { + ButtonClose.Enabled = CloseButtonEnabled; + ButtonClose.Visible = CloseButtonVisible; + ButtonAutoHide.Visible = ShouldShowAutoHideButton; + ButtonOptions.Visible = HasTabPageContextMenu; + ButtonClose.RefreshChanges(); + ButtonAutoHide.RefreshChanges(); + ButtonOptions.RefreshChanges(); + + SetButtonsPosition(); + } + + private void SetButtonsPosition() + { + // set the size and location for close and auto-hide buttons + Rectangle rectCaption = ClientRectangle; + int buttonWidth = ButtonClose.Image.Width; + int buttonHeight = ButtonClose.Image.Height; + int height = rectCaption.Height - ButtonGapTop - ButtonGapBottom; + if (buttonHeight < height) + { + buttonWidth = buttonWidth * (height / buttonHeight); + buttonHeight = height; + } + Size buttonSize = new Size(buttonWidth, buttonHeight); + int x = rectCaption.X + rectCaption.Width - 1 - ButtonGapRight - m_buttonClose.Width; + int y = rectCaption.Y + ButtonGapTop; + Point point = new Point(x, y); + ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + + // If the close button is not visible draw the auto hide button overtop. + // Otherwise it is drawn to the left of the close button. + if (CloseButtonVisible) + point.Offset(-(buttonWidth + ButtonGapBetween), 0); + + ButtonAutoHide.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + if (ShouldShowAutoHideButton) + point.Offset(-(buttonWidth + ButtonGapBetween), 0); + ButtonOptions.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + } + + private void Close_Click(object sender, EventArgs e) + { + DockPane.CloseActiveContent(); + } + + private void AutoHide_Click(object sender, EventArgs e) + { + DockPane.DockState = DockHelper.ToggleAutoHideState(DockPane.DockState); + if (DockHelper.IsDockStateAutoHide(DockPane.DockState)) + { + DockPane.DockPanel.ActiveAutoHideContent = null; + DockPane.NestedDockingStatus.NestedPanes.SwitchPaneWithFirstChild(DockPane); + } + } + + private void Options_Click(object sender, EventArgs e) + { + ShowTabPageContextMenu(PointToClient(Control.MousePosition)); + } + + protected override void OnRightToLeftChanged(EventArgs e) + { + base.OnRightToLeftChanged(e); + PerformLayout(); + } + } +} diff --git a/WinFormsUI/Docking/VS2005DockPaneStrip.cs b/WinFormsUI/Docking/VS2005DockPaneStrip.cs new file mode 100644 index 0000000000..65bb56e0f7 --- /dev/null +++ b/WinFormsUI/Docking/VS2005DockPaneStrip.cs @@ -0,0 +1,1493 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.ComponentModel; +using System.Collections; +using System.Collections.Generic; + +namespace WeifenLuo.WinFormsUI.Docking +{ + internal class VS2005DockPaneStrip : DockPaneStripBase + { + private class TabVS2005 : Tab + { + public TabVS2005(IDockContent content) + : base(content) + { + } + + private int m_tabX; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } + + private int m_tabWidth; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } + + private int m_maxWidth; + public int MaxWidth + { + get { return m_maxWidth; } + set { m_maxWidth = value; } + } + + private bool m_flag; + protected internal bool Flag + { + get { return m_flag; } + set { m_flag = value; } + } + } + + protected internal override DockPaneStripBase.Tab CreateTab(IDockContent content) + { + return new TabVS2005(content); + } + + private sealed class InertButton : InertButtonBase + { + private Bitmap m_image0, m_image1; + + public InertButton(Bitmap image0, Bitmap image1) + : base() + { + m_image0 = image0; + m_image1 = image1; + } + + private int m_imageCategory = 0; + public int ImageCategory + { + get { return m_imageCategory; } + set + { + if (m_imageCategory == value) + return; + + m_imageCategory = value; + Invalidate(); + } + } + + public override Bitmap Image + { + get { return ImageCategory == 0 ? m_image0 : m_image1; } + } + } + + #region Constants + + private const int _ToolWindowStripGapTop = 0; + private const int _ToolWindowStripGapBottom = 1; + private const int _ToolWindowStripGapLeft = 0; + private const int _ToolWindowStripGapRight = 0; + private const int _ToolWindowImageHeight = 16; + private const int _ToolWindowImageWidth = 16; + private const int _ToolWindowImageGapTop = 3; + private const int _ToolWindowImageGapBottom = 1; + private const int _ToolWindowImageGapLeft = 2; + private const int _ToolWindowImageGapRight = 0; + private const int _ToolWindowTextGapRight = 3; + private const int _ToolWindowTabSeperatorGapTop = 3; + private const int _ToolWindowTabSeperatorGapBottom = 3; + + private const int _DocumentStripGapTop = 0; + private const int _DocumentStripGapBottom = 1; + private const int _DocumentTabMaxWidth = 200; + private const int _DocumentButtonGapTop = 4; + private const int _DocumentButtonGapBottom = 4; + private const int _DocumentButtonGapBetween = 0; + private const int _DocumentButtonGapRight = 3; + private const int _DocumentTabGapTop = 3; + private const int _DocumentTabGapLeft = 3; + private const int _DocumentTabGapRight = 3; + private const int _DocumentIconGapBottom = 2; + private const int _DocumentIconGapLeft = 12; + private const int _DocumentIconGapRight = 0; + private const int _DocumentIconHeight = 16; + private const int _DocumentIconWidth = 16; + private const int _DocumentTextGapRight = 3; + + #endregion + + #region Members + + private ContextMenuStrip m_selectMenu; + private static Bitmap m_imageButtonClose; + private InertButton m_buttonClose; + private static Bitmap m_imageButtonWindowList; + private static Bitmap m_imageButtonWindowListOverflow; + private InertButton m_buttonWindowList; + private IContainer m_components; + private ToolTip m_toolTip; + private Font m_font; + private Font m_boldFont; + private int m_startDisplayingTab = 0; + private int m_endDisplayingTab = 0; + private int m_firstDisplayingTab = 0; + private bool m_documentTabsOverflow = false; + private static string m_toolTipSelect; + private static string m_toolTipClose; + private bool m_closeButtonVisible = false; + + #endregion + + #region Properties + + private Rectangle TabStripRectangle + { + get + { + if (Appearance == DockPane.AppearanceStyle.Document) + return TabStripRectangle_Document; + else + return TabStripRectangle_ToolWindow; + } + } + + private Rectangle TabStripRectangle_ToolWindow + { + get + { + Rectangle rect = ClientRectangle; + return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); + } + } + + private Rectangle TabStripRectangle_Document + { + get + { + Rectangle rect = ClientRectangle; + return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height - DocumentStripGapTop - ToolWindowStripGapBottom); + } + } + + private Rectangle TabsRectangle + { + get + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return TabStripRectangle; + + Rectangle rectWindow = TabStripRectangle; + int x = rectWindow.X; + int y = rectWindow.Y; + int width = rectWindow.Width; + int height = rectWindow.Height; + + x += DocumentTabGapLeft; + width -= DocumentTabGapLeft + + DocumentTabGapRight + + DocumentButtonGapRight + + ButtonClose.Width + + ButtonWindowList.Width + + 2 * DocumentButtonGapBetween; + + return new Rectangle(x, y, width, height); + } + } + + private ContextMenuStrip SelectMenu + { + get { return m_selectMenu; } + } + + private static Bitmap ImageButtonClose + { + get + { + if (m_imageButtonClose == null) + m_imageButtonClose = Resources.DockPane_Close; + + return m_imageButtonClose; + } + } + + private InertButton ButtonClose + { + get + { + if (m_buttonClose == null) + { + m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose); + m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); + m_buttonClose.Click += new EventHandler(Close_Click); + Controls.Add(m_buttonClose); + } + + return m_buttonClose; + } + } + + private static Bitmap ImageButtonWindowList + { + get + { + if (m_imageButtonWindowList == null) + m_imageButtonWindowList = Resources.DockPane_Option; + + return m_imageButtonWindowList; + } + } + + private static Bitmap ImageButtonWindowListOverflow + { + get + { + if (m_imageButtonWindowListOverflow == null) + m_imageButtonWindowListOverflow = Resources.DockPane_OptionOverflow; + + return m_imageButtonWindowListOverflow; + } + } + + private InertButton ButtonWindowList + { + get + { + if (m_buttonWindowList == null) + { + m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); + m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); + m_buttonWindowList.Click += new EventHandler(WindowList_Click); + Controls.Add(m_buttonWindowList); + } + + return m_buttonWindowList; + } + } + + private static GraphicsPath GraphicsPath + { + get { return VS2005AutoHideStrip.GraphicsPath; } + } + + private IContainer Components + { + get { return m_components; } + } + + public Font TextFont + { + get { return DockPane.DockPanel.Skin.DockPaneStripSkin.TextFont; } + } + + private Font BoldFont + { + get + { + if (IsDisposed) + return null; + + if (m_boldFont == null) + { + m_font = TextFont; + m_boldFont = new Font(TextFont, FontStyle.Bold); + } + else if (m_font != TextFont) + { + m_boldFont.Dispose(); + m_font = TextFont; + m_boldFont = new Font(TextFont, FontStyle.Bold); + } + + return m_boldFont; + } + } + + private int StartDisplayingTab + { + get { return m_startDisplayingTab; } + set + { + m_startDisplayingTab = value; + Invalidate(); + } + } + + private int EndDisplayingTab + { + get { return m_endDisplayingTab; } + set { m_endDisplayingTab = value; } + } + + private int FirstDisplayingTab + { + get { return m_firstDisplayingTab; } + set { m_firstDisplayingTab = value; } + } + + private bool DocumentTabsOverflow + { + set + { + if (m_documentTabsOverflow == value) + return; + + m_documentTabsOverflow = value; + if (value) + ButtonWindowList.ImageCategory = 1; + else + ButtonWindowList.ImageCategory = 0; + } + } + + #region Customizable Properties + + private static int ToolWindowStripGapTop + { + get { return _ToolWindowStripGapTop; } + } + + private static int ToolWindowStripGapBottom + { + get { return _ToolWindowStripGapBottom; } + } + + private static int ToolWindowStripGapLeft + { + get { return _ToolWindowStripGapLeft; } + } + + private static int ToolWindowStripGapRight + { + get { return _ToolWindowStripGapRight; } + } + + private static int ToolWindowImageHeight + { + get { return _ToolWindowImageHeight; } + } + + private static int ToolWindowImageWidth + { + get { return _ToolWindowImageWidth; } + } + + private static int ToolWindowImageGapTop + { + get { return _ToolWindowImageGapTop; } + } + + private static int ToolWindowImageGapBottom + { + get { return _ToolWindowImageGapBottom; } + } + + private static int ToolWindowImageGapLeft + { + get { return _ToolWindowImageGapLeft; } + } + + private static int ToolWindowImageGapRight + { + get { return _ToolWindowImageGapRight; } + } + + private static int ToolWindowTextGapRight + { + get { return _ToolWindowTextGapRight; } + } + + private static int ToolWindowTabSeperatorGapTop + { + get { return _ToolWindowTabSeperatorGapTop; } + } + + private static int ToolWindowTabSeperatorGapBottom + { + get { return _ToolWindowTabSeperatorGapBottom; } + } + + private static string ToolTipClose + { + get + { + if (m_toolTipClose == null) + m_toolTipClose = Strings.DockPaneStrip_ToolTipClose; + return m_toolTipClose; + } + } + + private static string ToolTipSelect + { + get + { + if (m_toolTipSelect == null) + m_toolTipSelect = Strings.DockPaneStrip_ToolTipWindowList; + return m_toolTipSelect; + } + } + + private TextFormatFlags ToolWindowTextFormat + { + get + { + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.HorizontalCenter | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; + else + return textFormat; + } + } + + private static int DocumentStripGapTop + { + get { return _DocumentStripGapTop; } + } + + private static int DocumentStripGapBottom + { + get { return _DocumentStripGapBottom; } + } + + private TextFormatFlags DocumentTextFormat + { + get + { + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter | + TextFormatFlags.HorizontalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft; + else + return textFormat; + } + } + + private static int DocumentTabMaxWidth + { + get { return _DocumentTabMaxWidth; } + } + + private static int DocumentButtonGapTop + { + get { return _DocumentButtonGapTop; } + } + + private static int DocumentButtonGapBottom + { + get { return _DocumentButtonGapBottom; } + } + + private static int DocumentButtonGapBetween + { + get { return _DocumentButtonGapBetween; } + } + + private static int DocumentButtonGapRight + { + get { return _DocumentButtonGapRight; } + } + + private static int DocumentTabGapTop + { + get { return _DocumentTabGapTop; } + } + + private static int DocumentTabGapLeft + { + get { return _DocumentTabGapLeft; } + } + + private static int DocumentTabGapRight + { + get { return _DocumentTabGapRight; } + } + + private static int DocumentIconGapBottom + { + get { return _DocumentIconGapBottom; } + } + + private static int DocumentIconGapLeft + { + get { return _DocumentIconGapLeft; } + } + + private static int DocumentIconGapRight + { + get { return _DocumentIconGapRight; } + } + + private static int DocumentIconWidth + { + get { return _DocumentIconWidth; } + } + + private static int DocumentIconHeight + { + get { return _DocumentIconHeight; } + } + + private static int DocumentTextGapRight + { + get { return _DocumentTextGapRight; } + } + + private static Pen PenToolWindowTabBorder + { + get { return SystemPens.GrayText; } + } + + private static Pen PenDocumentTabActiveBorder + { + get { return SystemPens.ControlDarkDark; } + } + + private static Pen PenDocumentTabInactiveBorder + { + get { return SystemPens.GrayText; } + } + + #endregion + + #endregion + + public VS2005DockPaneStrip(DockPane pane) + : base(pane) + { + SetStyle(ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); + + SuspendLayout(); + + m_components = new Container(); + m_toolTip = new ToolTip(Components); + m_selectMenu = new ContextMenuStrip(Components); + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Components.Dispose(); + if (m_boldFont != null) + { + m_boldFont.Dispose(); + m_boldFont = null; + } + } + base.Dispose(disposing); + } + + protected internal override int MeasureHeight() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return MeasureHeight_ToolWindow(); + else + return MeasureHeight_Document(); + } + + private int MeasureHeight_ToolWindow() + { + if (DockPane.IsAutoHide || Tabs.Count <= 1) + return 0; + + int height = Math.Max(TextFont.Height, ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + + ToolWindowStripGapTop + ToolWindowStripGapBottom; + + return height; + } + + private int MeasureHeight_Document() + { + int height = Math.Max(TextFont.Height + DocumentTabGapTop, + ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + + DocumentStripGapBottom + DocumentStripGapTop; + + return height; + } + + protected override void OnPaint(PaintEventArgs e) + { + Rectangle rect = TabsRectangle; + + if (Appearance == DockPane.AppearanceStyle.Document) + { + rect.X -= DocumentTabGapLeft; + + // Add these values back in so that the DockStrip color is drawn + // beneath the close button and window list button. + rect.Width += DocumentTabGapLeft + + DocumentTabGapRight + + DocumentButtonGapRight + + ButtonClose.Width + + ButtonWindowList.Width; + + // It is possible depending on the DockPanel DocumentStyle to have + // a Document without a DockStrip. + if (rect.Width > 0 && rect.Height > 0) + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(rect, startColor, endColor, gradientMode)) + { + e.Graphics.FillRectangle(brush, rect); + } + } + } + else + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(rect, startColor, endColor, gradientMode)) + { + e.Graphics.FillRectangle(brush, rect); + } + } + base.OnPaint(e); + CalculateTabs(); + if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null) + { + if (EnsureDocumentTabVisible(DockPane.ActiveContent, false)) + CalculateTabs(); + } + + DrawTabStrip(e.Graphics); + } + + protected override void OnRefreshChanges() + { + SetInertButtons(); + Invalidate(); + } + + protected internal override GraphicsPath GetOutline(int index) + { + + if (Appearance == DockPane.AppearanceStyle.Document) + return GetOutline_Document(index); + else + return GetOutline_ToolWindow(index); + + } + + private GraphicsPath GetOutline_Document(int index) + { + Rectangle rectTab = GetTabRectangle(index); + rectTab.X -= rectTab.Height / 2; + rectTab.Intersect(TabsRectangle); + rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true); + path.AddPath(pathTab, true); + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + path.AddLine(rectTab.Right, rectTab.Top, rectPaneClient.Right, rectTab.Top); + path.AddLine(rectPaneClient.Right, rectTab.Top, rectPaneClient.Right, rectPaneClient.Top); + path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Left, rectPaneClient.Top); + path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Left, rectTab.Top); + path.AddLine(rectPaneClient.Left, rectTab.Top, rectTab.Right, rectTab.Top); + } + else + { + path.AddLine(rectTab.Right, rectTab.Bottom, rectPaneClient.Right, rectTab.Bottom); + path.AddLine(rectPaneClient.Right, rectTab.Bottom, rectPaneClient.Right, rectPaneClient.Bottom); + path.AddLine(rectPaneClient.Right, rectPaneClient.Bottom, rectPaneClient.Left, rectPaneClient.Bottom); + path.AddLine(rectPaneClient.Left, rectPaneClient.Bottom, rectPaneClient.Left, rectTab.Bottom); + path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); + } + return path; + } + + private GraphicsPath GetOutline_ToolWindow(int index) + { + Rectangle rectTab = GetTabRectangle(index); + rectTab.Intersect(TabsRectangle); + rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true); + path.AddPath(pathTab, true); + path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top); + path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top); + path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Right, rectPaneClient.Top); + path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); + path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); + return path; + } + + private void CalculateTabs() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + CalculateTabs_ToolWindow(); + else + CalculateTabs_Document(); + } + + private void CalculateTabs_ToolWindow() + { + if (Tabs.Count <= 1 || DockPane.IsAutoHide) + return; + + Rectangle rectTabStrip = TabStripRectangle; + + // Calculate tab widths + int countTabs = Tabs.Count; + foreach (TabVS2005 tab in Tabs) + { + tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); + tab.Flag = false; + } + + // Set tab whose max width less than average width + bool anyWidthWithinAverage = true; + int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; + int totalAllocatedWidth = 0; + int averageWidth = totalWidth / countTabs; + int remainedTabs = countTabs; + for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0; ) + { + anyWidthWithinAverage = false; + foreach (TabVS2005 tab in Tabs) + { + if (tab.Flag) + continue; + + if (tab.MaxWidth <= averageWidth) + { + tab.Flag = true; + tab.TabWidth = tab.MaxWidth; + totalAllocatedWidth += tab.TabWidth; + anyWidthWithinAverage = true; + remainedTabs--; + } + } + if (remainedTabs != 0) + averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; + } + + // If any tab width not set yet, set it to the average width + if (remainedTabs > 0) + { + int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); + foreach (TabVS2005 tab in Tabs) + { + if (tab.Flag) + continue; + + tab.Flag = true; + if (roundUpWidth > 0) + { + tab.TabWidth = averageWidth + 1; + roundUpWidth--; + } + else + tab.TabWidth = averageWidth; + } + } + + // Set the X position of the tabs + int x = rectTabStrip.X + ToolWindowStripGapLeft; + foreach (TabVS2005 tab in Tabs) + { + tab.TabX = x; + x += tab.TabWidth; + } + } + + private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index) + { + bool overflow = false; + + TabVS2005 tab = Tabs[index] as TabVS2005; + tab.MaxWidth = GetMaxTabWidth(index); + int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + if (x + width < rectTabStrip.Right || index == StartDisplayingTab) + { + tab.TabX = x; + tab.TabWidth = width; + EndDisplayingTab = index; + } + else + { + tab.TabX = 0; + tab.TabWidth = 0; + overflow = true; + } + x += width; + + return overflow; + } + + /// + /// Calculate which tabs are displayed and in what order. + /// + private void CalculateTabs_Document() + { + if (m_startDisplayingTab >= Tabs.Count) + m_startDisplayingTab = 0; + + Rectangle rectTabStrip = TabsRectangle; + + int x = rectTabStrip.X + rectTabStrip.Height / 2; + bool overflow = false; + + // Originally all new documents that were considered overflow + // (not enough pane strip space to show all tabs) were added to + // the far left (assuming not right to left) and the tabs on the + // right were dropped from view. If StartDisplayingTab is not 0 + // then we are dealing with making sure a specific tab is kept in focus. + if (m_startDisplayingTab > 0) + { + int tempX = x; + TabVS2005 tab = Tabs[m_startDisplayingTab] as TabVS2005; + tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); + + // Add the active tab and tabs to the left + for (int i = StartDisplayingTab; i >= 0; i--) + CalculateDocumentTab(rectTabStrip, ref tempX, i); + + // Store which tab is the first one displayed so that it + // will be drawn correctly (without part of the tab cut off) + FirstDisplayingTab = EndDisplayingTab; + + tempX = x; // Reset X location because we are starting over + + // Start with the first tab displayed - name is a little misleading. + // Loop through each tab and set its location. If there is not enough + // room for all of them overflow will be returned. + for (int i = EndDisplayingTab; i < Tabs.Count; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i); + + // If not all tabs are shown then we have an overflow. + if (FirstDisplayingTab != 0) + overflow = true; + } + else + { + for (int i = StartDisplayingTab; i < Tabs.Count; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref x, i); + for (int i = 0; i < StartDisplayingTab; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref x, i); + + FirstDisplayingTab = StartDisplayingTab; + } + + if (!overflow) + { + m_startDisplayingTab = 0; + FirstDisplayingTab = 0; + x = rectTabStrip.X + rectTabStrip.Height / 2; + foreach (TabVS2005 tab in Tabs) + { + tab.TabX = x; + x += tab.TabWidth; + } + } + DocumentTabsOverflow = overflow; + } + + protected internal override void EnsureTabVisible(IDockContent content) + { + if (Appearance != DockPane.AppearanceStyle.Document || !Tabs.Contains(content)) + return; + + CalculateTabs(); + EnsureDocumentTabVisible(content, true); + } + + private bool EnsureDocumentTabVisible(IDockContent content, bool repaint) + { + int index = Tabs.IndexOf(content); + TabVS2005 tab = Tabs[index] as TabVS2005; + if (tab.TabWidth != 0) + return false; + + StartDisplayingTab = index; + if (repaint) + Invalidate(); + + return true; + } + + private int GetMaxTabWidth(int index) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetMaxTabWidth_ToolWindow(index); + else + return GetMaxTabWidth_Document(index); + } + + private int GetMaxTabWidth_ToolWindow(int index) + { + IDockContent content = Tabs[index].Content; + Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); + return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + + ToolWindowImageGapRight + ToolWindowTextGapRight; + } + + private int GetMaxTabWidth_Document(int index) + { + IDockContent content = Tabs[index].Content; + + int height = GetTabRectangle_Document(index).Height; + + Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); + + if (DockPane.DockPanel.ShowDocumentIcon) + return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight; + else + return sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; + } + + private void DrawTabStrip(Graphics g) + { + if (Appearance == DockPane.AppearanceStyle.Document) + DrawTabStrip_Document(g); + else + DrawTabStrip_ToolWindow(g); + } + + private void DrawTabStrip_Document(Graphics g) + { + int count = Tabs.Count; + if (count == 0) + return; + + Rectangle rectTabStrip = TabStripRectangle; + + // Draw the tabs + Rectangle rectTabOnly = TabsRectangle; + Rectangle rectTab = Rectangle.Empty; + TabVS2005 tabActive = null; + g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); + for (int i = 0; i < count; i++) + { + rectTab = GetTabRectangle(i); + if (Tabs[i].Content == DockPane.ActiveContent) + { + tabActive = Tabs[i] as TabVS2005; + continue; + } + if (rectTab.IntersectsWith(rectTabOnly)) + DrawTab(g, Tabs[i] as TabVS2005, rectTab); + } + + g.SetClip(rectTabStrip); + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Top + 1, + rectTabStrip.Right, rectTabStrip.Top + 1); + else + g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Bottom - 1, + rectTabStrip.Right, rectTabStrip.Bottom - 1); + + g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); + if (tabActive != null) + { + rectTab = GetTabRectangle(Tabs.IndexOf(tabActive)); + if (rectTab.IntersectsWith(rectTabOnly)) + DrawTab(g, tabActive, rectTab); + } + } + + private void DrawTabStrip_ToolWindow(Graphics g) + { + Rectangle rectTabStrip = TabStripRectangle; + + g.DrawLine(PenToolWindowTabBorder, rectTabStrip.Left, rectTabStrip.Top, + rectTabStrip.Right, rectTabStrip.Top); + + for (int i = 0; i < Tabs.Count; i++) + DrawTab(g, Tabs[i] as TabVS2005, GetTabRectangle(i)); + } + + private Rectangle GetTabRectangle(int index) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetTabRectangle_ToolWindow(index); + else + return GetTabRectangle_Document(index); + } + + private Rectangle GetTabRectangle_ToolWindow(int index) + { + Rectangle rectTabStrip = TabStripRectangle; + + TabVS2005 tab = (TabVS2005)(Tabs[index]); + return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height); + } + + private Rectangle GetTabRectangle_Document(int index) + { + Rectangle rectTabStrip = TabStripRectangle; + TabVS2005 tab = (TabVS2005)Tabs[index]; + + Rectangle rect = new Rectangle(); + rect.X = tab.TabX; + rect.Width = tab.TabWidth; + rect.Height = rectTabStrip.Height - DocumentTabGapTop; + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + rect.Y = rectTabStrip.Y + DocumentStripGapBottom; + else + rect.Y = rectTabStrip.Y + DocumentTabGapTop; + + return rect; + } + + private void DrawTab(Graphics g, TabVS2005 tab, Rectangle rect) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + DrawTab_ToolWindow(g, tab, rect); + else + DrawTab_Document(g, tab, rect); + } + + private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen); + else + return GetTabOutline_Document(tab, rtlTransform, toScreen, false); + } + + private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) + { + Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + if (rtlTransform) + rect = DrawHelper.RtlTransform(this, rect); + if (toScreen) + rect = RectangleToScreen(rect); + + DrawHelper.GetRoundedCornerTab(GraphicsPath, rect, false); + return GraphicsPath; + } + + private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full) + { + int curveSize = 6; + + GraphicsPath.Reset(); + Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + if (rtlTransform) + rect = DrawHelper.RtlTransform(this, rect); + if (toScreen) + rect = RectangleToScreen(rect); + + // Draws the full angle piece for active content (or first tab) + if (tab.Content == DockPane.ActiveContent || full || Tabs.IndexOf(tab) == FirstDisplayingTab) + { + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top. + // It is not needed so it has been commented out. + //GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom); + GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Top, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom); + GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Bottom, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top. + // It is not needed so it has been commented out. + //GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left - rect.Height / 2, rect.Top); + GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Top, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left - rect.Height / 2, rect.Bottom); + GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Bottom, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2); + } + } + } + // Draws the partial angle for non-active content + else + { + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2); + } + } + } + + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // Draws the bottom horizontal line (short side) + GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom); + + // Drawing the rounded corner is not necessary. The path is automatically connected + //GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); + } + else + { + // Draws the bottom horizontal line (short side) + GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Top, rect.Left + curveSize / 2, rect.Top); + GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // Draws the bottom horizontal line (short side) + GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Bottom, rect.Right - curveSize / 2, rect.Bottom); + + // Drawing the rounded corner is not necessary. The path is automatically connected + //GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom, curveSize, curveSize), 90, -90); + } + else + { + // Draws the top horizontal line (short side) + GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top); + + // Draws the rounded corner oppposite the angled side + GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90); + } + } + + if (Tabs.IndexOf(tab) != EndDisplayingTab && + (Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent) + && !full) + { + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2, rect.Top); + } + else + { + GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2, rect.Bottom); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2, rect.Top); + } + else + { + GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2, rect.Bottom); + } + } + } + else + { + // Draw the vertical line opposite the angled side + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top); + else + GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Bottom); + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Top); + else + GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom); + } + } + + return GraphicsPath; + } + + private void DrawTab_ToolWindow(Graphics g, TabVS2005 tab, Rectangle rect) + { + Rectangle rectIcon = new Rectangle( + rect.X + ToolWindowImageGapLeft, + rect.Y + rect.Height - 1 - ToolWindowImageGapBottom - ToolWindowImageHeight, + ToolWindowImageWidth, ToolWindowImageHeight); + Rectangle rectText = rectIcon; + rectText.X += rectIcon.Width + ToolWindowImageGapRight; + rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - + ToolWindowImageGapRight - ToolWindowTextGapRight; + + Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + rectText = DrawHelper.RtlTransform(this, rectText); + rectIcon = DrawHelper.RtlTransform(this, rectIcon); + GraphicsPath path = GetTabOutline(tab, true, false); + if (DockPane.ActiveContent == tab.Content) + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); + g.DrawPath(PenToolWindowTabBorder, path); + + Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.TextColor; + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); + } + else + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); + + if (Tabs.IndexOf(DockPane.ActiveContent) != Tabs.IndexOf(tab) + 1) + { + Point pt1 = new Point(rect.Right, rect.Top + ToolWindowTabSeperatorGapTop); + Point pt2 = new Point(rect.Right, rect.Bottom - ToolWindowTabSeperatorGapBottom); + g.DrawLine(PenToolWindowTabBorder, DrawHelper.RtlTransform(this, pt1), DrawHelper.RtlTransform(this, pt2)); + } + + Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor; + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); + } + + if (rectTab.Contains(rectIcon)) + g.DrawIcon(new Icon(tab.Content.DockHandler.Icon, new Size(rectIcon.Width, rectIcon.Height)), rectIcon); + } + + private void DrawTab_Document(Graphics g, TabVS2005 tab, Rectangle rect) + { + if (tab.TabWidth == 0) + return; + + Rectangle rectIcon = new Rectangle( + rect.X + DocumentIconGapLeft, + rect.Y + rect.Height - 1 - DocumentIconGapBottom - DocumentIconHeight, + DocumentIconWidth, DocumentIconHeight); + Rectangle rectText = rectIcon; + rectIcon.Y += 1; + if (DockPane.DockPanel.ShowDocumentIcon) + { + rectText.X += rectIcon.Width + DocumentIconGapRight; + rectText.Y = rect.Y; + rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - + DocumentIconGapRight - DocumentTextGapRight; + rectText.Height = rect.Height; + } + else + rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight; + + Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + Rectangle rectBack = DrawHelper.RtlTransform(this, rect); + rectBack.Width += rect.X; + rectBack.X = 0; + + rectText = DrawHelper.RtlTransform(this, rectText); + rectIcon = DrawHelper.RtlTransform(this, rectIcon); + GraphicsPath path = GetTabOutline(tab, true, false); + if (DockPane.ActiveContent == tab.Content) + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); + g.DrawPath(PenDocumentTabActiveBorder, path); + + Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.TextColor; + if (DockPane.IsActiveDocumentPane) + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, BoldFont, rectText, textColor, DocumentTextFormat); + else + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); + } + else + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); + g.DrawPath(PenDocumentTabInactiveBorder, path); + + Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.TextColor; + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); + } + + if (rectTab.Contains(rectIcon) && DockPane.DockPanel.ShowDocumentIcon) + g.DrawIcon(new Icon(tab.Content.DockHandler.Icon, new Size(rectIcon.Width, rectIcon.Height)), rectIcon); + } + + private void WindowList_Click(object sender, EventArgs e) + { + int x = 0; + int y = ButtonWindowList.Location.Y + ButtonWindowList.Height; + + SelectMenu.Items.Clear(); + foreach (TabVS2005 tab in Tabs) + { + IDockContent content = tab.Content; + ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); + item.Tag = tab.Content; + item.Click += new EventHandler(ContextMenuItem_Click); + } + SelectMenu.Show(ButtonWindowList, x, y); + } + + private void ContextMenuItem_Click(object sender, EventArgs e) + { + ToolStripMenuItem item = sender as ToolStripMenuItem; + if (item != null) + { + IDockContent content = (IDockContent)item.Tag; + DockPane.ActiveContent = content; + } + } + + private void SetInertButtons() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + { + if (m_buttonClose != null) + m_buttonClose.Left = -m_buttonClose.Width; + + if (m_buttonWindowList != null) + m_buttonWindowList.Left = -m_buttonWindowList.Width; + } + else + { + ButtonClose.Enabled = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton; + m_closeButtonVisible = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButtonVisible; + ButtonClose.Visible = m_closeButtonVisible; + ButtonClose.RefreshChanges(); + ButtonWindowList.RefreshChanges(); + } + } + + protected override void OnLayout(LayoutEventArgs levent) + { + if (Appearance == DockPane.AppearanceStyle.Document) + { + LayoutButtons(); + OnRefreshChanges(); + } + + base.OnLayout(levent); + } + + private void LayoutButtons() + { + Rectangle rectTabStrip = TabStripRectangle; + + // Set position and size of the buttons + int buttonWidth = ButtonClose.Image.Width; + int buttonHeight = ButtonClose.Image.Height; + int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; + if (buttonHeight < height) + { + buttonWidth = buttonWidth * (height / buttonHeight); + buttonHeight = height; + } + Size buttonSize = new Size(buttonWidth, buttonHeight); + + int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft + - DocumentButtonGapRight - buttonWidth; + int y = rectTabStrip.Y + DocumentButtonGapTop; + Point point = new Point(x, y); + ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + + // If the close button is not visible draw the window list button overtop. + // Otherwise it is drawn to the left of the close button. + if (m_closeButtonVisible) + point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0); + + ButtonWindowList.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + } + + private void Close_Click(object sender, EventArgs e) + { + DockPane.CloseActiveContent(); + } + + public override int HitTest(Point ptMouse) + { + if (!TabsRectangle.Contains(ptMouse)) + return -1; + + foreach (Tab tab in Tabs) + { + GraphicsPath path = GetTabOutline(tab, true, false); + if (path.IsVisible(ptMouse)) + return Tabs.IndexOf(tab); + } + return -1; + } + + protected override void OnMouseHover(EventArgs e) + { + int index = HitTest(PointToClient(Control.MousePosition)); + string toolTip = string.Empty; + + base.OnMouseHover(e); + + if (index != -1) + { + TabVS2005 tab = Tabs[index] as TabVS2005; + if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) + toolTip = tab.Content.DockHandler.ToolTipText; + else if (tab.MaxWidth > tab.TabWidth) + toolTip = tab.Content.DockHandler.TabText; + } + + if (m_toolTip.GetToolTip(this) != toolTip) + { + m_toolTip.Active = false; + m_toolTip.SetToolTip(this, toolTip); + m_toolTip.Active = true; + } + + // requires further tracking of mouse hover behavior, + ResetMouseEventArgs(); + } + + protected override void OnRightToLeftChanged(EventArgs e) + { + base.OnRightToLeftChanged(e); + PerformLayout(); + } + } +} \ No newline at end of file diff --git a/WinFormsUI/Docking/VisibleNestedPaneCollection.cs b/WinFormsUI/Docking/VisibleNestedPaneCollection.cs new file mode 100644 index 0000000000..04d9b46777 --- /dev/null +++ b/WinFormsUI/Docking/VisibleNestedPaneCollection.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Windows.Forms; + +namespace WeifenLuo.WinFormsUI.Docking +{ + public sealed class VisibleNestedPaneCollection : ReadOnlyCollection + { + private NestedPaneCollection m_nestedPanes; + + internal VisibleNestedPaneCollection(NestedPaneCollection nestedPanes) + : base(new List()) + { + m_nestedPanes = nestedPanes; + } + + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + public INestedPanesContainer Container + { + get { return NestedPanes.Container; } + } + + public DockState DockState + { + get { return NestedPanes.DockState; } + } + + public bool IsFloat + { + get { return NestedPanes.IsFloat; } + } + + internal void Refresh() + { + Items.Clear(); + for (int i=0; i IndexOf(pane); i--) + { + if (this[i].NestedDockingStatus.PreviousPane == pane) + { + lastNestedPane = this[i]; + break; + } + } + + if (lastNestedPane != null) + { + int indexLastNestedPane = IndexOf(lastNestedPane); + Items.Remove(lastNestedPane); + Items[IndexOf(pane)] = lastNestedPane; + NestedDockingStatus lastNestedDock = lastNestedPane.NestedDockingStatus; + lastNestedDock.SetDisplayingStatus(true, statusPane.DisplayingPreviousPane, statusPane.DisplayingAlignment, statusPane.DisplayingProportion); + for (int i=indexLastNestedPane - 1; i>IndexOf(lastNestedPane); i--) + { + NestedDockingStatus status = this[i].NestedDockingStatus; + if (status.PreviousPane == pane) + status.SetDisplayingStatus(true, lastNestedPane, status.DisplayingAlignment, status.DisplayingProportion); + } + } + else + Items.Remove(pane); + + statusPane.SetDisplayingStatus(false, null, DockAlignment.Left, 0.5); + } + + private void CalculateBounds() + { + if (Count == 0) + return; + + this[0].NestedDockingStatus.SetDisplayingBounds(Container.DisplayingRectangle, Container.DisplayingRectangle, Rectangle.Empty); + + for (int i=1; i + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {C75532C4-765B-418E-B09B-46D36B2ABDB1} + Library + Properties + WeifenLuo.WinFormsUI + WeifenLuo.WinFormsUI.Docking + true + dockpanelsuite.snk + False + File + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + bin\Profile\ + TRACE + true + pdbonly + AnyCPU + prompt + false + false + + + + + + + + + + + + Component + + + Component + + + Form + + + Component + + + Component + + + Component + + + + + + + Component + + + Component + + + + + Form + + + + + Component + + + + + + UserControl + + + Component + + + Component + + + + Component + + + + Component + + + UserControl + + + Component + + + Component + + + Component + + + + Component + + + Component + + + + + Form + + + + Component + + + + + + Component + + + + + + + + True + True + Resources.resx + + + True + True + Strings.resx + + + + + + + Designer + ResXFileCodeGenerator + Resources.Designer.cs + + + Designer + ResXFileCodeGenerator + Strings.Designer.cs + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WinFormsUI/dockpanelsuite.snk b/WinFormsUI/dockpanelsuite.snk new file mode 100644 index 0000000000..39a8b183ce Binary files /dev/null and b/WinFormsUI/dockpanelsuite.snk differ diff --git a/WinFormsUI/license.txt b/WinFormsUI/license.txt new file mode 100644 index 0000000000..9d7cc58714 --- /dev/null +++ b/WinFormsUI/license.txt @@ -0,0 +1,9 @@ +The MIT License + +Copyright (c) 2007-2012 Weifen Luo (email: weifenluo@yahoo.com) and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/breakpad/LICENSE b/breakpad/LICENSE new file mode 100644 index 0000000000..95207bdf6f --- /dev/null +++ b/breakpad/LICENSE @@ -0,0 +1,50 @@ +Copyright (c) 2006, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +Copyright 2001-2004 Unicode, Inc. + +Disclaimer + +This source code is provided as is by Unicode, Inc. No claims are +made as to fitness for any particular purpose. No warranties of any +kind are expressed or implied. The recipient agrees to determine +applicability of information provided. If this file has been +purchased on magnetic or optical media from Unicode, Inc., the +sole remedy for any claim will be exchange of defective media +within 90 days of receipt. + +Limitations on Rights to Redistribute This Code + +Unicode, Inc. hereby grants the right to freely use the information +supplied in this file in the creation of products supporting the +Unicode Standard, and to make copies of this file in any form +for internal or external distribution as long as this notice +remains attached. diff --git a/breakpad/README b/breakpad/README new file mode 100644 index 0000000000..3bccd4be8d --- /dev/null +++ b/breakpad/README @@ -0,0 +1,43 @@ +Breakpad is a set of client and server components which implement a +crash-reporting system. + + +----- +Getting started in 32-bit mode (from trunk) +Configure: CXXFLAGS=-m32 CFLAGS=-m32 CPPFLAGS=-m32 ./configure + Build: make + Test: make check + Install: make install + +If you need to reconfigure your build be sure to run "make distclean" first. + + +----- +To request change review: +0. Get access to a read-write copy of source. + Owners at http://code.google.com/p/google-breakpad/ are able to grant + this access. + +1. Check out a read-write copy of source using instructions at + http://code.google.com/p/google-breakpad/source/checkout + +2. Make changes. Build and test your changes. + For core code like processor use methods above. + For linux/mac/windows, there are test targets in each project file. + +3. Download http://codereview.appspot.com/static/upload.py + +4. Run upload.py from the 'src' directory: + upload.py --server=breakpad.appspot.com + + You will be prompted for credential and a description. + +5. At http://breakpad.appspot.com you'll find your issue listed; click on it, + and select Publish+Mail, and enter in the code reviewer and CC + google-breakpad-dev@googlegroups.com + +6. When applying code review feedback, specify the '-i' option when running + upload.py again and pass the issue number so it updates the existing issue, + rather than creating a new one. + Be sure to rerun upload.py from the same directory as you did for previous + uploads to allow for proper diff calculations. diff --git a/breakpad/breakpad.sln b/breakpad/breakpad.sln new file mode 100644 index 0000000000..06dc919b10 --- /dev/null +++ b/breakpad/breakpad.sln @@ -0,0 +1,73 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "breakpad_common", "client\windows\common.vcxproj", "{EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_client", "client\windows\crash_generation\crash_generation_client.vcxproj", "{EC847717-119A-2391-0477-212E1140082C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_server", "client\windows\crash_generation\crash_generation_server.vcxproj", "{7893E300-3ED0-7F4C-158F-67EA63934C57}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler", "client\windows\handler\exception_handler.vcxproj", "{B7399F39-300F-450E-F471-9490F959D2A7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Purify|Win32 = Purify|Win32 + Purify|x64 = Purify|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|Win32.Build.0 = Debug|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|x64.ActiveCfg = Debug|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|x64.Build.0 = Debug|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|Win32.ActiveCfg = Purify|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|Win32.Build.0 = Purify|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|x64.ActiveCfg = Purify|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|x64.Build.0 = Purify|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|Win32.ActiveCfg = Release|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|Win32.Build.0 = Release|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|x64.ActiveCfg = Release|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|x64.Build.0 = Release|x64 + {EC847717-119A-2391-0477-212E1140082C}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Debug|Win32.Build.0 = Debug|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Debug|x64.ActiveCfg = Debug|x64 + {EC847717-119A-2391-0477-212E1140082C}.Debug|x64.Build.0 = Debug|x64 + {EC847717-119A-2391-0477-212E1140082C}.Purify|Win32.ActiveCfg = Purify|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Purify|Win32.Build.0 = Purify|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Purify|x64.ActiveCfg = Purify|x64 + {EC847717-119A-2391-0477-212E1140082C}.Purify|x64.Build.0 = Purify|x64 + {EC847717-119A-2391-0477-212E1140082C}.Release|Win32.ActiveCfg = Release|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Release|Win32.Build.0 = Release|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Release|x64.ActiveCfg = Release|x64 + {EC847717-119A-2391-0477-212E1140082C}.Release|x64.Build.0 = Release|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|Win32.ActiveCfg = Debug|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|Win32.Build.0 = Debug|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|x64.ActiveCfg = Debug|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|x64.Build.0 = Debug|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|Win32.ActiveCfg = Purify|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|Win32.Build.0 = Purify|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|x64.ActiveCfg = Purify|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|x64.Build.0 = Purify|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|Win32.ActiveCfg = Release|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|Win32.Build.0 = Release|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|x64.ActiveCfg = Release|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|x64.Build.0 = Release|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|Win32.ActiveCfg = Debug|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|Win32.Build.0 = Debug|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|x64.ActiveCfg = Debug|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|x64.Build.0 = Debug|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|Win32.ActiveCfg = Purify|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|Win32.Build.0 = Purify|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|x64.ActiveCfg = Purify|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|x64.Build.0 = Purify|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|Win32.ActiveCfg = Release|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|Win32.Build.0 = Release|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|x64.ActiveCfg = Release|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/breakpad/client/minidump_file_writer-inl.h b/breakpad/client/minidump_file_writer-inl.h new file mode 100644 index 0000000000..0e12e00b69 --- /dev/null +++ b/breakpad/client/minidump_file_writer-inl.h @@ -0,0 +1,97 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// minidump_file_writer-inl.h: Minidump file writer implementation. +// +// See minidump_file_writer.h for documentation. + +#ifndef CLIENT_MINIDUMP_FILE_WRITER_INL_H__ +#define CLIENT_MINIDUMP_FILE_WRITER_INL_H__ + +#include + +#include "client/minidump_file_writer.h" +#include "google_breakpad/common/minidump_size.h" + +namespace google_breakpad { + +template +inline bool TypedMDRVA::Allocate() { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size()); +} + +template +inline bool TypedMDRVA::Allocate(size_t additional) { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size() + additional); +} + +template +inline bool TypedMDRVA::AllocateArray(size_t count) { + assert(count); + allocation_state_ = ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() * count); +} + +template +inline bool TypedMDRVA::AllocateObjectAndArray(size_t count, + size_t length) { + assert(count && length); + allocation_state_ = SINGLE_OBJECT_WITH_ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() + count * length); +} + +template +inline bool TypedMDRVA::CopyIndex(unsigned int index, MDType *item) { + assert(allocation_state_ == ARRAY); + return writer_->Copy( + static_cast(position_ + index * minidump_size::size()), + item, minidump_size::size()); +} + +template +inline bool TypedMDRVA::CopyIndexAfterObject(unsigned int index, + const void *src, + size_t length) { + assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY); + return writer_->Copy( + static_cast(position_ + minidump_size::size() + + index * length), + src, length); +} + +template +inline bool TypedMDRVA::Flush() { + return writer_->Copy(position_, &data_, minidump_size::size()); +} + +} // namespace google_breakpad + +#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__ diff --git a/breakpad/client/minidump_file_writer.cc b/breakpad/client/minidump_file_writer.cc new file mode 100644 index 0000000000..1e18d24ba2 --- /dev/null +++ b/breakpad/client/minidump_file_writer.cc @@ -0,0 +1,284 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// minidump_file_writer.cc: Minidump file writer implementation. +// +// See minidump_file_writer.h for documentation. + +#include +#include +#include +#include +#include + +#include "client/minidump_file_writer-inl.h" +#include "common/linux/linux_libc_support.h" +#include "common/string_conversion.h" +#if __linux__ +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace google_breakpad { + +const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast(-1); + +MinidumpFileWriter::MinidumpFileWriter() + : file_(-1), + close_file_when_destroyed_(true), + position_(0), + size_(0) { +} + +MinidumpFileWriter::~MinidumpFileWriter() { + if (close_file_when_destroyed_) + Close(); +} + +bool MinidumpFileWriter::Open(const char *path) { + assert(file_ == -1); +#if __linux__ + file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); +#else + file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif + + return file_ != -1; +} + +void MinidumpFileWriter::SetFile(const int file) { + assert(file_ == -1); + file_ = file; + close_file_when_destroyed_ = false; +} + +bool MinidumpFileWriter::Close() { + bool result = true; + + if (file_ != -1) { + if (-1 == ftruncate(file_, position_)) { + return false; + } +#if __linux__ + result = (sys_close(file_) == 0); +#else + result = (close(file_) == 0); +#endif + file_ = -1; + } + + return result; +} + +bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, + unsigned int length, + TypedMDRVA *mdstring) { + bool result = true; + if (sizeof(wchar_t) == sizeof(uint16_t)) { + // Shortcut if wchar_t is the same size as MDString's buffer + result = mdstring->Copy(str, mdstring->get()->length); + } else { + uint16_t out[2]; + int out_idx = 0; + + // Copy the string character by character + while (length && result) { + UTF32ToUTF16Char(*str, out); + if (!out[0]) + return false; + + // Process one character at a time + --length; + ++str; + + // Append the one or two UTF-16 characters. The first one will be non- + // zero, but the second one may be zero, depending on the conversion from + // UTF-32. + int out_count = out[1] ? 2 : 1; + size_t out_size = sizeof(uint16_t) * out_count; + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); + out_idx += out_count; + } + } + return result; +} + +bool MinidumpFileWriter::CopyStringToMDString(const char *str, + unsigned int length, + TypedMDRVA *mdstring) { + bool result = true; + uint16_t out[2]; + int out_idx = 0; + + // Copy the string character by character + while (length && result) { + int conversion_count = UTF8ToUTF16Char(str, length, out); + if (!conversion_count) + return false; + + // Move the pointer along based on the nubmer of converted characters + length -= conversion_count; + str += conversion_count; + + // Append the one or two UTF-16 characters + int out_count = out[1] ? 2 : 1; + size_t out_size = sizeof(uint16_t) * out_count; + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); + out_idx += out_count; + } + return result; +} + +template +bool MinidumpFileWriter::WriteStringCore(const CharType *str, + unsigned int length, + MDLocationDescriptor *location) { + assert(str); + assert(location); + // Calculate the mdstring length by either limiting to |length| as passed in + // or by finding the location of the NULL character. + unsigned int mdstring_length = 0; + if (!length) + length = INT_MAX; + for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) + ; + + // Allocate the string buffer + TypedMDRVA mdstring(this); + if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t))) + return false; + + // Set length excluding the NULL and copy the string + mdstring.get()->length = + static_cast(mdstring_length * sizeof(uint16_t)); + bool result = CopyStringToMDString(str, mdstring_length, &mdstring); + + // NULL terminate + if (result) { + uint16_t ch = 0; + result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch)); + + if (result) + *location = mdstring.location(); + } + + return result; +} + +bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length, + MDLocationDescriptor *location) { + return WriteStringCore(str, length, location); +} + +bool MinidumpFileWriter::WriteString(const char *str, unsigned int length, + MDLocationDescriptor *location) { + return WriteStringCore(str, length, location); +} + +bool MinidumpFileWriter::WriteMemory(const void *src, size_t size, + MDMemoryDescriptor *output) { + assert(src); + assert(output); + UntypedMDRVA mem(this); + + if (!mem.Allocate(size)) + return false; + if (!mem.Copy(src, mem.size())) + return false; + + output->start_of_memory_range = reinterpret_cast(src); + output->memory = mem.location(); + + return true; +} + +MDRVA MinidumpFileWriter::Allocate(size_t size) { + assert(size); + assert(file_ != -1); + size_t aligned_size = (size + 7) & ~7; // 64-bit alignment + + if (position_ + aligned_size > size_) { + size_t growth = aligned_size; + size_t minimal_growth = getpagesize(); + + // Ensure that the file grows by at least the size of a memory page + if (growth < minimal_growth) + growth = minimal_growth; + + size_t new_size = size_ + growth; + if (ftruncate(file_, new_size) != 0) + return kInvalidMDRVA; + + size_ = new_size; + } + + MDRVA current_position = position_; + position_ += static_cast(aligned_size); + + return current_position; +} + +bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { + assert(src); + assert(size); + assert(file_ != -1); + + // Ensure that the data will fit in the allocated space + if (static_cast(size + position) > size_) + return false; + + // Seek and write the data +#if __linux__ + if (sys_lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (sys_write(file_, src, size) == size) { +#else + if (lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (write(file_, src, size) == size) { +#endif + return true; + } + } + + return false; +} + +bool UntypedMDRVA::Allocate(size_t size) { + assert(size_ == 0); + size_ = size; + position_ = writer_->Allocate(size_); + return position_ != MinidumpFileWriter::kInvalidMDRVA; +} + +bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) { + assert(src); + assert(size); + assert(pos + size <= position_ + size_); + return writer_->Copy(pos, src, size); +} + +} // namespace google_breakpad diff --git a/breakpad/client/minidump_file_writer.h b/breakpad/client/minidump_file_writer.h new file mode 100644 index 0000000000..538e85453f --- /dev/null +++ b/breakpad/client/minidump_file_writer.h @@ -0,0 +1,272 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// minidump_file_writer.h: Implements file-based minidump generation. It's +// intended to be used with the Google Breakpad open source crash handling +// project. + +#ifndef CLIENT_MINIDUMP_FILE_WRITER_H__ +#define CLIENT_MINIDUMP_FILE_WRITER_H__ + +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class UntypedMDRVA; +template class TypedMDRVA; + +// The user of this class can Open() a file and add minidump streams, data, and +// strings using the definitions in minidump_format.h. Since this class is +// expected to be used in a situation where the current process may be +// damaged, it will not allocate heap memory. +// Sample usage: +// MinidumpFileWriter writer; +// writer.Open("/tmp/minidump.dmp"); +// TypedMDRVA header(&writer_); +// header.Allocate(); +// header->get()->signature = MD_HEADER_SIGNATURE; +// : +// writer.Close(); +// +// An alternative is to use SetFile and provide a file descriptor: +// MinidumpFileWriter writer; +// writer.SetFile(minidump_fd); +// TypedMDRVA header(&writer_); +// header.Allocate(); +// header->get()->signature = MD_HEADER_SIGNATURE; +// : +// writer.Close(); + +class MinidumpFileWriter { +public: + // Invalid MDRVA (Minidump Relative Virtual Address) + // returned on failed allocation + static const MDRVA kInvalidMDRVA; + + MinidumpFileWriter(); + ~MinidumpFileWriter(); + + // Open |path| as the destination of the minidump data. Any existing file + // will be overwritten. + // Return true on success, or false on failure. + bool Open(const char *path); + + // Sets the file descriptor |file| as the destination of the minidump data. + // Can be used as an alternative to Open() when a file descriptor is + // available. + // Note that |fd| is not closed when the instance of MinidumpFileWriter is + // destroyed. + void SetFile(const int file); + + // Close the current file (that was either created when Open was called, or + // specified with SetFile). + // Return true on success, or false on failure. + bool Close(); + + // Copy the contents of |str| to a MDString and write it to the file. + // |str| is expected to be either UTF-16 or UTF-32 depending on the size + // of wchar_t. + // Maximum |length| of characters to copy from |str|, or specify 0 to use the + // entire NULL terminated string. Copying will stop at the first NULL. + // |location| the allocated location + // Return true on success, or false on failure + bool WriteString(const wchar_t *str, unsigned int length, + MDLocationDescriptor *location); + + // Same as above, except with |str| as a UTF-8 string + bool WriteString(const char *str, unsigned int length, + MDLocationDescriptor *location); + + // Write |size| bytes starting at |src| into the current position. + // Return true on success and set |output| to position, or false on failure + bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output); + + // Copies |size| bytes from |src| to |position| + // Return true on success, or false on failure + bool Copy(MDRVA position, const void *src, ssize_t size); + + // Return the current position for writing to the minidump + inline MDRVA position() const { return position_; } + + private: + friend class UntypedMDRVA; + + // Allocates an area of |size| bytes. + // Returns the position of the allocation, or kInvalidMDRVA if it was + // unable to allocate the bytes. + MDRVA Allocate(size_t size); + + // The file descriptor for the output file. + int file_; + + // Whether |file_| should be closed when the instance is destroyed. + bool close_file_when_destroyed_; + + // Current position in buffer + MDRVA position_; + + // Current allocated size + size_t size_; + + // Copy |length| characters from |str| to |mdstring|. These are distinct + // because the underlying MDString is a UTF-16 based string. The wchar_t + // variant may need to create a MDString that has more characters than the + // source |str|, whereas the UTF-8 variant may coalesce characters to form + // a single UTF-16 character. + bool CopyStringToMDString(const wchar_t *str, unsigned int length, + TypedMDRVA *mdstring); + bool CopyStringToMDString(const char *str, unsigned int length, + TypedMDRVA *mdstring); + + // The common templated code for writing a string + template + bool WriteStringCore(const CharType *str, unsigned int length, + MDLocationDescriptor *location); +}; + +// Represents an untyped allocated chunk +class UntypedMDRVA { + public: + explicit UntypedMDRVA(MinidumpFileWriter *writer) + : writer_(writer), + position_(writer->position()), + size_(0) {} + + // Allocates |size| bytes. Must not call more than once. + // Return true on success, or false on failure + bool Allocate(size_t size); + + // Returns the current position or kInvalidMDRVA if allocation failed + inline MDRVA position() const { return position_; } + + // Number of bytes allocated + inline size_t size() const { return size_; } + + // Return size and position + inline MDLocationDescriptor location() const { + MDLocationDescriptor location = { static_cast(size_), + position_ }; + return location; + } + + // Copy |size| bytes starting at |src| into the minidump at |position| + // Return true on success, or false on failure + bool Copy(MDRVA position, const void *src, size_t size); + + // Copy |size| bytes from |src| to the current position + inline bool Copy(const void *src, size_t size) { + return Copy(position_, src, size); + } + + protected: + // Writer we associate with + MinidumpFileWriter *writer_; + + // Position of the start of the data + MDRVA position_; + + // Allocated size + size_t size_; +}; + +// Represents a Minidump object chunk. Additional memory can be allocated at +// the end of the object as a: +// - single allocation +// - Array of MDType objects +// - A MDType object followed by an array +template +class TypedMDRVA : public UntypedMDRVA { + public: + // Constructs an unallocated MDRVA + explicit TypedMDRVA(MinidumpFileWriter *writer) + : UntypedMDRVA(writer), + data_(), + allocation_state_(UNALLOCATED) {} + + inline ~TypedMDRVA() { + // Ensure that the data_ object is written out + if (allocation_state_ != ARRAY) + Flush(); + } + + // Address of object data_ of MDType. This is not declared const as the + // typical usage will be to access the underlying |data_| object as to + // alter its contents. + MDType *get() { return &data_; } + + // Allocates minidump_size::size() bytes. + // Must not call more than once. + // Return true on success, or false on failure + bool Allocate(); + + // Allocates minidump_size::size() + |additional| bytes. + // Must not call more than once. + // Return true on success, or false on failure + bool Allocate(size_t additional); + + // Allocate an array of |count| elements of MDType. + // Must not call more than once. + // Return true on success, or false on failure + bool AllocateArray(size_t count); + + // Allocate an array of |count| elements of |size| after object of MDType + // Must not call more than once. + // Return true on success, or false on failure + bool AllocateObjectAndArray(size_t count, size_t size); + + // Copy |item| to |index| + // Must have been allocated using AllocateArray(). + // Return true on success, or false on failure + bool CopyIndex(unsigned int index, MDType *item); + + // Copy |size| bytes starting at |str| to |index| + // Must have been allocated using AllocateObjectAndArray(). + // Return true on success, or false on failure + bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size); + + // Write data_ + bool Flush(); + + private: + enum AllocationState { + UNALLOCATED = 0, + SINGLE_OBJECT, + ARRAY, + SINGLE_OBJECT_WITH_ARRAY + }; + + MDType data_; + AllocationState allocation_state_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_MINIDUMP_FILE_WRITER_H__ diff --git a/breakpad/client/minidump_file_writer_unittest.cc b/breakpad/client/minidump_file_writer_unittest.cc new file mode 100644 index 0000000000..60c364e689 --- /dev/null +++ b/breakpad/client/minidump_file_writer_unittest.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: waylonis@google.com (Dan Waylonis) + +/* + g++ -I../ ../common/convert_UTF.c \ + ../common/string_conversion.cc \ + minidump_file_writer.cc \ + minidump_file_writer_unittest.cc \ + -o minidump_file_writer_unittest + */ + +#include +#include + +#include "minidump_file_writer-inl.h" + +using google_breakpad::MinidumpFileWriter; + +#define ASSERT_TRUE(cond) \ +if (!(cond)) { \ + fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ + return false; \ +} + +#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) +#define ASSERT_NE(e1, e2) ASSERT_TRUE((e1) != (e2)) + +struct StringStructure { + unsigned long integer_value; + MDLocationDescriptor first_string; + MDLocationDescriptor second_string; +}; + +struct ArrayStructure { + unsigned char char_value; + unsigned short short_value; + unsigned long long_value; +}; + +typedef struct { + unsigned long count; + ArrayStructure array[0]; +} ObjectAndArrayStructure; + +static bool WriteFile(const char *path) { + MinidumpFileWriter writer; + if (writer.Open(path)) { + // Test a single structure + google_breakpad::TypedMDRVA strings(&writer); + ASSERT_TRUE(strings.Allocate()); + strings.get()->integer_value = 0xBEEF; + const char *first = "First String"; + ASSERT_TRUE(writer.WriteString(first, 0, &strings.get()->first_string)); + const wchar_t *second = L"Second String"; + ASSERT_TRUE(writer.WriteString(second, 0, &strings.get()->second_string)); + + // Test an array structure + google_breakpad::TypedMDRVA array(&writer); + unsigned int count = 10; + ASSERT_TRUE(array.AllocateArray(count)); + for (unsigned char i = 0; i < count; ++i) { + ArrayStructure local; + local.char_value = i; + local.short_value = i + 1; + local.long_value = i + 2; + ASSERT_TRUE(array.CopyIndex(i, &local)); + } + + // Test an object followed by an array + google_breakpad::TypedMDRVA obj_array(&writer); + ASSERT_TRUE(obj_array.AllocateObjectAndArray(count, + sizeof(ArrayStructure))); + obj_array.get()->count = count; + for (unsigned char i = 0; i < count; ++i) { + ArrayStructure local; + local.char_value = i; + local.short_value = i + 1; + local.long_value = i + 2; + ASSERT_TRUE(obj_array.CopyIndexAfterObject(i, &local, sizeof(local))); + } + } + + return writer.Close(); +} + +static bool CompareFile(const char *path) { + unsigned long expected[] = { +#if defined(__BIG_ENDIAN__) + 0x0000beef, 0x0000001e, 0x00000018, 0x00000020, 0x00000038, 0x00000000, + 0x00000018, 0x00460069, 0x00720073, 0x00740020, 0x00530074, 0x00720069, + 0x006e0067, 0x00000000, 0x0000001a, 0x00530065, 0x0063006f, 0x006e0064, + 0x00200053, 0x00740072, 0x0069006e, 0x00670000, 0x00000001, 0x00000002, + 0x01000002, 0x00000003, 0x02000003, 0x00000004, 0x03000004, 0x00000005, + 0x04000005, 0x00000006, 0x05000006, 0x00000007, 0x06000007, 0x00000008, + 0x07000008, 0x00000009, 0x08000009, 0x0000000a, 0x0900000a, 0x0000000b, + 0x0000000a, 0x00000001, 0x00000002, 0x01000002, 0x00000003, 0x02000003, + 0x00000004, 0x03000004, 0x00000005, 0x04000005, 0x00000006, 0x05000006, + 0x00000007, 0x06000007, 0x00000008, 0x07000008, 0x00000009, 0x08000009, + 0x0000000a, 0x0900000a, 0x0000000b, 0x00000000 +#else + 0x0000beef, 0x0000001e, 0x00000018, 0x00000020, + 0x00000038, 0x00000000, 0x00000018, 0x00690046, + 0x00730072, 0x00200074, 0x00740053, 0x00690072, + 0x0067006e, 0x00000000, 0x0000001a, 0x00650053, + 0x006f0063, 0x0064006e, 0x00530020, 0x00720074, + 0x006e0069, 0x00000067, 0x00011e00, 0x00000002, + 0x00021e01, 0x00000003, 0x00031e02, 0x00000004, + 0x00041e03, 0x00000005, 0x00051e04, 0x00000006, + 0x00061e05, 0x00000007, 0x00071e06, 0x00000008, + 0x00081e07, 0x00000009, 0x00091e08, 0x0000000a, + 0x000a1e09, 0x0000000b, 0x0000000a, 0x00011c00, + 0x00000002, 0x00021c01, 0x00000003, 0x00031c02, + 0x00000004, 0x00041c03, 0x00000005, 0x00051c04, + 0x00000006, 0x00061c05, 0x00000007, 0x00071c06, + 0x00000008, 0x00081c07, 0x00000009, 0x00091c08, + 0x0000000a, 0x000a1c09, 0x0000000b, 0x00000000, +#endif + }; + size_t expected_byte_count = sizeof(expected); + int fd = open(path, O_RDONLY, 0600); + void *buffer = malloc(expected_byte_count); + ASSERT_NE(fd, -1); + ASSERT_TRUE(buffer); + ASSERT_EQ(read(fd, buffer, expected_byte_count), + static_cast(expected_byte_count)); + + char *b1, *b2; + b1 = reinterpret_cast(buffer); + b2 = reinterpret_cast(expected); + while (*b1 == *b2) { + b1++; + b2++; + } + + printf("%p\n", reinterpret_cast(b1 - (char*)buffer)); + + ASSERT_EQ(memcmp(buffer, expected, expected_byte_count), 0); + return true; +} + +static bool RunTests() { + const char *path = "/tmp/minidump_file_writer_unittest.dmp"; + ASSERT_TRUE(WriteFile(path)); + ASSERT_TRUE(CompareFile(path)); + unlink(path); + return true; +} + +extern "C" int main(int argc, const char *argv[]) { + return RunTests() ? 0 : 1; +} diff --git a/breakpad/client/windows/common.vcxproj b/breakpad/client/windows/common.vcxproj new file mode 100644 index 0000000000..777695ff9c --- /dev/null +++ b/breakpad/client/windows/common.vcxproj @@ -0,0 +1,384 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Purify + Win32 + + + Purify + x64 + + + Release + Win32 + + + Release + x64 + + + + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7} + Win32Proj + common + breakpad_common + + + + Unicode + StaticLibrary + + + + + + + + + $(ExecutablePath);$(MSBuildProjectDirectory)\..\..\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\..\third_party\python_26\ + $(SolutionDir)$(Configuration)\$(Platform)\ + $(OutDir)obj\$(ProjectName)\ + false + false + false + false + true + true + $(ProjectName) + $(OutDir)\$(ProjectName).lib + + + + ..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../..;..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + ..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../..;..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + + + + + ..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../..;..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + false + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + false + true + $(OutDir)\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../..;..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + false + false + true + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + true + Level4 + + + ../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + true + false + true + $(OutDir)\$(TargetName).lib + $(OutDir)$(TargetName).map + true + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../..;..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib32\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib32\ + + + + + ..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + false + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + Level4 + + + ../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../..;..\..;..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib64\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib64\ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/breakpad/client/windows/common.vcxproj.filters b/breakpad/client/windows/common.vcxproj.filters new file mode 100644 index 0000000000..d6285c77a6 --- /dev/null +++ b/breakpad/client/windows/common.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} + + + {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} + + + {2F5FD094-EF52-77F7-7AA8-4327A01BF747} + + + {C1450D01-C033-76F3-3763-6DE88AF48A77} + + + + + + + + ..\..\common\windows + + + ..\..\common\windows + + + ..\..\common\windows + + + + + ..\..\common\windows + + + ..\..\common\windows + + + \ No newline at end of file diff --git a/breakpad/client/windows/common/auto_critical_section.h b/breakpad/client/windows/common/auto_critical_section.h new file mode 100644 index 0000000000..40287427f2 --- /dev/null +++ b/breakpad/client/windows/common/auto_critical_section.h @@ -0,0 +1,81 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ +#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ + +#include + +namespace google_breakpad { + +// Automatically enters the critical section in the constructor and leaves +// the critical section in the destructor. +class AutoCriticalSection { + public: + // Creates a new instance with the given critical section object + // and enters the critical section immediately. + explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs), taken_(false) { + assert(cs_); + Acquire(); + } + + // Destructor: leaves the critical section. + ~AutoCriticalSection() { + if (taken_) { + Release(); + } + } + + // Enters the critical section. Recursive Acquire() calls are not allowed. + void Acquire() { + assert(!taken_); + EnterCriticalSection(cs_); + taken_ = true; + } + + // Leaves the critical section. The caller should not call Release() unless + // the critical seciton has been entered already. + void Release() { + assert(taken_); + taken_ = false; + LeaveCriticalSection(cs_); + } + + private: + // Disable copy ctor and operator=. + AutoCriticalSection(const AutoCriticalSection&); + AutoCriticalSection& operator=(const AutoCriticalSection&); + + CRITICAL_SECTION* cs_; + bool taken_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ diff --git a/breakpad/client/windows/common/ipc_protocol.h b/breakpad/client/windows/common/ipc_protocol.h new file mode 100644 index 0000000000..a9239ec20c --- /dev/null +++ b/breakpad/client/windows/common/ipc_protocol.h @@ -0,0 +1,208 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ +#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ + +#include +#include +#include +#include +#include "common/windows/string_utils-inl.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// These entries store a list of memory regions that the client wants included +// in the minidump. +struct AppMemory { + ULONG64 ptr; + ULONG length; + + bool operator==(const struct AppMemory& other) const { + return ptr == other.ptr; + } + + bool operator==(const void* other) const { + return ptr == reinterpret_cast(other); + } +}; + +struct AppMemoryInfo { + AppMemoryInfo() : entries(NULL), count(0) {} + const AppMemory* entries; + ULONG count; +}; + +// Name/value pair for custom client information. +struct CustomInfoEntry { + // Maximum length for name and value for client custom info. + static const int kNameMaxLength = 64; + static const int kValueMaxLength = 320; // large enough for MAX_PATH + + CustomInfoEntry() { + // Putting name and value in initializer list makes VC++ show warning 4351. + set_name(NULL); + set_value(NULL); + } + + CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) { + set_name(name_arg); + set_value(value_arg); + } + + void set_name(const wchar_t* name_arg) { + if (!name_arg) { + name[0] = L'\0'; + return; + } + WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg); + } + + void set_value(const wchar_t* value_arg) { + if (!value_arg) { + value[0] = L'\0'; + return; + } + + WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg); + } + + void set(const wchar_t* name_arg, const wchar_t* value_arg) { + set_name(name_arg); + set_value(value_arg); + } + + wchar_t name[kNameMaxLength]; + wchar_t value[kValueMaxLength]; +}; + +// Constants for the protocol between client and the server. + +// Tags sent with each message indicating the purpose of +// the message. +enum MessageTag { + MESSAGE_TAG_NONE = 0, + MESSAGE_TAG_REGISTRATION_REQUEST = 1, + MESSAGE_TAG_REGISTRATION_RESPONSE = 2, + MESSAGE_TAG_REGISTRATION_ACK = 3, + MESSAGE_TAG_UPLOAD_REQUEST = 4 +}; + +struct CustomClientInfo { + const CustomInfoEntry* entries; + size_t count; +}; + +// Message structure for IPC between crash client and crash server. +struct ProtocolMessage { + ProtocolMessage() + : tag(MESSAGE_TAG_NONE), + id(0), + dump_type(MiniDumpNormal), + thread_id(0), + exception_pointers(NULL), + assert_info(NULL), + custom_client_info(), + app_memory_info(NULL), + dump_request_handle(NULL), + dump_generated_handle(NULL), + server_alive_handle(NULL) { + } + + // Creates an instance with the given parameters. + ProtocolMessage(MessageTag arg_tag, + DWORD arg_id, + MINIDUMP_TYPE arg_dump_type, + DWORD* arg_thread_id, + EXCEPTION_POINTERS** arg_exception_pointers, + MDRawAssertionInfo* arg_assert_info, + const CustomClientInfo& custom_info, + AppMemoryInfo* app_mem_info, + HANDLE arg_dump_request_handle, + HANDLE arg_dump_generated_handle, + HANDLE arg_server_alive) + : tag(arg_tag), + id(arg_id), + dump_type(arg_dump_type), + thread_id(arg_thread_id), + exception_pointers(arg_exception_pointers), + assert_info(arg_assert_info), + custom_client_info(custom_info), + app_memory_info(app_mem_info), + dump_request_handle(arg_dump_request_handle), + dump_generated_handle(arg_dump_generated_handle), + server_alive_handle(arg_server_alive) { + } + + // Tag in the message. + MessageTag tag; + + // The id for this message. This may be either a process id or a crash id + // depending on the type of message. + DWORD id; + + // Dump type requested. + MINIDUMP_TYPE dump_type; + + // Client thread id pointer. + DWORD* thread_id; + + // Exception information. + EXCEPTION_POINTERS** exception_pointers; + + // Assert information in case of an invalid parameter or + // pure call failure. + MDRawAssertionInfo* assert_info; + + // Custom specified app regions of memory + AppMemoryInfo* app_memory_info; + + // Custom client information. + CustomClientInfo custom_client_info; + + // Handle to signal the crash event. + HANDLE dump_request_handle; + + // Handle to check if server is done generating crash. + HANDLE dump_generated_handle; + + // Handle to a mutex that becomes signaled (WAIT_ABANDONED) + // if server process goes down. + HANDLE server_alive_handle; + + private: + // Disable copy ctor and operator=. + ProtocolMessage(const ProtocolMessage& msg); + ProtocolMessage& operator=(const ProtocolMessage& msg); +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ diff --git a/breakpad/client/windows/crash_generation/ReadMe.txt b/breakpad/client/windows/crash_generation/ReadMe.txt new file mode 100644 index 0000000000..b54d0e11b7 --- /dev/null +++ b/breakpad/client/windows/crash_generation/ReadMe.txt @@ -0,0 +1,58 @@ +========================================================================= + State machine transitions for the Crash Generation Server +========================================================================= + +========================================================================= + | + STATE | ACTIONS + | +========================================================================= + ERROR | Clean up resources used to serve clients. + | Always remain in ERROR state. +------------------------------------------------------------------------- + INITIAL | Connect to the pipe asynchronously. + | If connection is successfully queued up asynchronously, + | go into CONNECTING state. + | If connection is done synchronously, go into CONNECTED + | state. + | For any unexpected problems, go into ERROR state. +------------------------------------------------------------------------- + CONNECTING | Get the result of async connection request. + | If I/O is still incomplete, remain in the CONNECTING + | state. + | If connection is complete, go into CONNECTED state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + CONNECTED | Read from the pipe asynchronously. + | If read request is successfully queued up asynchronously, + | go into READING state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + READING | Get the result of async read request. + | If read is done, go into READ_DONE state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + READ_DONE | Register the client, prepare the reply and write the + | reply to the pipe asynchronously. + | If write request is successfully queued up asynchronously, + | go into WRITING state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + WRITING | Get the result of the async write request. + | If write is done, go into WRITE_DONE state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + WRITE_DONE | Read from the pipe asynchronously (for an ACK). + | If read request is successfully queued up asynchonously, + | go into READING_ACK state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + READING_ACK | Get the result of the async read request. + | If read is done, perform action for successful client + | connection. + | Go into DISCONNECTING state. +------------------------------------------------------------------------- + DISCONNECTING | Disconnect from the pipe, reset the event and go into + | INITIAL state and signal the event again. If anything + | fails, go into ERROR state. +========================================================================= diff --git a/breakpad/client/windows/crash_generation/client_info.cc b/breakpad/client/windows/crash_generation/client_info.cc new file mode 100644 index 0000000000..3a1a96262d --- /dev/null +++ b/breakpad/client/windows/crash_generation/client_info.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "client/windows/crash_generation/client_info.h" +#include "client/windows/common/ipc_protocol.h" + +static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime"; +static const size_t kMaxCustomInfoEntries = 4096; +static const size_t kMaxAppMemoryEntries = 4096; + +namespace google_breakpad { + +ClientInfo::ClientInfo(CrashGenerationServer* crash_server, + DWORD pid, + MINIDUMP_TYPE dump_type, + DWORD* thread_id, + EXCEPTION_POINTERS** ex_info, + AppMemoryInfo* app_mem_info, + MDRawAssertionInfo* assert_info, + const CustomClientInfo& custom_client_info) + : crash_server_(crash_server), + pid_(pid), + dump_type_(dump_type), + ex_info_(ex_info), + app_memory_info_ptr_(app_mem_info), + assert_info_(assert_info), + custom_client_info_(custom_client_info), + thread_id_(thread_id), + process_handle_(NULL), + dump_requested_handle_(NULL), + dump_generated_handle_(NULL), + dump_request_wait_handle_(NULL), + process_exit_wait_handle_(NULL), + crash_id_(NULL) { + GetSystemTimeAsFileTime(&start_time_); +} + +bool ClientInfo::Initialize() { + process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_); + if (!process_handle_) { + return false; + } + + // The crash_id will be the low order word of the process creation time. + FILETIME creation_time, exit_time, kernel_time, user_time; + if (GetProcessTimes(process_handle_, &creation_time, &exit_time, + &kernel_time, &user_time)) + crash_id_ = creation_time.dwLowDateTime; + + dump_requested_handle_ = CreateEvent(NULL, // Security attributes. + TRUE, // Manual reset. + FALSE, // Initial state. + NULL); // Name. + if (!dump_requested_handle_) { + return false; + } + + dump_generated_handle_ = CreateEvent(NULL, // Security attributes. + TRUE, // Manual reset. + FALSE, // Initial state. + NULL); // Name. + return dump_generated_handle_ != NULL; +} + +void ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() { + if (dump_request_wait_handle_) { + // Wait for callbacks that might already be running to finish. + UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE); + dump_request_wait_handle_ = NULL; + } +} + +void ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) { + if (process_exit_wait_handle_) { + if (block_until_no_pending) { + // Wait for the callback that might already be running to finish. + UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE); + } else { + UnregisterWait(process_exit_wait_handle_); + } + process_exit_wait_handle_ = NULL; + } +} + +ClientInfo::~ClientInfo() { + // Waiting for the callback to finish here is safe because ClientInfo's are + // never destroyed from the dump request handling callback. + UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + // This is a little tricky because ClientInfo's may be destroyed by the same + // callback (OnClientEnd) and waiting for it to finish will cause a deadlock. + // Regardless of this complication, wait for any running callbacks to finish + // so that the common case is properly handled. In order to avoid deadlocks, + // the OnClientEnd callback must call UnregisterProcessExitWait(false) + // before deleting the ClientInfo. + UnregisterProcessExitWait(true); + + if (process_handle_) { + CloseHandle(process_handle_); + } + + if (dump_requested_handle_) { + CloseHandle(dump_requested_handle_); + } + + if (dump_generated_handle_) { + CloseHandle(dump_generated_handle_); + } +} + +bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const { + SIZE_T bytes_count = 0; + if (!ReadProcessMemory(process_handle_, + ex_info_, + ex_info, + sizeof(*ex_info), + &bytes_count)) { + return false; + } + + return bytes_count == sizeof(*ex_info); +} + +bool ClientInfo::GetClientThreadId(DWORD* thread_id) const { + SIZE_T bytes_count = 0; + if (!ReadProcessMemory(process_handle_, + thread_id_, + thread_id, + sizeof(*thread_id), + &bytes_count)) { + return false; + } + + return bytes_count == sizeof(*thread_id); +} + +void ClientInfo::SetProcessUptime() { + FILETIME now = {0}; + GetSystemTimeAsFileTime(&now); + + ULARGE_INTEGER time_start; + time_start.HighPart = start_time_.dwHighDateTime; + time_start.LowPart = start_time_.dwLowDateTime; + + ULARGE_INTEGER time_now; + time_now.HighPart = now.dwHighDateTime; + time_now.LowPart = now.dwLowDateTime; + + // Calculate the delay and convert it from 100-nanoseconds to milliseconds. + __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000; + + // Convert it to a string. + wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value; + _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10); +} + +bool ClientInfo::PopulateAppMemory() { + AppMemoryInfo info; + + SIZE_T read_count = sizeof(AppMemoryInfo); + SIZE_T bytes_count = 0; + + if (!ReadProcessMemory(process_handle_, + app_memory_info_ptr_, + (void *)&info, + read_count, + &bytes_count)) { + return false; + } + + if (info.count > kMaxAppMemoryEntries) + return false; + + app_memory_entries_.reset( + new AppMemory[info.count]); + + app_memory_count_ = info.count; + + read_count = sizeof(AppMemory) * info.count; + + if (!ReadProcessMemory(process_handle_, + info.entries, + app_memory_entries_.get(), + read_count, + &bytes_count)) { + return false; + } + + return (bytes_count == read_count); +} + +bool ClientInfo::PopulateCustomInfo() { + if (custom_client_info_.count > kMaxCustomInfoEntries) + return false; + + SIZE_T bytes_count = 0; + SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count; + + // If the scoped array for custom info already has an array, it will be + // the same size as what we need. This is because the number of custom info + // entries is always the same. So allocate memory only if scoped array has + // a NULL pointer. + if (!custom_info_entries_.get()) { + // Allocate an extra entry for reporting uptime for the client process. + custom_info_entries_.reset( + new CustomInfoEntry[custom_client_info_.count + 1]); + // Use the last element in the array for uptime. + custom_info_entries_.get()[custom_client_info_.count].set_name( + kCustomInfoProcessUptimeName); + } + + if (!ReadProcessMemory(process_handle_, + custom_client_info_.entries, + custom_info_entries_.get(), + read_count, + &bytes_count)) { + return false; + } + + SetProcessUptime(); + return (bytes_count == read_count); +} + +AppMemoryInfo ClientInfo::GetAppMemory() const { + AppMemoryInfo app_memory_info; + app_memory_info.entries = app_memory_entries_.get(); + app_memory_info.count = app_memory_count_; + return app_memory_info; +} + +CustomClientInfo ClientInfo::GetCustomInfo() const { + CustomClientInfo custom_info; + custom_info.entries = custom_info_entries_.get(); + // Add 1 to the count from the client process to account for extra entry for + // process uptime. + custom_info.count = custom_client_info_.count + 1; + return custom_info; +} + +} // namespace google_breakpad diff --git a/breakpad/client/windows/crash_generation/client_info.h b/breakpad/client/windows/crash_generation/client_info.h new file mode 100644 index 0000000000..d807e9adf2 --- /dev/null +++ b/breakpad/client/windows/crash_generation/client_info.h @@ -0,0 +1,198 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ +#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ + +#include +#include +#include "client/windows/common/ipc_protocol.h" +#include "common/scoped_ptr.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class CrashGenerationServer; + +// Abstraction for a crash client process. +class ClientInfo { + public: + // Creates an instance with the given values. Gets the process + // handle for the given process id and creates necessary event + // objects. + ClientInfo(CrashGenerationServer* crash_server, + DWORD pid, + MINIDUMP_TYPE dump_type, + DWORD* thread_id, + EXCEPTION_POINTERS** ex_info, + AppMemoryInfo* app_mem_info, + MDRawAssertionInfo* assert_info, + const CustomClientInfo& custom_client_info); + + ~ClientInfo(); + + CrashGenerationServer* crash_server() const { return crash_server_; } + DWORD pid() const { return pid_; } + MINIDUMP_TYPE dump_type() const { return dump_type_; } + EXCEPTION_POINTERS** ex_info() const { return ex_info_; } + MDRawAssertionInfo* assert_info() const { return assert_info_; } + DWORD* thread_id() const { return thread_id_; } + HANDLE process_handle() const { return process_handle_; } + HANDLE dump_requested_handle() const { return dump_requested_handle_; } + HANDLE dump_generated_handle() const { return dump_generated_handle_; } + DWORD crash_id() const { return crash_id_; } + const CustomClientInfo& custom_client_info() const { + return custom_client_info_; + } + + void set_dump_request_wait_handle(HANDLE value) { + dump_request_wait_handle_ = value; + } + + void set_process_exit_wait_handle(HANDLE value) { + process_exit_wait_handle_ = value; + } + + // Unregister the dump request wait operation and wait for all callbacks + // that might already be running to complete before returning. + void UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + // Unregister the process exit wait operation. If block_until_no_pending is + // true, wait for all callbacks that might already be running to complete + // before returning. + void UnregisterProcessExitWait(bool block_until_no_pending); + + bool Initialize(); + bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const; + bool GetClientThreadId(DWORD* thread_id) const; + + // Reads the custom memory regions from the client process address space. + bool PopulateAppMemory(); + + // Reads the custom information from the client process address space. + bool PopulateCustomInfo(); + + // Returns the app memory information. + AppMemoryInfo GetAppMemory() const; + + // Returns the client custom information. + CustomClientInfo GetCustomInfo() const; + + private: + // Calcualtes the uptime for the client process, converts it to a string and + // stores it in the last entry of client custom info. + void SetProcessUptime(); + + // Crash generation server. + CrashGenerationServer* crash_server_; + + // Client process ID. + DWORD pid_; + + // Dump type requested by the client. + MINIDUMP_TYPE dump_type_; + + // Address of an EXCEPTION_POINTERS* variable in the client + // process address space that will point to an instance of + // EXCEPTION_POINTERS containing information about crash. + // + // WARNING: Do not dereference these pointers as they are pointers + // in the address space of another process. + EXCEPTION_POINTERS** ex_info_; + + // Address of an instance of MDRawAssertionInfo in the client + // process address space that will contain information about + // non-exception related crashes like invalid parameter assertion + // failures and pure calls. + // + // WARNING: Do not dereference these pointers as they are pointers + // in the address space of another process. + MDRawAssertionInfo* assert_info_; + + // Address of an instance of AppMemoryInfo in the client + // process address space that will contain information about + // user-specified memory regions to save. + // + // WARNING: Do not dereference these pointers as they are pointers + // in the address space of another process. + AppMemoryInfo* app_memory_info_ptr_; + + // Contains the memory region entries read from the client process + // memory. This will be populated only if the method GetClientAppMemory + // is called. + scoped_array app_memory_entries_; + ULONG app_memory_count_; + + // Custom information about the client. + CustomClientInfo custom_client_info_; + + // Contains the custom client info entries read from the client process + // memory. This will be populated only if the method GetClientCustomInfo + // is called. + scoped_array custom_info_entries_; + + // Address of a variable in the client process address space that + // will contain the thread id of the crashing client thread. + // + // WARNING: Do not dereference these pointers as they are pointers + // in the address space of another process. + DWORD* thread_id_; + + // Client process handle. + HANDLE process_handle_; + + // Dump request event handle. + HANDLE dump_requested_handle_; + + // Dump generated event handle. + HANDLE dump_generated_handle_; + + // Wait handle for dump request event. + HANDLE dump_request_wait_handle_; + + // Wait handle for process exit event. + HANDLE process_exit_wait_handle_; + + // Time when the client process started. It is used to determine the uptime + // for the client process when it signals a crash. + FILETIME start_time_; + + // The crash id which can be used to request an upload. This will be the + // value of the low order dword of the process creation time for the process + // being dumped. + DWORD crash_id_; + + // Disallow copy ctor and operator=. + ClientInfo(const ClientInfo& client_info); + ClientInfo& operator=(const ClientInfo& client_info); +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ diff --git a/breakpad/client/windows/crash_generation/crash_generation.sln b/breakpad/client/windows/crash_generation/crash_generation.sln new file mode 100644 index 0000000000..6e247be9f0 --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation.sln @@ -0,0 +1,65 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "(crash_generation)", "..\..\..\..\crash_generation", "{71054F76-E083-ED71-B3F9-3E9B872F3E9E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "..\common.vcxproj", "{EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_client", "crash_generation_client.vcxproj", "{EC847717-119A-2391-0477-212E1140082C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_server", "crash_generation_server.vcxproj", "{7893E300-3ED0-7F4C-158F-67EA63934C57}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|x64 = Release|x64 + Purify|Win32 = Purify|Win32 + Purify|x64 = Purify|x64 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|Win32.ActiveCfg = Debug|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|Win32.Build.0 = Debug|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|x64.ActiveCfg = Release|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|x64.Build.0 = Release|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|Win32.ActiveCfg = Purify|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|Win32.Build.0 = Purify|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|x64.ActiveCfg = Purify|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|x64.Build.0 = Purify|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|x64.ActiveCfg = Debug|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|x64.Build.0 = Debug|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|Win32.ActiveCfg = Release|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|Win32.Build.0 = Release|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|Win32.Build.0 = Debug|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|x64.ActiveCfg = Release|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|x64.Build.0 = Release|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|Win32.ActiveCfg = Purify|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|Win32.Build.0 = Purify|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|x64.ActiveCfg = Purify|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|x64.Build.0 = Purify|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|x64.ActiveCfg = Debug|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|x64.Build.0 = Debug|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|Win32.ActiveCfg = Release|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|Win32.Build.0 = Release|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Debug|Win32.Build.0 = Debug|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Release|x64.ActiveCfg = Release|x64 + {EC847717-119A-2391-0477-212E1140082C}.Release|x64.Build.0 = Release|x64 + {EC847717-119A-2391-0477-212E1140082C}.Purify|Win32.ActiveCfg = Purify|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Purify|Win32.Build.0 = Purify|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Purify|x64.ActiveCfg = Purify|x64 + {EC847717-119A-2391-0477-212E1140082C}.Purify|x64.Build.0 = Purify|x64 + {EC847717-119A-2391-0477-212E1140082C}.Debug|x64.ActiveCfg = Debug|x64 + {EC847717-119A-2391-0477-212E1140082C}.Debug|x64.Build.0 = Debug|x64 + {EC847717-119A-2391-0477-212E1140082C}.Release|Win32.ActiveCfg = Release|Win32 + {EC847717-119A-2391-0477-212E1140082C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {7893E300-3ED0-7F4C-158F-67EA63934C57} = {71054F76-E083-ED71-B3F9-3E9B872F3E9E} + {EC847717-119A-2391-0477-212E1140082C} = {71054F76-E083-ED71-B3F9-3E9B872F3E9E} + EndGlobalSection +EndGlobal diff --git a/breakpad/client/windows/crash_generation/crash_generation_client.cc b/breakpad/client/windows/crash_generation/crash_generation_client.cc new file mode 100644 index 0000000000..f88216abac --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_client.cc @@ -0,0 +1,413 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "client/windows/crash_generation/crash_generation_client.h" +#include +#include +#include "client/windows/common/ipc_protocol.h" + +namespace google_breakpad { + +const int kPipeBusyWaitTimeoutMs = 2000; + +#ifdef _DEBUG +const DWORD kWaitForServerTimeoutMs = INFINITE; +#else +const DWORD kWaitForServerTimeoutMs = 15000; +#endif + +const int kPipeConnectMaxAttempts = 2; + +const DWORD kPipeDesiredAccess = FILE_READ_DATA | + FILE_WRITE_DATA | + FILE_WRITE_ATTRIBUTES; + +const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION | + SECURITY_SQOS_PRESENT; + +const DWORD kPipeMode = PIPE_READMODE_MESSAGE; + +const size_t kWaitEventCount = 2; + +// This function is orphan for production code. It can be used +// for debugging to help repro some scenarios like the client +// is slow in writing to the pipe after connecting, the client +// is slow in reading from the pipe after writing, etc. The parameter +// overlapped below is not used and it is present to match the signature +// of this function to TransactNamedPipe Win32 API. Uncomment if needed +// for debugging. +/** +static bool TransactNamedPipeDebugHelper(HANDLE pipe, + const void* in_buffer, + DWORD in_size, + void* out_buffer, + DWORD out_size, + DWORD* bytes_count, + LPOVERLAPPED) { + // Uncomment the next sleep to create a gap before writing + // to pipe. + // Sleep(5000); + + if (!WriteFile(pipe, + in_buffer, + in_size, + bytes_count, + NULL)) { + return false; + } + + // Uncomment the next sleep to create a gap between write + // and read. + // Sleep(5000); + + return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE; +} +**/ + +CrashGenerationClient::CrashGenerationClient( + const wchar_t* pipe_name, + MINIDUMP_TYPE dump_type, + const CustomClientInfo* custom_info) + : pipe_name_(pipe_name), + pipe_handle_(NULL), + dump_type_(dump_type), + thread_id_(0), + server_process_id_(0), + crash_event_(NULL), + crash_generated_(NULL), + server_alive_(NULL), + exception_pointers_(NULL), + app_memory_info_(), + custom_info_() { + memset(&assert_info_, 0, sizeof(assert_info_)); + if (custom_info) { + custom_info_ = *custom_info; + } +} + +CrashGenerationClient::CrashGenerationClient( + HANDLE pipe_handle, + MINIDUMP_TYPE dump_type, + const CustomClientInfo* custom_info) + : pipe_name_(), + pipe_handle_(pipe_handle), + dump_type_(dump_type), + thread_id_(0), + server_process_id_(0), + crash_event_(NULL), + crash_generated_(NULL), + server_alive_(NULL), + exception_pointers_(NULL), + app_memory_info_(), + custom_info_() { + memset(&assert_info_, 0, sizeof(assert_info_)); + if (custom_info) { + custom_info_ = *custom_info; + } +} + +CrashGenerationClient::~CrashGenerationClient() { + if (crash_event_) { + CloseHandle(crash_event_); + } + + if (crash_generated_) { + CloseHandle(crash_generated_); + } + + if (server_alive_) { + CloseHandle(server_alive_); + } +} + +// Performs the registration step with the server process. +// The registration step involves communicating with the server +// via a named pipe. The client sends the following pieces of +// data to the server: +// +// * Message tag indicating the client is requesting registration. +// * Process id of the client process. +// * Address of a DWORD variable in the client address space +// that will contain the thread id of the client thread that +// caused the crash. +// * Address of a EXCEPTION_POINTERS* variable in the client +// address space that will point to an instance of EXCEPTION_POINTERS +// when the crash happens. +// * Address of an instance of MDRawAssertionInfo that will contain +// relevant information in case of non-exception crashes like assertion +// failures and pure calls. +// +// In return the client expects the following information from the server: +// +// * Message tag indicating successful registration. +// * Server process id. +// * Handle to an object that client can signal to request dump +// generation from the server. +// * Handle to an object that client can wait on after requesting +// dump generation for the server to finish dump generation. +// * Handle to a mutex object that client can wait on to make sure +// server is still alive. +// +// If any step of the expected behavior mentioned above fails, the +// registration step is not considered successful and hence out-of-process +// dump generation service is not available. +// +// Returns true if the registration is successful; false otherwise. +bool CrashGenerationClient::Register() { + if (IsRegistered()) { + return true; + } + + HANDLE pipe = ConnectToServer(); + if (!pipe) { + return false; + } + + bool success = RegisterClient(pipe); + CloseHandle(pipe); + return success; +} + +void CrashGenerationClient::SetAppMemory(AppMemory *mem, ULONG count) { + app_memory_info_.entries = mem; + app_memory_info_.count = count; +} + +bool CrashGenerationClient::RequestUpload(DWORD crash_id) { + HANDLE pipe = ConnectToServer(); + if (!pipe) { + return false; + } + + CustomClientInfo custom_info = {NULL, 0}; + ProtocolMessage msg(MESSAGE_TAG_UPLOAD_REQUEST, crash_id, + static_cast(NULL), NULL, NULL, NULL, + custom_info, NULL, NULL, NULL, NULL); + DWORD bytes_count = 0; + bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, NULL) != 0; + + CloseHandle(pipe); + return success; +} + +HANDLE CrashGenerationClient::ConnectToServer() { + HANDLE pipe = ConnectToPipe(pipe_name_.c_str(), + kPipeDesiredAccess, + kPipeFlagsAndAttributes); + if (!pipe) { + return NULL; + } + + DWORD mode = kPipeMode; + if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) { + CloseHandle(pipe); + pipe = NULL; + } + + return pipe; +} + +bool CrashGenerationClient::RegisterClient(HANDLE pipe) { + ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST, + GetCurrentProcessId(), + dump_type_, + &thread_id_, + &exception_pointers_, + &assert_info_, + custom_info_, + &app_memory_info_, + NULL, + NULL, + NULL); + ProtocolMessage reply; + DWORD bytes_count = 0; + // The call to TransactNamedPipe below can be changed to a call + // to TransactNamedPipeDebugHelper to help repro some scenarios. + // For details see comments for TransactNamedPipeDebugHelper. + if (!TransactNamedPipe(pipe, + &msg, + sizeof(msg), + &reply, + sizeof(ProtocolMessage), + &bytes_count, + NULL)) { + return false; + } + + if (!ValidateResponse(reply)) { + return false; + } + + ProtocolMessage ack_msg; + ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK; + + if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) { + return false; + } + crash_event_ = reply.dump_request_handle; + crash_generated_ = reply.dump_generated_handle; + server_alive_ = reply.server_alive_handle; + server_process_id_ = reply.id; + + return true; +} + +HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name, + DWORD pipe_access, + DWORD flags_attrs) { + if (pipe_handle_) { + HANDLE t = pipe_handle_; + pipe_handle_ = NULL; + return t; + } + + for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { + HANDLE pipe = CreateFile(pipe_name, + pipe_access, + 0, + NULL, + OPEN_EXISTING, + flags_attrs, + NULL); + if (pipe != INVALID_HANDLE_VALUE) { + return pipe; + } + + // Cannot continue retrying if error is something other than + // ERROR_PIPE_BUSY. + if (GetLastError() != ERROR_PIPE_BUSY) { + break; + } + + // Cannot continue retrying if wait on pipe fails. + if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) { + break; + } + } + + return NULL; +} + +bool CrashGenerationClient::ValidateResponse( + const ProtocolMessage& msg) const { + return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) && + (msg.id != 0) && + (msg.dump_request_handle != NULL) && + (msg.dump_generated_handle != NULL) && + (msg.server_alive_handle != NULL); +} + +bool CrashGenerationClient::IsRegistered() const { + return crash_event_ != NULL; +} + +bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info, + MDRawAssertionInfo* assert_info) { + if (!IsRegistered()) { + return false; + } + + exception_pointers_ = ex_info; + thread_id_ = GetCurrentThreadId(); + + if (assert_info) { + memcpy(&assert_info_, assert_info, sizeof(assert_info_)); + } else { + memset(&assert_info_, 0, sizeof(assert_info_)); + } + + return SignalCrashEventAndWait(); +} + +bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) { + return RequestDump(ex_info, NULL); +} + +bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) { + return RequestDump(NULL, assert_info); +} + +bool CrashGenerationClient::SignalCrashEventAndWait() { + assert(crash_event_); + assert(crash_generated_); + assert(server_alive_); + + // Reset the dump generated event before signaling the crash + // event so that the server can set the dump generated event + // once it is done generating the event. + if (!ResetEvent(crash_generated_)) { + return false; + } + + if (!SetEvent(crash_event_)) { + return false; + } + + HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_}; + + DWORD result = WaitForMultipleObjects(kWaitEventCount, + wait_handles, + FALSE, + kWaitForServerTimeoutMs); + + // Crash dump was successfully generated only if the server + // signaled the crash generated event. + return result == WAIT_OBJECT_0; +} + +HANDLE CrashGenerationClient::DuplicatePipeToClientProcess(const wchar_t* pipe_name, + HANDLE hProcess) { + for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { + HANDLE local_pipe = CreateFile(pipe_name, kPipeDesiredAccess, + 0, NULL, OPEN_EXISTING, + kPipeFlagsAndAttributes, NULL); + if (local_pipe != INVALID_HANDLE_VALUE) { + HANDLE remotePipe = INVALID_HANDLE_VALUE; + if (DuplicateHandle(GetCurrentProcess(), local_pipe, + hProcess, &remotePipe, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + return remotePipe; + } else { + return INVALID_HANDLE_VALUE; + } + } + + // Cannot continue retrying if the error wasn't a busy pipe. + if (GetLastError() != ERROR_PIPE_BUSY) { + return INVALID_HANDLE_VALUE; + } + + if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) { + return INVALID_HANDLE_VALUE; + } + } + return INVALID_HANDLE_VALUE; +} + +} // namespace google_breakpad diff --git a/breakpad/client/windows/crash_generation/crash_generation_client.h b/breakpad/client/windows/crash_generation/crash_generation_client.h new file mode 100644 index 0000000000..ce9ec0919a --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_client.h @@ -0,0 +1,190 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ +#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ + +#include +#include +#include +#include +#include +#include "client/windows/common/ipc_protocol.h" +#include "common/scoped_ptr.h" + +namespace google_breakpad { + +struct CustomClientInfo; +struct AppMemory; + +typedef std::vector AppMemoryList; + +// Abstraction of client-side implementation of out of process +// crash generation. +// +// The process that desires to have out-of-process crash dump +// generation service can use this class in the following way: +// +// * Create an instance. +// * Call Register method so that the client tries to register +// with the server process and check the return value. If +// registration is not successful, out-of-process crash dump +// generation will not be available +// * Request dump generation by calling either of the two +// overloaded RequestDump methods - one in case of exceptions +// and the other in case of assertion failures +// +// Note that it is the responsibility of the client code of +// this class to set the unhandled exception filter with the +// system by calling the SetUnhandledExceptionFilter function +// and the client code should explicitly request dump generation. +class CrashGenerationClient { + public: + CrashGenerationClient(const wchar_t* pipe_name, + MINIDUMP_TYPE dump_type, + const CustomClientInfo* custom_info); + + CrashGenerationClient(HANDLE pipe_handle, + MINIDUMP_TYPE dump_type, + const CustomClientInfo* custom_info); + + ~CrashGenerationClient(); + + // Registers the client process with the crash server. + // + // Returns true if the registration is successful; false otherwise. + bool Register(); + + void SetAppMemory(AppMemory *mem, ULONG count); + + // Requests the crash server to upload a previous dump with the + // given crash id. + bool RequestUpload(DWORD crash_id); + + bool RequestDump(EXCEPTION_POINTERS* ex_info, + MDRawAssertionInfo* assert_info); + + // Requests the crash server to generate a dump with the given + // exception information. + // + // Returns true if the dump was successful; false otherwise. Note that + // if the registration step was not performed or it was not successful, + // false will be returned. + bool RequestDump(EXCEPTION_POINTERS* ex_info); + + // Requests the crash server to generate a dump with the given + // assertion information. + // + // Returns true if the dump was successful; false otherwise. Note that + // if the registration step was not performed or it was not successful, + // false will be returned. + bool RequestDump(MDRawAssertionInfo* assert_info); + + // If the crash generation client is running in a sandbox that prevents it + // from opening the named pipe directly, the server process may open the + // handle and duplicate it into the client process with this helper method. + // Returns INVALID_HANDLE_VALUE on failure. The process must have been opened + // with the PROCESS_DUP_HANDLE access right. + static HANDLE DuplicatePipeToClientProcess(const wchar_t* pipe_name, + HANDLE hProcess); + + private: + // Connects to the appropriate pipe and sets the pipe handle state. + // + // Returns the pipe handle if everything goes well; otherwise Returns NULL. + HANDLE ConnectToServer(); + + // Performs a handshake with the server over the given pipe which should be + // already connected to the server. + // + // Returns true if handshake with the server was successful; false otherwise. + bool RegisterClient(HANDLE pipe); + + // Validates the given server response. + bool ValidateResponse(const ProtocolMessage& msg) const; + + // Returns true if the registration step succeeded; false otherwise. + bool IsRegistered() const; + + // Connects to the given named pipe with given parameters. + // + // Returns true if the connection is successful; false otherwise. + HANDLE ConnectToPipe(const wchar_t* pipe_name, + DWORD pipe_access, + DWORD flags_attrs); + + // Signals the crash event and wait for the server to generate crash. + bool SignalCrashEventAndWait(); + + // Pipe name to use to talk to server. + std::wstring pipe_name_; + + // Pipe handle duplicated from server process. Only valid before + // Register is called. + HANDLE pipe_handle_; + + AppMemoryInfo app_memory_info_; + + // Custom client information + CustomClientInfo custom_info_; + + // Type of dump to generate. + MINIDUMP_TYPE dump_type_; + + // Event to signal in case of a crash. + HANDLE crash_event_; + + // Handle to wait on after signaling a crash for the server + // to finish generating crash dump. + HANDLE crash_generated_; + + // Handle to a mutex that will become signaled with WAIT_ABANDONED + // if the server process goes down. + HANDLE server_alive_; + + // Server process id. + DWORD server_process_id_; + + // Id of the thread that caused the crash. + DWORD thread_id_; + + // Exception pointers for an exception crash. + EXCEPTION_POINTERS* exception_pointers_; + + // Assertion info for an invalid parameter or pure call crash. + MDRawAssertionInfo assert_info_; + + // Disable copy ctor and operator=. + CrashGenerationClient(const CrashGenerationClient& crash_client); + CrashGenerationClient& operator=(const CrashGenerationClient& crash_client); +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ diff --git a/breakpad/client/windows/crash_generation/crash_generation_client.vcxproj b/breakpad/client/windows/crash_generation/crash_generation_client.vcxproj new file mode 100644 index 0000000000..250c854e0d --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_client.vcxproj @@ -0,0 +1,381 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Purify + Win32 + + + Purify + x64 + + + Release + Win32 + + + Release + x64 + + + + {EC847717-119A-2391-0477-212E1140082C} + Win32Proj + crash_generation_client + + + + Unicode + StaticLibrary + + + + + + + + + $(ExecutablePath);$(MSBuildProjectDirectory)\..\..\..\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\..\..\third_party\python_26\ + $(SolutionDir)$(Configuration)\$(Platform)\ + $(OutDir)obj\$(ProjectName)\ + false + false + false + false + true + true + $(ProjectName) + $(OutDir)\$(ProjectName).lib + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + false + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + false + false + true + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + true + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + true + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib32\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib32\ + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib64\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib64\ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/breakpad/client/windows/crash_generation/crash_generation_client.vcxproj.filters b/breakpad/client/windows/crash_generation/crash_generation_client.vcxproj.filters new file mode 100644 index 0000000000..89584cb2b5 --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_client.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/breakpad/client/windows/crash_generation/crash_generation_server.cc b/breakpad/client/windows/crash_generation/crash_generation_server.cc new file mode 100644 index 0000000000..0161588832 --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_server.cc @@ -0,0 +1,948 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "client/windows/crash_generation/crash_generation_server.h" +#include +#include +#include +#include "client/windows/common/auto_critical_section.h" +#include "common/scoped_ptr.h" + +#include "client/windows/crash_generation/client_info.h" + +namespace google_breakpad { + +// Output buffer size. +static const size_t kOutBufferSize = 64; + +// Input buffer size. +static const size_t kInBufferSize = 64; + +// Access flags for the client on the dump request event. +static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE; + +// Access flags for the client on the dump generated event. +static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE | + SYNCHRONIZE; + +// Access flags for the client on the mutex. +static const DWORD kMutexAccess = SYNCHRONIZE; + +// Attribute flags for the pipe. +static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE | + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED; + +// Mode for the pipe. +static const DWORD kPipeMode = PIPE_TYPE_MESSAGE | + PIPE_READMODE_MESSAGE | + PIPE_WAIT; + +// For pipe I/O, execute the callback in the wait thread itself, +// since the callback does very little work. The callback executes +// the code for one of the states of the server state machine and +// the code for all of the states perform async I/O and hence +// finish very quickly. +static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD; + +// Dump request threads will, most likely, generate dumps. That may +// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag. +static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD | + WT_EXECUTELONGFUNCTION; + +static bool IsClientRequestValid(const ProtocolMessage& msg) { + return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST || + (msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST && + msg.id != 0 && + msg.thread_id != NULL && + msg.exception_pointers != NULL && + msg.assert_info != NULL); +} + +CrashGenerationServer::CrashGenerationServer( + const std::wstring& pipe_name, + SECURITY_ATTRIBUTES* pipe_sec_attrs, + OnClientConnectedCallback connect_callback, + void* connect_context, + OnClientDumpRequestCallback dump_callback, + void* dump_context, + OnClientExitedCallback exit_callback, + void* exit_context, + OnClientUploadRequestCallback upload_request_callback, + void* upload_context, + bool generate_dumps, + const std::wstring* dump_path) + : pipe_name_(pipe_name), + pipe_sec_attrs_(pipe_sec_attrs), + pipe_(NULL), + pipe_wait_handle_(NULL), + server_alive_handle_(NULL), + connect_callback_(connect_callback), + connect_context_(connect_context), + dump_callback_(dump_callback), + dump_context_(dump_context), + exit_callback_(exit_callback), + exit_context_(exit_context), + upload_request_callback_(upload_request_callback), + upload_context_(upload_context), + generate_dumps_(generate_dumps), + dump_generator_(NULL), + server_state_(IPC_SERVER_STATE_UNINITIALIZED), + shutting_down_(false), + overlapped_(), + client_info_(NULL), + pre_fetch_custom_info_(true) { + InitializeCriticalSection(&sync_); + + if (dump_path) { + dump_generator_.reset(new MinidumpGenerator(*dump_path)); + } +} + +// This should never be called from the OnPipeConnected callback. +// Otherwise the UnregisterWaitEx call below will cause a deadlock. +CrashGenerationServer::~CrashGenerationServer() { + // New scope to release the lock automatically. + { + // Make sure no clients are added or removed beyond this point. + // Before adding or removing any clients, the critical section + // must be entered and the shutting_down_ flag checked. The + // critical section is then exited only after the clients_ list + // modifications are done and the list is in a consistent state. + AutoCriticalSection lock(&sync_); + + // Indicate to existing threads that server is shutting down. + shutting_down_ = true; + } + // No one will modify the clients_ list beyond this point - + // not even from another thread. + + // Even if there are no current worker threads running, it is possible that + // an I/O request is pending on the pipe right now but not yet done. + // In fact, it's very likely this is the case unless we are in an ERROR + // state. If we don't wait for the pending I/O to be done, then when the I/O + // completes, it may write to invalid memory. AppVerifier will flag this + // problem too. So we disconnect from the pipe and then wait for the server + // to get into error state so that the pending I/O will fail and get + // cleared. + DisconnectNamedPipe(pipe_); + int num_tries = 100; + while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) { + Sleep(10); + } + + // Unregister wait on the pipe. + if (pipe_wait_handle_) { + // Wait for already executing callbacks to finish. + UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE); + } + + // Close the pipe to avoid further client connections. + if (pipe_) { + CloseHandle(pipe_); + } + + // Request all ClientInfo objects to unregister all waits. + // No need to enter the critical section because no one is allowed to modify + // the clients_ list once the shutting_down_ flag is set. + std::list::iterator iter; + for (iter = clients_.begin(); iter != clients_.end(); ++iter) { + ClientInfo* client_info = *iter; + // Unregister waits. Wait for already executing callbacks to finish. + // Unregister the client process exit wait first and only then unregister + // the dump request wait. The reason is that the OnClientExit callback + // also unregisters the dump request wait and such a race (doing the same + // unregistration from two threads) is undesirable. + client_info->UnregisterProcessExitWait(true); + client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + // Destroying the ClientInfo here is safe because all wait operations for + // this ClientInfo were unregistered and no pending or running callbacks + // for this ClientInfo can possible exist (block_until_no_pending option + // was used). + delete client_info; + } + + if (server_alive_handle_) { + // Release the mutex before closing the handle so that clients requesting + // dumps wait for a long time for the server to generate a dump. + ReleaseMutex(server_alive_handle_); + CloseHandle(server_alive_handle_); + } + + if (overlapped_.hEvent) { + CloseHandle(overlapped_.hEvent); + } + + DeleteCriticalSection(&sync_); +} + +bool CrashGenerationServer::Start() { + if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) { + return false; + } + + server_state_ = IPC_SERVER_STATE_INITIAL; + + server_alive_handle_ = CreateMutex(NULL, TRUE, NULL); + if (!server_alive_handle_) { + return false; + } + + // Event to signal the client connection and pipe reads and writes. + overlapped_.hEvent = CreateEvent(NULL, // Security descriptor. + TRUE, // Manual reset. + FALSE, // Initially nonsignaled. + NULL); // Name. + if (!overlapped_.hEvent) { + return false; + } + + // Register a callback with the thread pool for the client connection. + if (!RegisterWaitForSingleObject(&pipe_wait_handle_, + overlapped_.hEvent, + OnPipeConnected, + this, + INFINITE, + kPipeIOThreadFlags)) { + return false; + } + + pipe_ = CreateNamedPipe(pipe_name_.c_str(), + kPipeAttr, + kPipeMode, + 1, + kOutBufferSize, + kInBufferSize, + 0, + pipe_sec_attrs_); + if (pipe_ == INVALID_HANDLE_VALUE) { + return false; + } + + // Kick-start the state machine. This will initiate an asynchronous wait + // for client connections. + if (!SetEvent(overlapped_.hEvent)) { + server_state_ = IPC_SERVER_STATE_ERROR; + return false; + } + + // If we are in error state, it's because we failed to start listening. + return true; +} + +// If the server thread serving clients ever gets into the +// ERROR state, reset the event, close the pipe and remain +// in the error state forever. Error state means something +// that we didn't account for has happened, and it's dangerous +// to do anything unknowingly. +void CrashGenerationServer::HandleErrorState() { + assert(server_state_ == IPC_SERVER_STATE_ERROR); + + // If the server is shutting down anyway, don't clean up + // here since shut down process will clean up. + if (shutting_down_) { + return; + } + + if (pipe_wait_handle_) { + UnregisterWait(pipe_wait_handle_); + pipe_wait_handle_ = NULL; + } + + if (pipe_) { + CloseHandle(pipe_); + pipe_ = NULL; + } + + if (overlapped_.hEvent) { + CloseHandle(overlapped_.hEvent); + overlapped_.hEvent = NULL; + } +} + +// When the server thread serving clients is in the INITIAL state, +// try to connect to the pipe asynchronously. If the connection +// finishes synchronously, directly go into the CONNECTED state; +// otherwise go into the CONNECTING state. For any problems, go +// into the ERROR state. +void CrashGenerationServer::HandleInitialState() { + assert(server_state_ == IPC_SERVER_STATE_INITIAL); + + if (!ResetEvent(overlapped_.hEvent)) { + EnterErrorState(); + return; + } + + bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + // From MSDN, it is not clear that when ConnectNamedPipe is used + // in an overlapped mode, will it ever return non-zero value, and + // if so, in what cases. + assert(!success); + + switch (error_code) { + case ERROR_IO_PENDING: + EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING); + break; + + case ERROR_PIPE_CONNECTED: + EnterStateImmediately(IPC_SERVER_STATE_CONNECTED); + break; + + default: + EnterErrorState(); + break; + } +} + +// When the server thread serving the clients is in the CONNECTING state, +// try to get the result of the asynchronous connection request using +// the OVERLAPPED object. If the result indicates the connection is done, +// go into the CONNECTED state. If the result indicates I/O is still +// INCOMPLETE, remain in the CONNECTING state. For any problems, +// go into the DISCONNECTING state. +void CrashGenerationServer::HandleConnectingState() { + assert(server_state_ == IPC_SERVER_STATE_CONNECTING); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + if (success) { + EnterStateImmediately(IPC_SERVER_STATE_CONNECTED); + } else if (error_code != ERROR_IO_INCOMPLETE) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } else { + // remain in CONNECTING state + } +} + +// When the server thread serving the clients is in the CONNECTED state, +// try to issue an asynchronous read from the pipe. If read completes +// synchronously or if I/O is pending then go into the READING state. +// For any problems, go into the DISCONNECTING state. +void CrashGenerationServer::HandleConnectedState() { + assert(server_state_ == IPC_SERVER_STATE_CONNECTED); + + DWORD bytes_count = 0; + memset(&msg_, 0, sizeof(msg_)); + bool success = ReadFile(pipe_, + &msg_, + sizeof(msg_), + &bytes_count, + &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + // Note that the asynchronous read issued above can finish before the + // code below executes. But, it is okay to change state after issuing + // the asynchronous read. This is because even if the asynchronous read + // is done, the callback for it would not be executed until the current + // thread finishes its execution. + if (success || error_code == ERROR_IO_PENDING) { + EnterStateWhenSignaled(IPC_SERVER_STATE_READING); + } else { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } +} + +// When the server thread serving the clients is in the READING state, +// try to get the result of the async read. If async read is done, +// go into the READ_DONE state. For any problems, go into the +// DISCONNECTING state. +void CrashGenerationServer::HandleReadingState() { + assert(server_state_ == IPC_SERVER_STATE_READING); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + error_code = error_code; + + if (success && bytes_count == sizeof(ProtocolMessage)) { + EnterStateImmediately(IPC_SERVER_STATE_READ_DONE); + } else { + // We should never get an I/O incomplete since we should not execute this + // unless the Read has finished and the overlapped event is signaled. If + // we do get INCOMPLETE, we have a bug in our code. + assert(error_code != ERROR_IO_INCOMPLETE); + + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } +} + +// When the server thread serving the client is in the READ_DONE state, +// validate the client's request message, register the client by +// creating appropriate objects and prepare the response. Then try to +// write the response to the pipe asynchronously. If that succeeds, +// go into the WRITING state. For any problems, go into the DISCONNECTING +// state. +void CrashGenerationServer::HandleReadDoneState() { + assert(server_state_ == IPC_SERVER_STATE_READ_DONE); + + if (!IsClientRequestValid(msg_)) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) { + if (upload_request_callback_) + upload_request_callback_(upload_context_, msg_.id); + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + scoped_ptr client_info( + new ClientInfo(this, + msg_.id, + msg_.dump_type, + msg_.thread_id, + msg_.exception_pointers, + msg_.app_memory_info, + msg_.assert_info, + msg_.custom_client_info)); + + if (!client_info->Initialize()) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + // Issues an asynchronous WriteFile call if successful. + // Iff successful, assigns ownership of the client_info pointer to the server + // instance, in which case we must be sure not to free it in this function. + if (!RespondToClient(client_info.get())) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + // This is only valid as long as it can be found in the clients_ list + client_info_ = client_info.release(); + + // Note that the asynchronous write issued by RespondToClient function + // can finish before the code below executes. But it is okay to change + // state after issuing the asynchronous write. This is because even if + // the asynchronous write is done, the callback for it would not be + // executed until the current thread finishes its execution. + EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING); +} + +// When the server thread serving the clients is in the WRITING state, +// try to get the result of the async write. If the async write is done, +// go into the WRITE_DONE state. For any problems, go into the +// DISONNECTING state. +void CrashGenerationServer::HandleWritingState() { + assert(server_state_ == IPC_SERVER_STATE_WRITING); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + error_code = error_code; + + if (success) { + EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE); + return; + } + + // We should never get an I/O incomplete since we should not execute this + // unless the Write has finished and the overlapped event is signaled. If + // we do get INCOMPLETE, we have a bug in our code. + assert(error_code != ERROR_IO_INCOMPLETE); + + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); +} + +// When the server thread serving the clients is in the WRITE_DONE state, +// try to issue an async read on the pipe. If the read completes synchronously +// or if I/O is still pending then go into the READING_ACK state. For any +// issues, go into the DISCONNECTING state. +void CrashGenerationServer::HandleWriteDoneState() { + assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE); + + DWORD bytes_count = 0; + bool success = ReadFile(pipe_, + &msg_, + sizeof(msg_), + &bytes_count, + &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + if (success) { + EnterStateImmediately(IPC_SERVER_STATE_READING_ACK); + } else if (error_code == ERROR_IO_PENDING) { + EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK); + } else { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } +} + +// When the server thread serving the clients is in the READING_ACK state, +// try to get result of async read. Go into the DISCONNECTING state. +void CrashGenerationServer::HandleReadingAckState() { + assert(server_state_ == IPC_SERVER_STATE_READING_ACK); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + error_code = error_code; + + if (success) { + // The connection handshake with the client is now complete; perform + // the callback. + if (connect_callback_) { + // Note that there is only a single copy of the ClientInfo of the + // currently connected client. However it is being referenced from + // two different places: + // - the client_info_ member + // - the clients_ list + // The lifetime of this ClientInfo depends on the lifetime of the + // client process - basically it can go away at any time. + // However, as long as it is referenced by the clients_ list it + // is guaranteed to be valid. Enter the critical section and check + // to see whether the client_info_ can be found in the list. + // If found, execute the callback and only then leave the critical + // section. + AutoCriticalSection lock(&sync_); + + bool client_is_still_alive = false; + std::list::iterator iter; + for (iter = clients_.begin(); iter != clients_.end(); ++iter) { + if (client_info_ == *iter) { + client_is_still_alive = true; + break; + } + } + + if (client_is_still_alive) { + connect_callback_(connect_context_, client_info_); + } + } + } else { + // We should never get an I/O incomplete since we should not execute this + // unless the Read has finished and the overlapped event is signaled. If + // we do get INCOMPLETE, we have a bug in our code. + assert(error_code != ERROR_IO_INCOMPLETE); + } + + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); +} + +// When the server thread serving the client is in the DISCONNECTING state, +// disconnect from the pipe and reset the event. If anything fails, go into +// the ERROR state. If it goes well, go into the INITIAL state and set the +// event to start all over again. +void CrashGenerationServer::HandleDisconnectingState() { + assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING); + + // Done serving the client. + client_info_ = NULL; + + overlapped_.Internal = NULL; + overlapped_.InternalHigh = NULL; + overlapped_.Offset = 0; + overlapped_.OffsetHigh = 0; + overlapped_.Pointer = NULL; + + if (!ResetEvent(overlapped_.hEvent)) { + EnterErrorState(); + return; + } + + if (!DisconnectNamedPipe(pipe_)) { + EnterErrorState(); + return; + } + + // If the server is shutting down do not connect to the + // next client. + if (shutting_down_) { + return; + } + + EnterStateImmediately(IPC_SERVER_STATE_INITIAL); +} + +void CrashGenerationServer::EnterErrorState() { + SetEvent(overlapped_.hEvent); + server_state_ = IPC_SERVER_STATE_ERROR; +} + +void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) { + server_state_ = state; +} + +void CrashGenerationServer::EnterStateImmediately(IPCServerState state) { + server_state_ = state; + + if (!SetEvent(overlapped_.hEvent)) { + server_state_ = IPC_SERVER_STATE_ERROR; + } +} + +bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info, + ProtocolMessage* reply) const { + reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE; + reply->id = GetCurrentProcessId(); + + if (CreateClientHandles(client_info, reply)) { + return true; + } + + // Closing of remote handles (belonging to a different process) can + // only be done through DuplicateHandle. + if (reply->dump_request_handle) { + DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle + reply->dump_request_handle, // hSourceHandle + NULL, // hTargetProcessHandle + 0, // lpTargetHandle + 0, // dwDesiredAccess + FALSE, // bInheritHandle + DUPLICATE_CLOSE_SOURCE); // dwOptions + reply->dump_request_handle = NULL; + } + + if (reply->dump_generated_handle) { + DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle + reply->dump_generated_handle, // hSourceHandle + NULL, // hTargetProcessHandle + 0, // lpTargetHandle + 0, // dwDesiredAccess + FALSE, // bInheritHandle + DUPLICATE_CLOSE_SOURCE); // dwOptions + reply->dump_generated_handle = NULL; + } + + if (reply->server_alive_handle) { + DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle + reply->server_alive_handle, // hSourceHandle + NULL, // hTargetProcessHandle + 0, // lpTargetHandle + 0, // dwDesiredAccess + FALSE, // bInheritHandle + DUPLICATE_CLOSE_SOURCE); // dwOptions + reply->server_alive_handle = NULL; + } + + return false; +} + +bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info, + ProtocolMessage* reply) const { + HANDLE current_process = GetCurrentProcess(); + if (!DuplicateHandle(current_process, + client_info.dump_requested_handle(), + client_info.process_handle(), + &reply->dump_request_handle, + kDumpRequestEventAccess, + FALSE, + 0)) { + return false; + } + + if (!DuplicateHandle(current_process, + client_info.dump_generated_handle(), + client_info.process_handle(), + &reply->dump_generated_handle, + kDumpGeneratedEventAccess, + FALSE, + 0)) { + return false; + } + + if (!DuplicateHandle(current_process, + server_alive_handle_, + client_info.process_handle(), + &reply->server_alive_handle, + kMutexAccess, + FALSE, + 0)) { + return false; + } + + return true; +} + +bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) { + ProtocolMessage reply; + if (!PrepareReply(*client_info, &reply)) { + return false; + } + + DWORD bytes_count = 0; + bool success = WriteFile(pipe_, + &reply, + sizeof(reply), + &bytes_count, + &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + if (!success && error_code != ERROR_IO_PENDING) { + return false; + } + + // Takes over ownership of client_info. We MUST return true if AddClient + // succeeds. + return AddClient(client_info); +} + +// The server thread servicing the clients runs this method. The method +// implements the state machine described in ReadMe.txt along with the +// helper methods HandleXXXState. +void CrashGenerationServer::HandleConnectionRequest() { + // If the server is shutting down, get into ERROR state, reset the event so + // more workers don't run and return immediately. + if (shutting_down_) { + server_state_ = IPC_SERVER_STATE_ERROR; + ResetEvent(overlapped_.hEvent); + return; + } + + switch (server_state_) { + case IPC_SERVER_STATE_ERROR: + HandleErrorState(); + break; + + case IPC_SERVER_STATE_INITIAL: + HandleInitialState(); + break; + + case IPC_SERVER_STATE_CONNECTING: + HandleConnectingState(); + break; + + case IPC_SERVER_STATE_CONNECTED: + HandleConnectedState(); + break; + + case IPC_SERVER_STATE_READING: + HandleReadingState(); + break; + + case IPC_SERVER_STATE_READ_DONE: + HandleReadDoneState(); + break; + + case IPC_SERVER_STATE_WRITING: + HandleWritingState(); + break; + + case IPC_SERVER_STATE_WRITE_DONE: + HandleWriteDoneState(); + break; + + case IPC_SERVER_STATE_READING_ACK: + HandleReadingAckState(); + break; + + case IPC_SERVER_STATE_DISCONNECTING: + HandleDisconnectingState(); + break; + + default: + assert(false); + // This indicates that we added one more state without + // adding handling code. + server_state_ = IPC_SERVER_STATE_ERROR; + break; + } +} + +bool CrashGenerationServer::AddClient(ClientInfo* client_info) { + HANDLE request_wait_handle = NULL; + if (!RegisterWaitForSingleObject(&request_wait_handle, + client_info->dump_requested_handle(), + OnDumpRequest, + client_info, + INFINITE, + kDumpRequestThreadFlags)) { + return false; + } + + client_info->set_dump_request_wait_handle(request_wait_handle); + + // OnClientEnd will be called when the client process terminates. + HANDLE process_wait_handle = NULL; + if (!RegisterWaitForSingleObject(&process_wait_handle, + client_info->process_handle(), + OnClientEnd, + client_info, + INFINITE, + WT_EXECUTEONLYONCE)) { + return false; + } + + client_info->set_process_exit_wait_handle(process_wait_handle); + + // New scope to hold the lock for the shortest time. + { + AutoCriticalSection lock(&sync_); + if (shutting_down_) { + // If server is shutting down, don't add new clients + return false; + } + clients_.push_back(client_info); + } + + return true; +} + +// static +void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) { + assert(context); + + CrashGenerationServer* obj = + reinterpret_cast(context); + obj->HandleConnectionRequest(); +} + +// static +void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { + assert(context); + ClientInfo* client_info = reinterpret_cast(context); + + CrashGenerationServer* crash_server = client_info->crash_server(); + assert(crash_server); + if (crash_server->pre_fetch_custom_info_) { + client_info->PopulateCustomInfo(); + } + client_info->PopulateAppMemory(); + crash_server->HandleDumpRequest(*client_info); + + ResetEvent(client_info->dump_requested_handle()); +} + +// static +void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) { + assert(context); + ClientInfo* client_info = reinterpret_cast(context); + + CrashGenerationServer* crash_server = client_info->crash_server(); + assert(crash_server); + + crash_server->HandleClientProcessExit(client_info); +} + +void CrashGenerationServer::HandleClientProcessExit(ClientInfo* client_info) { + assert(client_info); + + // Must unregister the dump request wait operation and wait for any + // dump requests that might be pending to finish before proceeding + // with the client_info cleanup. + client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + if (exit_callback_) { + exit_callback_(exit_context_, client_info); + } + + // Start a new scope to release lock automatically. + { + AutoCriticalSection lock(&sync_); + if (shutting_down_) { + // The crash generation server is shutting down and as part of the + // shutdown process it will delete all clients from the clients_ list. + return; + } + clients_.remove(client_info); + } + + // Explicitly unregister the process exit wait using the non-blocking method. + // Otherwise, the destructor will attempt to unregister it using the blocking + // method which will lead to a deadlock because it is being called from the + // callback of the same wait operation + client_info->UnregisterProcessExitWait(false); + + delete client_info; +} + +void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) { + bool execute_callback = true; + // Generate the dump only if it's explicitly requested by the + // server application; otherwise the server might want to generate + // dump in the callback. + std::wstring dump_path; + if (generate_dumps_) { + if (!GenerateDump(client_info, &dump_path)) { + // client proccess terminated or some other error + execute_callback = false; + } + } + + if (dump_callback_ && execute_callback) { + std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path; + dump_callback_(dump_context_, &client_info, ptr_dump_path); + } + + SetEvent(client_info.dump_generated_handle()); +} + +bool CrashGenerationServer::GenerateDump(const ClientInfo& client, + std::wstring* dump_path) { + assert(client.pid() != 0); + assert(client.process_handle()); + + // We have to get the address of EXCEPTION_INFORMATION from + // the client process address space. + EXCEPTION_POINTERS* client_ex_info = NULL; + if (!client.GetClientExceptionInfo(&client_ex_info)) { + return false; + } + + DWORD client_thread_id = 0; + if (!client.GetClientThreadId(&client_thread_id)) { + return false; + } + + return dump_generator_->WriteMinidump(client.process_handle(), + client.pid(), + client_thread_id, + GetCurrentThreadId(), + client_ex_info, + client.assert_info(), + client.GetAppMemory(), + client.dump_type(), + true, + dump_path); +} + +} // namespace google_breakpad diff --git a/breakpad/client/windows/crash_generation/crash_generation_server.h b/breakpad/client/windows/crash_generation/crash_generation_server.h new file mode 100644 index 0000000000..070198582c --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_server.h @@ -0,0 +1,299 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__ +#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__ + +#include +#include +#include "client/windows/common/ipc_protocol.h" +#include "client/windows/crash_generation/minidump_generator.h" +#include "common/scoped_ptr.h" + +namespace google_breakpad { +class ClientInfo; + +// Abstraction for server side implementation of out-of-process crash +// generation protocol for Windows platform only. It generates Windows +// minidump files for client processes that request dump generation. When +// the server is requested to start listening for clients (by calling the +// Start method), it creates a named pipe and waits for the clients to +// register. In response, it hands them event handles that the client can +// signal to request dump generation. When the clients request dump +// generation in this way, the server generates Windows minidump files. +class CrashGenerationServer { + public: + typedef void (*OnClientConnectedCallback)(void* context, + const ClientInfo* client_info); + + typedef void (*OnClientDumpRequestCallback)(void* context, + const ClientInfo* client_info, + const std::wstring* file_path); + + typedef void (*OnClientExitedCallback)(void* context, + const ClientInfo* client_info); + + typedef void (*OnClientUploadRequestCallback)(void* context, + const DWORD crash_id); + + // Creates an instance with the given parameters. + // + // Parameter pipe_name: Name of the Windows named pipe + // Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass + // NULL to use default security on the pipe. By default, the pipe created + // allows Local System, Administrators and the Creator full control and + // the Everyone group read access on the pipe. + // Parameter connect_callback: Callback for a new client connection. + // Parameter connect_context: Context for client connection callback. + // Parameter crash_callback: Callback for a client crash dump request. + // Parameter crash_context: Context for client crash dump request callback. + // Parameter exit_callback: Callback for client process exit. + // Parameter exit_context: Context for client exit callback. + // Parameter generate_dumps: Whether to automatically generate dumps. + // Client code of this class might want to generate dumps explicitly in the + // crash dump request callback. In that case, false can be passed for this + // parameter. + // Parameter dump_path: Path for generating dumps; required only if true is + // passed for generateDumps parameter; NULL can be passed otherwise. + CrashGenerationServer(const std::wstring& pipe_name, + SECURITY_ATTRIBUTES* pipe_sec_attrs, + OnClientConnectedCallback connect_callback, + void* connect_context, + OnClientDumpRequestCallback dump_callback, + void* dump_context, + OnClientExitedCallback exit_callback, + void* exit_context, + OnClientUploadRequestCallback upload_request_callback, + void* upload_context, + bool generate_dumps, + const std::wstring* dump_path); + + ~CrashGenerationServer(); + + // Performs initialization steps needed to start listening to clients. Upon + // successful return clients may connect to this server's pipe. + // + // Returns true if initialization is successful; false otherwise. + bool Start(); + + void pre_fetch_custom_info(bool do_pre_fetch) { + pre_fetch_custom_info_ = do_pre_fetch; + } + + private: + // Various states the client can be in during the handshake with + // the server. + enum IPCServerState { + // Server starts in this state. + IPC_SERVER_STATE_UNINITIALIZED, + + // Server is in error state and it cannot serve any clients. + IPC_SERVER_STATE_ERROR, + + // Server starts in this state. + IPC_SERVER_STATE_INITIAL, + + // Server has issued an async connect to the pipe and it is waiting + // for the connection to be established. + IPC_SERVER_STATE_CONNECTING, + + // Server is connected successfully. + IPC_SERVER_STATE_CONNECTED, + + // Server has issued an async read from the pipe and it is waiting for + // the read to finish. + IPC_SERVER_STATE_READING, + + // Server is done reading from the pipe. + IPC_SERVER_STATE_READ_DONE, + + // Server has issued an async write to the pipe and it is waiting for + // the write to finish. + IPC_SERVER_STATE_WRITING, + + // Server is done writing to the pipe. + IPC_SERVER_STATE_WRITE_DONE, + + // Server has issued an async read from the pipe for an ack and it + // is waiting for the read to finish. + IPC_SERVER_STATE_READING_ACK, + + // Server is done writing to the pipe and it is now ready to disconnect + // and reconnect. + IPC_SERVER_STATE_DISCONNECTING + }; + + // + // Helper methods to handle various server IPC states. + // + void HandleErrorState(); + void HandleInitialState(); + void HandleConnectingState(); + void HandleConnectedState(); + void HandleReadingState(); + void HandleReadDoneState(); + void HandleWritingState(); + void HandleWriteDoneState(); + void HandleReadingAckState(); + void HandleDisconnectingState(); + + // Prepares reply for a client from the given parameters. + bool PrepareReply(const ClientInfo& client_info, + ProtocolMessage* reply) const; + + // Duplicates various handles in the ClientInfo object for the client + // process and stores them in the given ProtocolMessage instance. If + // creating any handle fails, ProtocolMessage will contain the handles + // already created successfully, which should be closed by the caller. + bool CreateClientHandles(const ClientInfo& client_info, + ProtocolMessage* reply) const; + + // Response to the given client. Return true if all steps of + // responding to the client succeed, false otherwise. + bool RespondToClient(ClientInfo* client_info); + + // Handles a connection request from the client. + void HandleConnectionRequest(); + + // Handles a dump request from the client. + void HandleDumpRequest(const ClientInfo& client_info); + + // Callback for pipe connected event. + static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait); + + // Callback for a dump request. + static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait); + + // Callback for client process exit event. + static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait); + + // Handles client process exit. + void HandleClientProcessExit(ClientInfo* client_info); + + // Adds the given client to the list of registered clients. + bool AddClient(ClientInfo* client_info); + + // Generates dump for the given client. + bool GenerateDump(const ClientInfo& client, std::wstring* dump_path); + + // Puts the server in a permanent error state and sets a signal such that + // the state will be immediately entered after the current state transition + // is complete. + void EnterErrorState(); + + // Puts the server in the specified state and sets a signal such that the + // state is immediately entered after the current state transition is + // complete. + void EnterStateImmediately(IPCServerState state); + + // Puts the server in the specified state. No signal will be set, so the state + // transition will only occur when signaled manually or by completion of an + // asynchronous IO operation. + void EnterStateWhenSignaled(IPCServerState state); + + // Sync object for thread-safe access to the shared list of clients. + CRITICAL_SECTION sync_; + + // List of clients. + std::list clients_; + + // Pipe name. + std::wstring pipe_name_; + + // Pipe security attributes + SECURITY_ATTRIBUTES* pipe_sec_attrs_; + + // Handle to the pipe used for handshake with clients. + HANDLE pipe_; + + // Pipe wait handle. + HANDLE pipe_wait_handle_; + + // Handle to server-alive mutex. + HANDLE server_alive_handle_; + + // Callback for a successful client connection. + OnClientConnectedCallback connect_callback_; + + // Context for client connected callback. + void* connect_context_; + + // Callback for a client dump request. + OnClientDumpRequestCallback dump_callback_; + + // Context for client dump request callback. + void* dump_context_; + + // Callback for client process exit. + OnClientExitedCallback exit_callback_; + + // Context for client process exit callback. + void* exit_context_; + + // Callback for upload request. + OnClientUploadRequestCallback upload_request_callback_; + + // Context for upload request callback. + void* upload_context_; + + // Whether to generate dumps. + bool generate_dumps_; + + // Wether to populate custom information up-front. + bool pre_fetch_custom_info_; + + // Instance of a mini dump generator. + scoped_ptr dump_generator_; + + // State of the server in performing the IPC with the client. + // Note that since we restrict the pipe to one instance, we + // only need to keep one state of the server. Otherwise, server + // would have one state per client it is talking to. + IPCServerState server_state_; + + // Whether the server is shutting down. + bool shutting_down_; + + // Overlapped instance for async I/O on the pipe. + OVERLAPPED overlapped_; + + // Message object used in IPC with the client. + ProtocolMessage msg_; + + // Client Info for the client that's connecting to the server. + ClientInfo* client_info_; + + // Disable copy ctor and operator=. + CrashGenerationServer(const CrashGenerationServer& crash_server); + CrashGenerationServer& operator=(const CrashGenerationServer& crash_server); +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__ diff --git a/breakpad/client/windows/crash_generation/crash_generation_server.vcxproj b/breakpad/client/windows/crash_generation/crash_generation_server.vcxproj new file mode 100644 index 0000000000..39fd49c962 --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_server.vcxproj @@ -0,0 +1,385 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Purify + Win32 + + + Purify + x64 + + + Release + Win32 + + + Release + x64 + + + + {7893E300-3ED0-7F4C-158F-67EA63934C57} + Win32Proj + crash_generation_server + + + + Unicode + StaticLibrary + + + + + + + + + $(ExecutablePath);$(MSBuildProjectDirectory)\..\..\..\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\..\..\third_party\python_26\ + $(SolutionDir)$(Configuration)\$(Platform)\ + $(OutDir)obj\$(ProjectName)\ + false + false + false + false + true + true + $(ProjectName) + $(OutDir)\$(ProjectName).lib + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + false + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + false + false + true + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + true + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + true + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib32\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib32\ + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib64\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib64\ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/breakpad/client/windows/crash_generation/crash_generation_server.vcxproj.filters b/breakpad/client/windows/crash_generation/crash_generation_server.vcxproj.filters new file mode 100644 index 0000000000..84f57a4699 --- /dev/null +++ b/breakpad/client/windows/crash_generation/crash_generation_server.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/breakpad/client/windows/crash_generation/minidump_generator.cc b/breakpad/client/windows/crash_generation/minidump_generator.cc new file mode 100644 index 0000000000..dd5515a469 --- /dev/null +++ b/breakpad/client/windows/crash_generation/minidump_generator.cc @@ -0,0 +1,624 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "client/windows/crash_generation/minidump_generator.h" + +#include +#include + +#include +#include +#include +#include + +#include "client/windows/common/auto_critical_section.h" +#include "common/windows/guid_string.h" + +using std::wstring; + +namespace { + +// A helper class used to collect handle operations data. Unlike +// |MiniDumpWithHandleData| it records the operations for a single handle value +// only, making it possible to include this information to a minidump. +class HandleTraceData { + public: + HandleTraceData(); + ~HandleTraceData(); + + // Collects the handle operations data and formats a user stream to be added + // to the minidump. + bool CollectHandleData(HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers); + + // Fills the user dump entry with a pointer to the collected handle operations + // data. Returns |true| if the entry was initialized successfully, or |false| + // if no trace data is available. + bool GetUserStream(MINIDUMP_USER_STREAM* user_stream); + + private: + // Reads the exception code from the client process's address space. + // This routine assumes that the client process's pointer width matches ours. + static bool ReadExceptionCode(HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers, + DWORD* exception_code); + + // Stores handle operations retrieved by VerifierEnumerateResource(). + static ULONG CALLBACK RecordHandleOperations(void* resource_description, + void* enumeration_context, + ULONG* enumeration_level); + + // Function pointer type for VerifierEnumerateResource, which is looked up + // dynamically. + typedef BOOL (WINAPI* VerifierEnumerateResourceType)( + HANDLE Process, + ULONG Flags, + ULONG ResourceType, + AVRF_RESOURCE_ENUMERATE_CALLBACK ResourceCallback, + PVOID EnumerationContext); + + // Handle to dynamically loaded verifier.dll. + HMODULE verifier_module_; + + // Pointer to the VerifierEnumerateResource function. + VerifierEnumerateResourceType enumerate_resource_; + + // Handle value to look for. + ULONG64 handle_; + + // List of handle operations for |handle_|. + std::list operations_; + + // Minidump stream data. + std::vector stream_; +}; + +HandleTraceData::HandleTraceData() + : verifier_module_(NULL), + enumerate_resource_(NULL), + handle_(NULL) { +} + +HandleTraceData::~HandleTraceData() { + if (verifier_module_) { + FreeLibrary(verifier_module_); + } +} + +bool HandleTraceData::CollectHandleData( + HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers) { + DWORD exception_code; + if (!ReadExceptionCode(process_handle, exception_pointers, &exception_code)) { + return false; + } + + // Verify whether the execption is STATUS_INVALID_HANDLE. Do not record any + // handle information if it is a different exception to keep the minidump + // small. + if (exception_code != STATUS_INVALID_HANDLE) { + return true; + } + + // Load verifier!VerifierEnumerateResource() dynamically. + verifier_module_ = LoadLibrary(TEXT("verifier.dll")); + if (!verifier_module_) { + return false; + } + + enumerate_resource_ = reinterpret_cast( + GetProcAddress(verifier_module_, "VerifierEnumerateResource")); + if (!enumerate_resource_) { + return false; + } + + // STATUS_INVALID_HANDLE does not provide the offending handle value in + // the exception parameters so we have to guess. At the moment we scan + // the handle operations trace looking for the last invalid handle operation + // and record only the operations for that handle value. + if (enumerate_resource_(process_handle, + 0, + AvrfResourceHandleTrace, + &RecordHandleOperations, + this) != ERROR_SUCCESS) { + // The handle tracing must have not been enabled. + return true; + } + + // Now that |handle_| is initialized, purge all irrelevant operations. + std::list::iterator i = operations_.begin(); + std::list::iterator i_end = operations_.end(); + while (i != i_end) { + if (i->Handle == handle_) { + ++i; + } else { + i = operations_.erase(i); + } + } + + // Convert the list of recorded operations to a minidump stream. + stream_.resize(sizeof(MINIDUMP_HANDLE_OPERATION_LIST) + + sizeof(AVRF_HANDLE_OPERATION) * operations_.size()); + + MINIDUMP_HANDLE_OPERATION_LIST* stream_data = + reinterpret_cast( + &stream_.front()); + stream_data->SizeOfHeader = sizeof(MINIDUMP_HANDLE_OPERATION_LIST); + stream_data->SizeOfEntry = sizeof(AVRF_HANDLE_OPERATION); + stream_data->NumberOfEntries = static_cast(operations_.size()); + stream_data->Reserved = 0; + std::copy(operations_.begin(), + operations_.end(), + stdext::checked_array_iterator( + reinterpret_cast(stream_data + 1), + operations_.size())); + + return true; +} + +bool HandleTraceData::GetUserStream(MINIDUMP_USER_STREAM* user_stream) { + if (stream_.empty()) { + return false; + } else { + user_stream->Type = HandleOperationListStream; + user_stream->BufferSize = static_cast(stream_.size()); + user_stream->Buffer = &stream_.front(); + return true; + } +} + +bool HandleTraceData::ReadExceptionCode( + HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers, + DWORD* exception_code) { + EXCEPTION_POINTERS pointers; + if (!ReadProcessMemory(process_handle, + exception_pointers, + &pointers, + sizeof(pointers), + NULL)) { + return false; + } + + if (!ReadProcessMemory(process_handle, + pointers.ExceptionRecord, + exception_code, + sizeof(*exception_code), + NULL)) { + return false; + } + + return true; +} + +ULONG CALLBACK HandleTraceData::RecordHandleOperations( + void* resource_description, + void* enumeration_context, + ULONG* enumeration_level) { + AVRF_HANDLE_OPERATION* description = + reinterpret_cast(resource_description); + HandleTraceData* self = + reinterpret_cast(enumeration_context); + + // Remember the last invalid handle operation. + if (description->OperationType == OperationDbBADREF) { + self->handle_ = description->Handle; + } + + // Record all handle operations. + self->operations_.push_back(*description); + + *enumeration_level = HeapEnumerationEverything; + return ERROR_SUCCESS; +} + +} // namespace + +namespace google_breakpad { + +// This is passed as the context to the MinidumpWriteDump callback. +typedef struct { + const AppMemory *regions; + ULONG idx; + ULONG count; +} MinidumpCallbackCtx; + +// static +BOOL CALLBACK MinidumpGenerator::MinidumpWriteDumpCallback( + PVOID context, + const PMINIDUMP_CALLBACK_INPUT callback_input, + PMINIDUMP_CALLBACK_OUTPUT callback_output) { + switch (callback_input->CallbackType) { + case MemoryCallback: { + MinidumpCallbackCtx* callback_context = + reinterpret_cast(context); + if (callback_context->idx == callback_context->count) + return FALSE; + + // Include the specified memory region. + callback_output->MemoryBase = callback_context->regions[callback_context->idx].ptr; + callback_output->MemorySize = callback_context->regions[callback_context->idx].length; + callback_context->idx++; + return TRUE; + } + + // Include all modules. + case IncludeModuleCallback: + case ModuleCallback: + return TRUE; + + // Include all threads. + case IncludeThreadCallback: + case ThreadCallback: + return TRUE; + + // Stop receiving cancel callbacks. + case CancelCallback: + callback_output->CheckCancel = FALSE; + callback_output->Cancel = FALSE; + return TRUE; + } + // Ignore other callback types. + return FALSE; +} + +MinidumpGenerator::MinidumpGenerator(const wstring& dump_path) + : dbghelp_module_(NULL), + rpcrt4_module_(NULL), + dump_path_(dump_path), + write_dump_(NULL), + create_uuid_(NULL) { + InitializeCriticalSection(&module_load_sync_); + InitializeCriticalSection(&get_proc_address_sync_); +} + +MinidumpGenerator::~MinidumpGenerator() { + if (dbghelp_module_) { + FreeLibrary(dbghelp_module_); + } + + if (rpcrt4_module_) { + FreeLibrary(rpcrt4_module_); + } + + DeleteCriticalSection(&get_proc_address_sync_); + DeleteCriticalSection(&module_load_sync_); +} + +bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, + DWORD process_id, + DWORD thread_id, + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + AppMemoryInfo app_memory, + MINIDUMP_TYPE dump_type, + bool is_client_pointers, + wstring* dump_path) { + // Just call the full WriteMinidump with NULL as the full_dump_path. + return this->WriteMinidump(process_handle, process_id, thread_id, + requesting_thread_id, exception_pointers, + assert_info, app_memory, dump_type, + is_client_pointers, dump_path, NULL); +} + +bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, + DWORD process_id, + DWORD thread_id, + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + AppMemoryInfo app_memory, + MINIDUMP_TYPE dump_type, + bool is_client_pointers, + wstring* dump_path, + wstring* full_dump_path) { + wstring dump_file_path; + if (!GenerateDumpFilePath(&dump_file_path)) { + return false; + } + + // If the client requests a full memory dump, we will write a normal mini + // dump and a full memory dump. Both dump files use the same uuid as file + // name prefix. + bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0; + wstring full_dump_file_path; + if (full_memory_dump) { + full_dump_file_path.assign(dump_file_path); + full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp + full_dump_file_path.append(TEXT("-full.dmp")); + } + + HANDLE dump_file = CreateFile(dump_file_path.c_str(), + GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (dump_file == INVALID_HANDLE_VALUE) { + return false; + } + + HANDLE full_dump_file = INVALID_HANDLE_VALUE; + if (full_memory_dump) { + full_dump_file = CreateFile(full_dump_file_path.c_str(), + GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (full_dump_file == INVALID_HANDLE_VALUE) { + CloseHandle(dump_file); + return false; + } + } + + bool result = WriteMinidump(process_handle, + process_id, + thread_id, + requesting_thread_id, + exception_pointers, + assert_info, + app_memory, + dump_type, + is_client_pointers, + dump_file, + full_dump_file); + + // Store the path of the dump file in the out parameter if dump generation + // succeeded. + if (result && dump_path) { + *dump_path = dump_file_path; + } + if (result && full_memory_dump && full_dump_path) { + *full_dump_path = full_dump_file_path; + } + + CloseHandle(dump_file); + if (full_dump_file != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file); + + return result; +} + +bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, + DWORD process_id, + DWORD thread_id, + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + AppMemoryInfo app_memory, + MINIDUMP_TYPE dump_type, + bool is_client_pointers, + HANDLE dump_file, + HANDLE full_dump_file) { + bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0; + if (dump_file == INVALID_HANDLE_VALUE || + (full_memory_dump && full_dump_file == INVALID_HANDLE_VALUE)) { + return false; + } + + MiniDumpWriteDumpType write_dump = GetWriteDump(); + if (!write_dump) { + return false; + } + + MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL; + MINIDUMP_EXCEPTION_INFORMATION dump_exception_info; + + // Setup the exception information object only if it's a dump + // due to an exception. + if (exception_pointers) { + dump_exception_pointers = &dump_exception_info; + dump_exception_info.ThreadId = thread_id; + dump_exception_info.ExceptionPointers = exception_pointers; + dump_exception_info.ClientPointers = is_client_pointers; + } + + // Add an MDRawBreakpadInfo stream to the minidump, to provide additional + // information about the exception handler to the Breakpad processor. + // The information will help the processor determine which threads are + // relevant. The Breakpad processor does not require this information but + // can function better with Breakpad-generated dumps when it is present. + // The native debugger is not harmed by the presence of this information. + MDRawBreakpadInfo breakpad_info = {0}; + if (!is_client_pointers) { + // Set the dump thread id and requesting thread id only in case of + // in-process dump generation. + breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; + breakpad_info.dump_thread_id = thread_id; + breakpad_info.requesting_thread_id = requesting_thread_id; + } + + // Leave room in user_stream_array for possible assertion info and handle + // operations streams. + MINIDUMP_USER_STREAM user_stream_array[3]; + user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; + user_stream_array[0].BufferSize = sizeof(breakpad_info); + user_stream_array[0].Buffer = &breakpad_info; + + MINIDUMP_USER_STREAM_INFORMATION user_streams; + user_streams.UserStreamCount = 1; + user_streams.UserStreamArray = user_stream_array; + + MDRawAssertionInfo* actual_assert_info = assert_info; + MDRawAssertionInfo client_assert_info = {0}; + + if (assert_info) { + // If the assertion info object lives in the client process, + // read the memory of the client process. + if (is_client_pointers) { + SIZE_T bytes_read = 0; + if (!ReadProcessMemory(process_handle, + assert_info, + &client_assert_info, + sizeof(client_assert_info), + &bytes_read)) { + CloseHandle(dump_file); + if (full_dump_file != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file); + return false; + } + + if (bytes_read != sizeof(client_assert_info)) { + CloseHandle(dump_file); + if (full_dump_file != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file); + return false; + } + + actual_assert_info = &client_assert_info; + } + + user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM; + user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo); + user_stream_array[1].Buffer = actual_assert_info; + ++user_streams.UserStreamCount; + } + + // If the process is terminated by STATUS_INVALID_HANDLE exception store + // the trace of operatios for the offending handle value. Do nothing special + // if the client already requested the handle trace to be stored in the dump. + HandleTraceData handle_trace_data; + if (exception_pointers && (dump_type & MiniDumpWithHandleData) == 0) { + if (!handle_trace_data.CollectHandleData(process_handle, + exception_pointers)) { + CloseHandle(dump_file); + if (full_dump_file != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file); + return false; + } + } + + MinidumpCallbackCtx context; + context.regions = app_memory.entries; + context.idx = 0; + context.count = app_memory.count; + + MINIDUMP_CALLBACK_INFORMATION callback; + callback.CallbackRoutine = MinidumpWriteDumpCallback; + callback.CallbackParam = reinterpret_cast(&context); + + bool result_full_memory = true; + if (full_memory_dump) { + result_full_memory = write_dump( + process_handle, + process_id, + full_dump_file, + static_cast((dump_type & (~MiniDumpNormal)) + | MiniDumpWithHandleData), + exception_pointers ? &dump_exception_info : NULL, + &user_streams, + &callback) != FALSE; + } + + // Add handle operations trace stream to the minidump if it was collected. + if (handle_trace_data.GetUserStream( + &user_stream_array[user_streams.UserStreamCount])) { + ++user_streams.UserStreamCount; + } + + bool result_minidump = write_dump( + process_handle, + process_id, + dump_file, + static_cast((dump_type & (~MiniDumpWithFullMemory)) + | MiniDumpNormal), + exception_pointers ? &dump_exception_info : NULL, + &user_streams, + &callback) != FALSE; + + return result_minidump && result_full_memory; +} + +HMODULE MinidumpGenerator::GetDbghelpModule() { + AutoCriticalSection lock(&module_load_sync_); + if (!dbghelp_module_) { + dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll")); + } + + return dbghelp_module_; +} + +MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() { + AutoCriticalSection lock(&get_proc_address_sync_); + if (!write_dump_) { + HMODULE module = GetDbghelpModule(); + if (module) { + FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump"); + write_dump_ = reinterpret_cast(proc); + } + } + + return write_dump_; +} + +HMODULE MinidumpGenerator::GetRpcrt4Module() { + AutoCriticalSection lock(&module_load_sync_); + if (!rpcrt4_module_) { + rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll")); + } + + return rpcrt4_module_; +} + +MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() { + AutoCriticalSection lock(&module_load_sync_); + if (!create_uuid_) { + HMODULE module = GetRpcrt4Module(); + if (module) { + FARPROC proc = GetProcAddress(module, "UuidCreate"); + create_uuid_ = reinterpret_cast(proc); + } + } + + return create_uuid_; +} + +bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) { + UUID id = {0}; + + UuidCreateType create_uuid = GetCreateUuid(); + if (!create_uuid) { + return false; + } + + create_uuid(&id); + wstring id_str = GUIDString::GUIDToWString(&id); + + *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp"); + return true; +} + +} // namespace google_breakpad diff --git a/breakpad/client/windows/crash_generation/minidump_generator.h b/breakpad/client/windows/crash_generation/minidump_generator.h new file mode 100644 index 0000000000..0347726878 --- /dev/null +++ b/breakpad/client/windows/crash_generation/minidump_generator.h @@ -0,0 +1,162 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_ +#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_ + +#include +#include +#include +#include +#include "google_breakpad/common/minidump_format.h" +#include "client/windows/common/ipc_protocol.h" + +namespace google_breakpad { + +// Abstraction for various objects and operations needed to generate +// minidump on Windows. This abstraction is useful to hide all the gory +// details for minidump generation and provide a clean interface to +// the clients to generate minidumps. +class MinidumpGenerator { + public: + // Creates an instance with the given dump path. + explicit MinidumpGenerator(const std::wstring& dump_path); + + ~MinidumpGenerator(); + + // Writes the minidump with the given parameters. Stores the + // dump file path in the dump_path parameter if dump generation + // succeeds. + bool WriteMinidump(HANDLE process_handle, + DWORD process_id, + DWORD thread_id, + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + AppMemoryInfo app_memory, + MINIDUMP_TYPE dump_type, + bool is_client_pointers, + std::wstring* dump_path); + + // Writes the minidump with the given parameters. Stores the dump file + // path in the dump_path (and full_dump_path) parameter if dump + // generation succeeds. full_dump_path and dump_path can be NULL. + bool WriteMinidump(HANDLE process_handle, + DWORD process_id, + DWORD thread_id, + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + AppMemoryInfo app_memory, + MINIDUMP_TYPE dump_type, + bool is_client_pointers, + std::wstring* dump_path, + std::wstring* full_dump_path); + + // Writes the minidump with the given parameters. Writes the minidump and + // full dump to the file handles supplied. This allows the caller to handle + // the creation of the files for the dump. The file handles are not closed + // by this function. + bool WriteMinidump(HANDLE process_handle, + DWORD process_id, + DWORD thread_id, + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + AppMemoryInfo app_memory, + MINIDUMP_TYPE dump_type, + bool is_client_pointers, + HANDLE dump_file, + HANDLE full_dump_file); + + private: + // Function pointer type for MiniDumpWriteDump, which is looked up + // dynamically. + typedef BOOL (WINAPI* MiniDumpWriteDumpType)( + HANDLE hProcess, + DWORD ProcessId, + HANDLE hFile, + MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); + + // This function is used as a callback when calling MinidumpWriteDump, + // in order to add additional memory regions to the dump. + static BOOL CALLBACK MinidumpWriteDumpCallback( + PVOID context, + const PMINIDUMP_CALLBACK_INPUT callback_input, + PMINIDUMP_CALLBACK_OUTPUT callback_output); + + // Function pointer type for UuidCreate, which is looked up dynamically. + typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid); + + // Loads the appropriate DLL lazily in a thread safe way. + HMODULE GetDbghelpModule(); + + // Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump + // function lazily and in a thread-safe manner. + MiniDumpWriteDumpType GetWriteDump(); + + // Loads the appropriate DLL lazily in a thread safe way. + HMODULE GetRpcrt4Module(); + + // Loads the appropriate DLL and gets a pointer to the UuidCreate + // function lazily and in a thread-safe manner. + UuidCreateType GetCreateUuid(); + + // Returns the path for the file to write dump to. + bool GenerateDumpFilePath(std::wstring* file_path); + + // Handle to dynamically loaded DbgHelp.dll. + HMODULE dbghelp_module_; + + // Pointer to the MiniDumpWriteDump function. + MiniDumpWriteDumpType write_dump_; + + // Handle to dynamically loaded rpcrt4.dll. + HMODULE rpcrt4_module_; + + // Pointer to the UuidCreate function. + UuidCreateType create_uuid_; + + // Folder path to store dump files. + std::wstring dump_path_; + + // Critical section to sychronize action of loading modules dynamically. + CRITICAL_SECTION module_load_sync_; + + // Critical section to synchronize action of dynamically getting function + // addresses from modules. + CRITICAL_SECTION get_proc_address_sync_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_ diff --git a/breakpad/client/windows/handler/exception_handler.cc b/breakpad/client/windows/handler/exception_handler.cc new file mode 100644 index 0000000000..10d781289c --- /dev/null +++ b/breakpad/client/windows/handler/exception_handler.cc @@ -0,0 +1,1070 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include +#include +#include + +#include "common/windows/string_utils-inl.h" + +#include "client/windows/common/ipc_protocol.h" +#include "client/windows/handler/exception_handler.h" +#include "common/windows/guid_string.h" + +namespace google_breakpad { + +static const int kWaitForHandlerThreadMs = 60000; +static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; + +// As documented on MSDN, on failure SuspendThread returns (DWORD) -1 +static const DWORD kFailedToSuspendThread = static_cast(-1); + +// This is passed as the context to the MinidumpWriteDump callback. +typedef struct { + AppMemoryList::const_iterator iter; + AppMemoryList::const_iterator end; +} MinidumpCallbackContext; + +vector* ExceptionHandler::handler_stack_ = NULL; +LONG ExceptionHandler::handler_stack_index_ = 0; +CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_; +volatile LONG ExceptionHandler::instance_count_ = 0; + +ExceptionHandler::ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name, + const CustomClientInfo* custom_info) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + dump_type, + pipe_name, + NULL, // pipe_handle + NULL, // crash_generation_client + custom_info); +} + +ExceptionHandler::ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + HANDLE pipe_handle, + const CustomClientInfo* custom_info) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + dump_type, + NULL, // pipe_name + pipe_handle, + NULL, // crash_generation_client + custom_info); +} + +ExceptionHandler::ExceptionHandler( + const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + CrashGenerationClient* crash_generation_client) { + // The dump_type, pipe_name and custom_info that are passed in to Initialize() + // are not used. The ones set in crash_generation_client are used instead. + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + MiniDumpNormal, // dump_type - not used + NULL, // pipe_name - not used + NULL, // pipe_handle + crash_generation_client, + NULL); // custom_info - not used +} + +ExceptionHandler::ExceptionHandler(const wstring &dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + MiniDumpNormal, + NULL, // pipe_name + NULL, // pipe_handle + NULL, // crash_generation_client + NULL); // custom_info +} + +void ExceptionHandler::Initialize( + const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name, + HANDLE pipe_handle, + CrashGenerationClient* crash_generation_client, + const CustomClientInfo* custom_info) { + LONG instance_count = InterlockedIncrement(&instance_count_); + filter_ = filter; + callback_ = callback; + callback_context_ = callback_context; + dump_path_c_ = NULL; + next_minidump_id_c_ = NULL; + next_minidump_path_c_ = NULL; + dbghelp_module_ = NULL; + minidump_write_dump_ = NULL; + dump_type_ = dump_type; + rpcrt4_module_ = NULL; + uuid_create_ = NULL; + handler_types_ = handler_types; + previous_filter_ = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + previous_iph_ = NULL; +#endif // _MSC_VER >= 1400 + previous_pch_ = NULL; + handler_thread_ = NULL; + is_shutdown_ = false; + handler_start_semaphore_ = NULL; + handler_finish_semaphore_ = NULL; + requesting_thread_id_ = 0; + exception_info_ = NULL; + assertion_ = NULL; + handler_return_value_ = false; + handle_debug_exceptions_ = false; + + // Attempt to use out-of-process if user has specified a pipe or a + // crash generation client. + scoped_ptr client; + if (crash_generation_client) { + client.reset(crash_generation_client); + } else if (pipe_name) { + client.reset( + new CrashGenerationClient(pipe_name, dump_type_, custom_info)); + } else if (pipe_handle) { + client.reset( + new CrashGenerationClient(pipe_handle, dump_type_, custom_info)); + } + + if (client.get() != NULL) { + // If successful in registering with the monitoring process, + // there is no need to setup in-process crash generation. + if (client->Register()) { + crash_generation_client_.reset(client.release()); + } + } + + if (!IsOutOfProcess()) { + // Either client did not ask for out-of-process crash generation + // or registration with the server process failed. In either case, + // setup to do in-process crash generation. + + // Set synchronization primitives and the handler thread. Each + // ExceptionHandler object gets its own handler thread because that's the + // only way to reliably guarantee sufficient stack space in an exception, + // and it allows an easy way to get a snapshot of the requesting thread's + // context outside of an exception. + InitializeCriticalSection(&handler_critical_section_); + handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + assert(handler_start_semaphore_ != NULL); + + handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + assert(handler_finish_semaphore_ != NULL); + + // Don't attempt to create the thread if we could not create the semaphores. + if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) { + DWORD thread_id; + handler_thread_ = CreateThread(NULL, // lpThreadAttributes + kExceptionHandlerThreadInitialStackSize, + ExceptionHandlerThreadMain, + this, // lpParameter + 0, // dwCreationFlags + &thread_id); + assert(handler_thread_ != NULL); + } + + dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); + if (dbghelp_module_) { + minidump_write_dump_ = reinterpret_cast( + GetProcAddress(dbghelp_module_, "MiniDumpWriteDump")); + } + + // Load this library dynamically to not affect existing projects. Most + // projects don't link against this directly, it's usually dynamically + // loaded by dependent code. + rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll"); + if (rpcrt4_module_) { + uuid_create_ = reinterpret_cast( + GetProcAddress(rpcrt4_module_, "UuidCreate")); + } + + // set_dump_path calls UpdateNextID. This sets up all of the path and id + // strings, and their equivalent c_str pointers. + set_dump_path(dump_path); + } + + // Reserve one element for the instruction memory + AppMemory instruction_memory; + instruction_memory.ptr = NULL; + instruction_memory.length = 0; + app_memory_info_.push_back(instruction_memory); + + // There is a race condition here. If the first instance has not yet + // initialized the critical section, the second (and later) instances may + // try to use uninitialized critical section object. The feature of multiple + // instances in one module is not used much, so leave it as is for now. + // One way to solve this in the current design (that is, keeping the static + // handler stack) is to use spin locks with volatile bools to synchronize + // the handler stack. This works only if the compiler guarantees to generate + // cache coherent code for volatile. + // TODO(munjal): Fix this in a better way by changing the design if possible. + + // Lazy initialization of the handler_stack_critical_section_ + if (instance_count == 1) { + InitializeCriticalSection(&handler_stack_critical_section_); + } + + if (handler_types != HANDLER_NONE) { + EnterCriticalSection(&handler_stack_critical_section_); + + // The first time an ExceptionHandler that installs a handler is + // created, set up the handler stack. + if (!handler_stack_) { + handler_stack_ = new vector(); + } + handler_stack_->push_back(this); + + if (handler_types & HANDLER_EXCEPTION) + previous_filter_ = SetUnhandledExceptionFilter(HandleException); + +#if _MSC_VER >= 1400 // MSVC 2005/8 + if (handler_types & HANDLER_INVALID_PARAMETER) + previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter); +#endif // _MSC_VER >= 1400 + + if (handler_types & HANDLER_PURECALL) + previous_pch_ = _set_purecall_handler(HandlePureVirtualCall); + + LeaveCriticalSection(&handler_stack_critical_section_); + } +} + +ExceptionHandler::~ExceptionHandler() { + if (dbghelp_module_) { + FreeLibrary(dbghelp_module_); + } + + if (rpcrt4_module_) { + FreeLibrary(rpcrt4_module_); + } + + if (handler_types_ != HANDLER_NONE) { + EnterCriticalSection(&handler_stack_critical_section_); + + if (handler_types_ & HANDLER_EXCEPTION) + SetUnhandledExceptionFilter(previous_filter_); + +#if _MSC_VER >= 1400 // MSVC 2005/8 + if (handler_types_ & HANDLER_INVALID_PARAMETER) + _set_invalid_parameter_handler(previous_iph_); +#endif // _MSC_VER >= 1400 + + if (handler_types_ & HANDLER_PURECALL) + _set_purecall_handler(previous_pch_); + + if (handler_stack_->back() == this) { + handler_stack_->pop_back(); + } else { + // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the + // system's application event log. + fprintf(stderr, "warning: removing Breakpad handler out of order\n"); + vector::iterator iterator = handler_stack_->begin(); + while (iterator != handler_stack_->end()) { + if (*iterator == this) { + iterator = handler_stack_->erase(iterator); + } else { + ++iterator; + } + } + } + + if (handler_stack_->empty()) { + // When destroying the last ExceptionHandler that installed a handler, + // clean up the handler stack. + delete handler_stack_; + handler_stack_ = NULL; + } + + LeaveCriticalSection(&handler_stack_critical_section_); + } + + // Some of the objects were only initialized if out of process + // registration was not done. + if (!IsOutOfProcess()) { +#ifdef BREAKPAD_NO_TERMINATE_THREAD + // Clean up the handler thread and synchronization primitives. The handler + // thread is either waiting on the semaphore to handle a crash or it is + // handling a crash. Coming out of the wait is fast but wait more in the + // eventuality a crash is handled. This compilation option results in a + // deadlock if the exception handler is destroyed while executing code + // inside DllMain. + is_shutdown_ = true; + ReleaseSemaphore(handler_start_semaphore_, 1, NULL); + WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs); +#else + TerminateThread(handler_thread_, 1); +#endif // BREAKPAD_NO_TERMINATE_THREAD + + CloseHandle(handler_thread_); + handler_thread_ = NULL; + DeleteCriticalSection(&handler_critical_section_); + CloseHandle(handler_start_semaphore_); + CloseHandle(handler_finish_semaphore_); + } + + // There is a race condition in the code below: if this instance is + // deleting the static critical section and a new instance of the class + // is created, then there is a possibility that the critical section be + // initialized while the same critical section is being deleted. Given the + // usage pattern for the code, this race condition is unlikely to hit, but it + // is a race condition nonetheless. + if (InterlockedDecrement(&instance_count_) == 0) { + DeleteCriticalSection(&handler_stack_critical_section_); + } +} + +bool ExceptionHandler::RequestUpload(DWORD crash_id) { + return crash_generation_client_->RequestUpload(crash_id); +} + +// static +DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { + ExceptionHandler* self = reinterpret_cast(lpParameter); + assert(self); + assert(self->handler_start_semaphore_ != NULL); + assert(self->handler_finish_semaphore_ != NULL); + + while (true) { + if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == + WAIT_OBJECT_0) { + // Perform the requested action. + if (self->is_shutdown_) { + // The instance of the exception handler is being destroyed. + break; + } else { + self->handler_return_value_ = + self->WriteMinidumpWithException(self->requesting_thread_id_, + self->exception_info_, + self->assertion_); + } + + // Allow the requesting thread to proceed. + ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL); + } + } + + // This statement is not reached when the thread is unconditionally + // terminated by the ExceptionHandler destructor. + return 0; +} + +// HandleException and HandleInvalidParameter must create an +// AutoExceptionHandler object to maintain static state and to determine which +// ExceptionHandler instance to use. The constructor locates the correct +// instance, and makes it available through get_handler(). The destructor +// restores the state in effect prior to allocating the AutoExceptionHandler. +class AutoExceptionHandler { + public: + AutoExceptionHandler() { + // Increment handler_stack_index_ so that if another Breakpad handler is + // registered using this same HandleException function, and it needs to be + // called while this handler is running (either because this handler + // declines to handle the exception, or an exception occurs during + // handling), HandleException will find the appropriate ExceptionHandler + // object in handler_stack_ to deliver the exception to. + // + // Because handler_stack_ is addressed in reverse (as |size - index|), + // preincrementing handler_stack_index_ avoids needing to subtract 1 from + // the argument to |at|. + // + // The index is maintained instead of popping elements off of the handler + // stack and pushing them at the end of this method. This avoids ruining + // the order of elements in the stack in the event that some other thread + // decides to manipulate the handler stack (such as creating a new + // ExceptionHandler object) while an exception is being handled. + EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_); + handler_ = ExceptionHandler::handler_stack_->at( + ExceptionHandler::handler_stack_->size() - + ++ExceptionHandler::handler_stack_index_); + + // In case another exception occurs while this handler is doing its thing, + // it should be delivered to the previous filter. + SetUnhandledExceptionFilter(handler_->previous_filter_); +#if _MSC_VER >= 1400 // MSVC 2005/8 + _set_invalid_parameter_handler(handler_->previous_iph_); +#endif // _MSC_VER >= 1400 + _set_purecall_handler(handler_->previous_pch_); + } + + ~AutoExceptionHandler() { + // Put things back the way they were before entering this handler. + SetUnhandledExceptionFilter(ExceptionHandler::HandleException); +#if _MSC_VER >= 1400 // MSVC 2005/8 + _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter); +#endif // _MSC_VER >= 1400 + _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall); + + --ExceptionHandler::handler_stack_index_; + LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_); + } + + ExceptionHandler* get_handler() const { return handler_; } + + private: + ExceptionHandler* handler_; +}; + +// static +LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) { + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions. This + // logic will short-circuit before calling WriteMinidumpOnHandlerThread, + // allowing something else to handle the breakpoint without incurring the + // overhead transitioning to and from the handler thread. This behavior + // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions. + DWORD code = exinfo->ExceptionRecord->ExceptionCode; + LONG action; + bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) || + (code == EXCEPTION_SINGLE_STEP); + + bool success = false; + + if (!is_debug_exception || + current_handler->get_handle_debug_exceptions()) { + // If out-of-proc crash handler client is available, we have to use that + // to generate dump and we cannot fall back on in-proc dump generation + // because we never prepared for an in-proc dump generation + + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + exinfo, + NULL); + } else { + success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL); + } + } + + // The handler fully handled the exception. Returning + // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually + // results in the application being terminated. + // + // Note: If the application was launched from within the Cygwin + // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the + // application to be restarted. + if (success) { + action = EXCEPTION_EXECUTE_HANDLER; + } else { + // There was an exception, it was a breakpoint or something else ignored + // above, or it was passed to the handler, which decided not to handle it. + // This could be because the filter callback didn't want it, because + // minidump writing failed for some reason, or because the post-minidump + // callback function indicated failure. Give the previous handler a + // chance to do something with the exception. If there is no previous + // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger + // or native "crashed" dialog to handle the exception. + if (current_handler->previous_filter_) { + action = current_handler->previous_filter_(exinfo); + } else { + action = EXCEPTION_CONTINUE_SEARCH; + } + } + + return action; +} + +#if _MSC_VER >= 1400 // MSVC 2005/8 +// static +void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, + unsigned int line, + uintptr_t reserved) { + // This is an invalid parameter, not an exception. It's safe to play with + // sprintf here. + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + MDRawAssertionInfo assertion; + memset(&assertion, 0, sizeof(assertion)); + _snwprintf_s(reinterpret_cast(assertion.expression), + sizeof(assertion.expression) / sizeof(assertion.expression[0]), + _TRUNCATE, L"%s", expression); + _snwprintf_s(reinterpret_cast(assertion.function), + sizeof(assertion.function) / sizeof(assertion.function[0]), + _TRUNCATE, L"%s", function); + _snwprintf_s(reinterpret_cast(assertion.file), + sizeof(assertion.file) / sizeof(assertion.file[0]), + _TRUNCATE, L"%s", file); + assertion.line = line; + assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER; + + // Make up an exception record for the current thread and CPU context + // to make it possible for the crash processor to classify these + // as do regular crashes, and to make it humane for developers to + // analyze them. + EXCEPTION_RECORD exception_record = {}; + CONTEXT exception_context = {}; + EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; + + ::RtlCaptureContext(&exception_context); + + exception_record.ExceptionCode = STATUS_INVALID_PARAMETER; + + // We store pointers to the the expression and function strings, + // and the line as exception parameters to make them easy to + // access by the developer on the far side. + exception_record.NumberParameters = 3; + exception_record.ExceptionInformation[0] = + reinterpret_cast(&assertion.expression); + exception_record.ExceptionInformation[1] = + reinterpret_cast(&assertion.file); + exception_record.ExceptionInformation[2] = assertion.line; + + bool success = false; + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + &exception_ptrs, + &assertion); + } else { + success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs, + &assertion); + } + + if (!success) { + if (current_handler->previous_iph_) { + // The handler didn't fully handle the exception. Give it to the + // previous invalid parameter handler. + current_handler->previous_iph_(expression, + function, + file, + line, + reserved); + } else { + // If there's no previous handler, pass the exception back in to the + // invalid parameter handler's core. That's the routine that called this + // function, but now, since this function is no longer registered (and in + // fact, no function at all is registered), this will result in the + // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson. + // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes + // more information through. In non-debug builds, it is not available, + // so fall back to using _invalid_parameter_noinfo. See invarg.c in the + // CRT source. +#ifdef _DEBUG + _invalid_parameter(expression, function, file, line, reserved); +#else // _DEBUG + _invalid_parameter_noinfo(); +#endif // _DEBUG + } + } + + // The handler either took care of the invalid parameter problem itself, + // or passed it on to another handler. "Swallow" it by exiting, paralleling + // the behavior of "swallowing" exceptions. + exit(0); +} +#endif // _MSC_VER >= 1400 + +// static +void ExceptionHandler::HandlePureVirtualCall() { + // This is an pure virtual function call, not an exception. It's safe to + // play with sprintf here. + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + MDRawAssertionInfo assertion; + memset(&assertion, 0, sizeof(assertion)); + assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL; + + // Make up an exception record for the current thread and CPU context + // to make it possible for the crash processor to classify these + // as do regular crashes, and to make it humane for developers to + // analyze them. + EXCEPTION_RECORD exception_record = {}; + CONTEXT exception_context = {}; + EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; + + ::RtlCaptureContext(&exception_context); + + exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; + + // We store pointers to the the expression and function strings, + // and the line as exception parameters to make them easy to + // access by the developer on the far side. + exception_record.NumberParameters = 3; + exception_record.ExceptionInformation[0] = + reinterpret_cast(&assertion.expression); + exception_record.ExceptionInformation[1] = + reinterpret_cast(&assertion.file); + exception_record.ExceptionInformation[2] = assertion.line; + + bool success = false; + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + &exception_ptrs, + &assertion); + } else { + success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs, + &assertion); + } + + if (!success) { + if (current_handler->previous_pch_) { + // The handler didn't fully handle the exception. Give it to the + // previous purecall handler. + current_handler->previous_pch_(); + } else { + // If there's no previous handler, return and let _purecall handle it. + // This will just put up an assertion dialog. + return; + } + } + + // The handler either took care of the invalid parameter problem itself, + // or passed it on to another handler. "Swallow" it by exiting, paralleling + // the behavior of "swallowing" exceptions. + exit(0); +} + +bool ExceptionHandler::WriteMinidumpOnHandlerThread( + EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { + EnterCriticalSection(&handler_critical_section_); + + // There isn't much we can do if the handler thread + // was not successfully created. + if (handler_thread_ == NULL) { + LeaveCriticalSection(&handler_critical_section_); + return false; + } + + // The handler thread should only be created when the semaphores are valid. + assert(handler_start_semaphore_ != NULL); + assert(handler_finish_semaphore_ != NULL); + + // Set up data to be passed in to the handler thread. + requesting_thread_id_ = GetCurrentThreadId(); + exception_info_ = exinfo; + assertion_ = assertion; + + // This causes the handler thread to call WriteMinidumpWithException. + ReleaseSemaphore(handler_start_semaphore_, 1, NULL); + + // Wait until WriteMinidumpWithException is done and collect its return value. + WaitForSingleObject(handler_finish_semaphore_, INFINITE); + bool status = handler_return_value_; + + // Clean up. + requesting_thread_id_ = 0; + exception_info_ = NULL; + assertion_ = NULL; + + LeaveCriticalSection(&handler_critical_section_); + + return status; +} + +bool ExceptionHandler::WriteMinidump() { + // Make up an exception record for the current thread and CPU context + // to make it possible for the crash processor to classify these + // as do regular crashes, and to make it humane for developers to + // analyze them. + EXCEPTION_RECORD exception_record = {}; + CONTEXT exception_context = {}; + EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; + + ::RtlCaptureContext(&exception_context); + exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; + + return WriteMinidumpForException(&exception_ptrs); +} + +bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) { + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (IsOutOfProcess()) { + return WriteMinidumpWithException(GetCurrentThreadId(), + exinfo, + NULL); + } + + bool success = WriteMinidumpOnHandlerThread(exinfo, NULL); + UpdateNextID(); + return success; +} + +// static +bool ExceptionHandler::WriteMinidump(const wstring &dump_path, + MinidumpCallback callback, + void* callback_context) { + ExceptionHandler handler(dump_path, NULL, callback, callback_context, + HANDLER_NONE); + return handler.WriteMinidump(); +} + +// static +bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, + DWORD child_blamed_thread, + const wstring& dump_path, + MinidumpCallback callback, + void* callback_context) { + EXCEPTION_RECORD ex; + CONTEXT ctx; + EXCEPTION_POINTERS exinfo = { NULL, NULL }; + DWORD last_suspend_count = kFailedToSuspendThread; + HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT | + THREAD_QUERY_INFORMATION | + THREAD_SUSPEND_RESUME, + FALSE, + child_blamed_thread); + // This thread may have died already, so not opening the handle is a + // non-fatal error. + if (child_thread_handle != NULL) { + last_suspend_count = SuspendThread(child_thread_handle); + if (last_suspend_count != kFailedToSuspendThread) { + ctx.ContextFlags = CONTEXT_ALL; + if (GetThreadContext(child_thread_handle, &ctx)) { + memset(&ex, 0, sizeof(ex)); + ex.ExceptionCode = EXCEPTION_BREAKPOINT; +#if defined(_M_IX86) + ex.ExceptionAddress = reinterpret_cast(ctx.Eip); +#elif defined(_M_X64) + ex.ExceptionAddress = reinterpret_cast(ctx.Rip); +#endif + exinfo.ExceptionRecord = &ex; + exinfo.ContextRecord = &ctx; + } + } + } + + ExceptionHandler handler(dump_path, NULL, callback, callback_context, + HANDLER_NONE); + bool success = handler.WriteMinidumpWithExceptionForProcess( + child_blamed_thread, + exinfo.ExceptionRecord ? &exinfo : NULL, + NULL, child, false); + + if (last_suspend_count != kFailedToSuspendThread) { + ResumeThread(child_thread_handle); + } + + CloseHandle(child_thread_handle); + + if (callback) { + success = callback(handler.dump_path_c_, handler.next_minidump_id_c_, + callback_context, NULL, NULL, success); + } + + return success; +} + +bool ExceptionHandler::WriteMinidumpWithException( + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion) { + // Give user code a chance to approve or prevent writing a minidump. If the + // filter returns false, don't handle the exception at all. If this method + // was called as a result of an exception, returning false will cause + // HandleException to call any previous handler or return + // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear + // as though this handler were not present at all. + if (filter_ && !filter_(callback_context_, exinfo, assertion)) { + return false; + } + + bool success = false; + if (IsOutOfProcess()) { + if(app_memory_info_.size() > 1) + crash_generation_client_->SetAppMemory(&app_memory_info_[1], (ULONG)(app_memory_info_.size()-1)); + + success = crash_generation_client_->RequestDump(exinfo, assertion); + } else { + success = WriteMinidumpWithExceptionForProcess(requesting_thread_id, + exinfo, + assertion, + GetCurrentProcess(), + true); + } + + if (callback_) { + // TODO(munjal): In case of out-of-process dump generation, both + // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process + // scenario, the server process ends up creating the dump path and dump + // id so they are not known to the client. + success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_, + exinfo, assertion, success); + } + + return success; +} + +// static +BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback( + PVOID context, + const PMINIDUMP_CALLBACK_INPUT callback_input, + PMINIDUMP_CALLBACK_OUTPUT callback_output) { + switch (callback_input->CallbackType) { + case MemoryCallback: { + MinidumpCallbackContext* callback_context = + reinterpret_cast(context); + if (callback_context->iter == callback_context->end) + return FALSE; + + // Include the specified memory region. + callback_output->MemoryBase = callback_context->iter->ptr; + callback_output->MemorySize = callback_context->iter->length; + callback_context->iter++; + return TRUE; + } + + // Include all modules. + case IncludeModuleCallback: + case ModuleCallback: + return TRUE; + + // Include all threads. + case IncludeThreadCallback: + case ThreadCallback: + return TRUE; + + // Stop receiving cancel callbacks. + case CancelCallback: + callback_output->CheckCancel = FALSE; + callback_output->Cancel = FALSE; + return TRUE; + } + // Ignore other callback types. + return FALSE; +} + +bool ExceptionHandler::WriteMinidumpWithExceptionForProcess( + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + HANDLE process, + bool write_requester_stream) { + bool success = false; + if (minidump_write_dump_) { + HANDLE dump_file = CreateFile(next_minidump_path_c_, + GENERIC_WRITE, + 0, // no sharing + NULL, + CREATE_NEW, // fail if exists + FILE_ATTRIBUTE_NORMAL, + NULL); + if (dump_file != INVALID_HANDLE_VALUE) { + MINIDUMP_EXCEPTION_INFORMATION except_info; + except_info.ThreadId = requesting_thread_id; + except_info.ExceptionPointers = exinfo; + except_info.ClientPointers = FALSE; + + // Leave room in user_stream_array for possible breakpad and + // assertion info streams. + MINIDUMP_USER_STREAM user_stream_array[2]; + MINIDUMP_USER_STREAM_INFORMATION user_streams; + user_streams.UserStreamCount = 0; + user_streams.UserStreamArray = user_stream_array; + + if (write_requester_stream) { + // Add an MDRawBreakpadInfo stream to the minidump, to provide + // additional information about the exception handler to the Breakpad + // processor. The information will help the processor determine which + // threads are relevant. The Breakpad processor does not require this + // information but can function better with Breakpad-generated dumps + // when it is present. The native debugger is not harmed by the + // presence of this information. + MDRawBreakpadInfo breakpad_info; + breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; + breakpad_info.dump_thread_id = GetCurrentThreadId(); + breakpad_info.requesting_thread_id = requesting_thread_id; + + int index = user_streams.UserStreamCount; + user_stream_array[index].Type = MD_BREAKPAD_INFO_STREAM; + user_stream_array[index].BufferSize = sizeof(breakpad_info); + user_stream_array[index].Buffer = &breakpad_info; + ++user_streams.UserStreamCount; + } + + if (assertion) { + int index = user_streams.UserStreamCount; + user_stream_array[index].Type = MD_ASSERTION_INFO_STREAM; + user_stream_array[index].BufferSize = sizeof(MDRawAssertionInfo); + user_stream_array[index].Buffer = assertion; + ++user_streams.UserStreamCount; + } + + // Older versions of DbgHelp.dll don't correctly put the memory around + // the faulting instruction pointer into the minidump. This + // callback will ensure that it gets included. + if (exinfo) { + // Find a memory region of 256 bytes centered on the + // faulting instruction pointer. + const ULONG64 instruction_pointer = +#if defined(_M_IX86) + exinfo->ContextRecord->Eip; +#elif defined(_M_AMD64) + exinfo->ContextRecord->Rip; +#else +#error Unsupported platform +#endif + + MEMORY_BASIC_INFORMATION info; + if (VirtualQueryEx(process, + reinterpret_cast(instruction_pointer), + &info, + sizeof(MEMORY_BASIC_INFORMATION)) != 0 && + info.State == MEM_COMMIT) { + // Attempt to get 128 bytes before and after the instruction + // pointer, but settle for whatever's available up to the + // boundaries of the memory region. + const ULONG64 kIPMemorySize = 256; + ULONG64 base = + (std::max)(reinterpret_cast(info.BaseAddress), + instruction_pointer - (kIPMemorySize / 2)); + ULONG64 end_of_range = + (std::min)(instruction_pointer + (kIPMemorySize / 2), + reinterpret_cast(info.BaseAddress) + + info.RegionSize); + ULONG size = static_cast(end_of_range - base); + + AppMemory& elt = app_memory_info_.front(); + elt.ptr = base; + elt.length = size; + } + } + + MinidumpCallbackContext context; + context.iter = app_memory_info_.begin(); + context.end = app_memory_info_.end(); + + // Skip the reserved element if there was no instruction memory + if (context.iter->ptr == 0) { + context.iter++; + } + + MINIDUMP_CALLBACK_INFORMATION callback; + callback.CallbackRoutine = MinidumpWriteDumpCallback; + callback.CallbackParam = reinterpret_cast(&context); + + // The explicit comparison to TRUE avoids a warning (C4800). + success = (minidump_write_dump_(process, + GetProcessId(process), + dump_file, + dump_type_, + exinfo ? &except_info : NULL, + &user_streams, + &callback) == TRUE); + + CloseHandle(dump_file); + } + } + + return success; +} + +void ExceptionHandler::UpdateNextID() { + assert(uuid_create_); + UUID id = {0}; + if (uuid_create_) { + uuid_create_(&id); + } + next_minidump_id_ = GUIDString::GUIDToWString(&id); + next_minidump_id_c_ = next_minidump_id_.c_str(); + + wchar_t minidump_path[MAX_PATH]; + swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp", + dump_path_c_, next_minidump_id_c_); + + // remove when VC++7.1 is no longer supported + minidump_path[MAX_PATH - 1] = L'\0'; + + next_minidump_path_ = minidump_path; + next_minidump_path_c_ = next_minidump_path_.c_str(); +} + +void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { + AppMemoryList::iterator iter = + std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr); + if (iter != app_memory_info_.end()) { + // Don't allow registering the same pointer twice. + return; + } + + AppMemory app_memory; + app_memory.ptr = reinterpret_cast(ptr); + app_memory.length = static_cast(length); + app_memory_info_.push_back(app_memory); +} + +void ExceptionHandler::UnregisterAppMemory(void* ptr) { + AppMemoryList::iterator iter = + std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr); + if (iter != app_memory_info_.end()) { + app_memory_info_.erase(iter); + } +} + +} // namespace google_breakpad diff --git a/breakpad/client/windows/handler/exception_handler.h b/breakpad/client/windows/handler/exception_handler.h new file mode 100644 index 0000000000..6ca40d4f59 --- /dev/null +++ b/breakpad/client/windows/handler/exception_handler.h @@ -0,0 +1,494 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ExceptionHandler can write a minidump file when an exception occurs, +// or when WriteMinidump() is called explicitly by your program. +// +// To have the exception handler write minidumps when an uncaught exception +// (crash) occurs, you should create an instance early in the execution +// of your program, and keep it around for the entire time you want to +// have crash handling active (typically, until shutdown). +// +// If you want to write minidumps without installing the exception handler, +// you can create an ExceptionHandler with install_handler set to false, +// then call WriteMinidump. You can also use this technique if you want to +// use different minidump callbacks for different call sites. +// +// In either case, a callback function is called when a minidump is written, +// which receives the unqiue id of the minidump. The caller can use this +// id to collect and write additional application state, and to launch an +// external crash-reporting application. +// +// It is important that creation and destruction of ExceptionHandler objects +// be nested cleanly, when using install_handler = true. +// Avoid the following pattern: +// ExceptionHandler *e = new ExceptionHandler(...); +// ExceptionHandler *f = new ExceptionHandler(...); +// delete e; +// This will put the exception filter stack into an inconsistent state. + +#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ +#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ + +#include +#include +#include +#include + +#pragma warning(push) +// Disable exception handler warnings. +#pragma warning(disable:4530) + +#include +#include +#include + +#include "client/windows/common/ipc_protocol.h" +#include "client/windows/crash_generation/crash_generation_client.h" +#include "common/scoped_ptr.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +using std::vector; +using std::wstring; + +class ExceptionHandler { + public: + // A callback function to run before Breakpad performs any substantial + // processing of an exception. A FilterCallback is called before writing + // a minidump. context is the parameter supplied by the user as + // callback_context when the handler was created. exinfo points to the + // exception record, if any; assertion points to assertion information, + // if any. + // + // If a FilterCallback returns true, Breakpad will continue processing, + // attempting to write a minidump. If a FilterCallback returns false, + // Breakpad will immediately report the exception as unhandled without + // writing a minidump, allowing another handler the opportunity to handle it. + typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion); + + // A callback function to run after the minidump has been written. + // minidump_id is a unique id for the dump, so the minidump + // file is \.dmp. context is the parameter supplied + // by the user as callback_context when the handler was created. exinfo + // points to the exception record, or NULL if no exception occurred. + // succeeded indicates whether a minidump file was successfully written. + // assertion points to information about an assertion if the handler was + // invoked by an assertion. + // + // If an exception occurred and the callback returns true, Breakpad will treat + // the exception as fully-handled, suppressing any other handlers from being + // notified of the exception. If the callback returns false, Breakpad will + // treat the exception as unhandled, and allow another handler to handle it. + // If there are no other handlers, Breakpad will report the exception to the + // system as unhandled, allowing a debugger or native crash dialog the + // opportunity to handle the exception. Most callback implementations + // should normally return the value of |succeeded|, or when they wish to + // not report an exception of handled, false. Callbacks will rarely want to + // return true directly (unless |succeeded| is true). + // + // For out-of-process dump generation, dump path and minidump ID will always + // be NULL. In case of out-of-process dump generation, the dump path and + // minidump id are controlled by the server process and are not communicated + // back to the crashing process. + typedef bool (*MinidumpCallback)(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded); + + // HandlerType specifies which types of handlers should be installed, if + // any. Use HANDLER_NONE for an ExceptionHandler that remains idle, + // without catching any failures on its own. This type of handler may + // still be triggered by calling WriteMinidump. Otherwise, use a + // combination of the other HANDLER_ values, or HANDLER_ALL to install + // all handlers. + enum HandlerType { + HANDLER_NONE = 0, + HANDLER_EXCEPTION = 1 << 0, // SetUnhandledExceptionFilter + HANDLER_INVALID_PARAMETER = 1 << 1, // _set_invalid_parameter_handler + HANDLER_PURECALL = 1 << 2, // _set_purecall_handler + HANDLER_ALL = HANDLER_EXCEPTION | + HANDLER_INVALID_PARAMETER | + HANDLER_PURECALL + }; + + // Creates a new ExceptionHandler instance to handle writing minidumps. + // Before writing a minidump, the optional filter callback will be called. + // Its return value determines whether or not Breakpad should write a + // minidump. Minidump files will be written to dump_path, and the optional + // callback is called after writing the dump file, as described above. + // handler_types specifies the types of handlers that should be installed. + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types); + + // Creates a new ExceptionHandler instance that can attempt to perform + // out-of-process dump generation if pipe_name is not NULL. If pipe_name is + // NULL, or if out-of-process dump generation registration step fails, + // in-process dump generation will be used. This also allows specifying + // the dump type to generate. + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name, + const CustomClientInfo* custom_info); + + // As above, creates a new ExceptionHandler instance to perform + // out-of-process dump generation if the given pipe_handle is not NULL. + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + HANDLE pipe_handle, + const CustomClientInfo* custom_info); + + // ExceptionHandler that ENSURES out-of-process dump generation. Expects a + // crash generation client that is already registered with a crash generation + // server. Takes ownership of the passed-in crash_generation_client. + // + // Usage example: + // crash_generation_client = new CrashGenerationClient(..); + // if (crash_generation_client->Register()) { + // // Registration with the crash generation server succeeded. + // // Out-of-process dump generation is guaranteed. + // g_handler = new ExceptionHandler(.., crash_generation_client, ..); + // return true; + // } + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + CrashGenerationClient* crash_generation_client); + + ~ExceptionHandler(); + + // Get and set the minidump path. + wstring dump_path() const { return dump_path_; } + void set_dump_path(const wstring &dump_path) { + dump_path_ = dump_path; + dump_path_c_ = dump_path_.c_str(); + UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. + } + + // Requests that a previously reported crash be uploaded. + bool RequestUpload(DWORD crash_id); + + // Writes a minidump immediately. This can be used to capture the + // execution state independently of a crash. Returns true on success. + bool WriteMinidump(); + + // Writes a minidump immediately, with the user-supplied exception + // information. + bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo); + + // Convenience form of WriteMinidump which does not require an + // ExceptionHandler instance. + static bool WriteMinidump(const wstring &dump_path, + MinidumpCallback callback, void* callback_context); + + // Write a minidump of |child| immediately. This can be used to + // capture the execution state of |child| independently of a crash. + // Pass a meaningful |child_blamed_thread| to make that thread in + // the child process the one from which a crash signature is + // extracted. + static bool WriteMinidumpForChild(HANDLE child, + DWORD child_blamed_thread, + const wstring& dump_path, + MinidumpCallback callback, + void* callback_context); + + // Get the thread ID of the thread requesting the dump (either the exception + // thread or any other thread that called WriteMinidump directly). This + // may be useful if you want to include additional thread state in your + // dumps. + DWORD get_requesting_thread_id() const { return requesting_thread_id_; } + + // Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP. + bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; } + void set_handle_debug_exceptions(bool handle_debug_exceptions) { + handle_debug_exceptions_ = handle_debug_exceptions; + } + + // Returns whether out-of-process dump generation is used or not. + bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } + + // Calling RegisterAppMemory(p, len) causes len bytes starting + // at address p to be copied to the minidump when a crash happens. + void RegisterAppMemory(void* ptr, size_t length); + void UnregisterAppMemory(void* ptr); + const AppMemoryList &QueryRegisteredAppMemory() { return app_memory_info_; } + + private: + friend class AutoExceptionHandler; + + // Initializes the instance with given values. + void Initialize(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name, + HANDLE pipe_handle, + CrashGenerationClient* crash_generation_client, + const CustomClientInfo* custom_info); + + // Function pointer type for MiniDumpWriteDump, which is looked up + // dynamically. + typedef BOOL (WINAPI *MiniDumpWriteDump_type)( + HANDLE hProcess, + DWORD dwPid, + HANDLE hFile, + MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); + + // Function pointer type for UuidCreate, which is looked up dynamically. + typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid); + + // Runs the main loop for the exception handler thread. + static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter); + + // Called on the exception thread when an unhandled exception occurs. + // Signals the exception handler thread to handle the exception. + static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo); + +#if _MSC_VER >= 1400 // MSVC 2005/8 + // This function will be called by some CRT functions when they detect + // that they were passed an invalid parameter. Note that in _DEBUG builds, + // the CRT may display an assertion dialog before calling this function, + // and the function will not be called unless the assertion dialog is + // dismissed by clicking "Ignore." + static void HandleInvalidParameter(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, + unsigned int line, + uintptr_t reserved); +#endif // _MSC_VER >= 1400 + + // This function will be called by the CRT when a pure virtual + // function is called. + static void HandlePureVirtualCall(); + + // This is called on the exception thread or on another thread that + // the user wishes to produce a dump from. It calls + // WriteMinidumpWithException on the handler thread, avoiding stack + // overflows and inconsistent dumps due to writing the dump from + // the exception thread. If the dump is requested as a result of an + // exception, exinfo contains exception information, otherwise, it + // is NULL. If the dump is requested as a result of an assertion + // (such as an invalid parameter being passed to a CRT function), + // assertion contains data about the assertion, otherwise, it is NULL. + bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion); + + // This function is called on the handler thread. It calls into + // WriteMinidumpWithExceptionForProcess() with a handle to the + // current process. requesting_thread_id is the ID of the thread + // that requested the dump. If the dump is requested as a result of + // an exception, exinfo contains exception information, otherwise, + // it is NULL. + bool WriteMinidumpWithException(DWORD requesting_thread_id, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion); + + // This function is used as a callback when calling MinidumpWriteDump, + // in order to add additional memory regions to the dump. + static BOOL CALLBACK MinidumpWriteDumpCallback( + PVOID context, + const PMINIDUMP_CALLBACK_INPUT callback_input, + PMINIDUMP_CALLBACK_OUTPUT callback_output); + + // This function does the actual writing of a minidump. It is + // called on the handler thread. requesting_thread_id is the ID of + // the thread that requested the dump, if that information is + // meaningful. If the dump is requested as a result of an + // exception, exinfo contains exception information, otherwise, it + // is NULL. process is the one that will be dumped. If + // requesting_thread_id is meaningful and should be added to the + // minidump, write_requester_stream is |true|. + bool WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + HANDLE process, + bool write_requester_stream); + + // Generates a new ID and stores it in next_minidump_id_, and stores the + // path of the next minidump to be written in next_minidump_path_. + void UpdateNextID(); + + FilterCallback filter_; + MinidumpCallback callback_; + void* callback_context_; + + scoped_ptr crash_generation_client_; + + // The directory in which a minidump will be written, set by the dump_path + // argument to the constructor, or set_dump_path. + wstring dump_path_; + + // The basename of the next minidump to be written, without the extension. + wstring next_minidump_id_; + + // The full pathname of the next minidump to be written, including the file + // extension. + wstring next_minidump_path_; + + // Pointers to C-string representations of the above. These are set when + // the above wstring versions are set in order to avoid calling c_str during + // an exception, as c_str may attempt to allocate heap memory. These + // pointers are not owned by the ExceptionHandler object, but their lifetimes + // should be equivalent to the lifetimes of the associated wstring, provided + // that the wstrings are not altered. + const wchar_t* dump_path_c_; + const wchar_t* next_minidump_id_c_; + const wchar_t* next_minidump_path_c_; + + HMODULE dbghelp_module_; + MiniDumpWriteDump_type minidump_write_dump_; + MINIDUMP_TYPE dump_type_; + + HMODULE rpcrt4_module_; + UuidCreate_type uuid_create_; + + // Tracks the handler types that were installed according to the + // handler_types constructor argument. + int handler_types_; + + // When installed_handler_ is true, previous_filter_ is the unhandled + // exception filter that was set prior to installing ExceptionHandler as + // the unhandled exception filter and pointing it to |this|. NULL indicates + // that there is no previous unhandled exception filter. + LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_; + +#if _MSC_VER >= 1400 // MSVC 2005/8 + // Beginning in VC 8, the CRT provides an invalid parameter handler that will + // be called when some CRT functions are passed invalid parameters. In + // earlier CRTs, the same conditions would cause unexpected behavior or + // crashes. + _invalid_parameter_handler previous_iph_; +#endif // _MSC_VER >= 1400 + + // The CRT allows you to override the default handler for pure + // virtual function calls. + _purecall_handler previous_pch_; + + // The exception handler thread. + HANDLE handler_thread_; + + // True if the exception handler is being destroyed. + // Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars. + // It has release semantics on write and acquire semantics on reads. + // See the msdn documentation. + volatile bool is_shutdown_; + + // The critical section enforcing the requirement that only one exception be + // handled by a handler at a time. + CRITICAL_SECTION handler_critical_section_; + + // Semaphores used to move exception handling between the exception thread + // and the handler thread. handler_start_semaphore_ is signalled by the + // exception thread to wake up the handler thread when an exception occurs. + // handler_finish_semaphore_ is signalled by the handler thread to wake up + // the exception thread when handling is complete. + HANDLE handler_start_semaphore_; + HANDLE handler_finish_semaphore_; + + // The next 2 fields contain data passed from the requesting thread to + // the handler thread. + + // The thread ID of the thread requesting the dump (either the exception + // thread or any other thread that called WriteMinidump directly). + DWORD requesting_thread_id_; + + // The exception info passed to the exception handler on the exception + // thread, if an exception occurred. NULL for user-requested dumps. + EXCEPTION_POINTERS* exception_info_; + + // If the handler is invoked due to an assertion, this will contain a + // pointer to the assertion information. It is NULL at other times. + MDRawAssertionInfo* assertion_; + + // The return value of the handler, passed from the handler thread back to + // the requesting thread. + bool handler_return_value_; + + // If true, the handler will intercept EXCEPTION_BREAKPOINT and + // EXCEPTION_SINGLE_STEP exceptions. Leave this false (the default) + // to not interfere with debuggers. + bool handle_debug_exceptions_; + + // Callers can request additional memory regions to be included in + // the dump. + AppMemoryList app_memory_info_; + + // A stack of ExceptionHandler objects that have installed unhandled + // exception filters. This vector is used by HandleException to determine + // which ExceptionHandler object to route an exception to. When an + // ExceptionHandler is created with install_handler true, it will append + // itself to this list. + static vector* handler_stack_; + + // The index of the ExceptionHandler in handler_stack_ that will handle the + // next exception. Note that 0 means the last entry in handler_stack_, 1 + // means the next-to-last entry, and so on. This is used by HandleException + // to support multiple stacked Breakpad handlers. + static LONG handler_stack_index_; + + // handler_stack_critical_section_ guards operations on handler_stack_ and + // handler_stack_index_. The critical section is initialized by the + // first instance of the class and destroyed by the last instance of it. + static CRITICAL_SECTION handler_stack_critical_section_; + + // The number of instances of this class. + static volatile LONG instance_count_; + + // disallow copy ctor and operator= + explicit ExceptionHandler(const ExceptionHandler &); + void operator=(const ExceptionHandler &); +}; + +} // namespace google_breakpad + +#pragma warning(pop) + +#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ diff --git a/breakpad/client/windows/handler/exception_handler.sln b/breakpad/client/windows/handler/exception_handler.sln new file mode 100644 index 0000000000..5ab6a3a3c7 --- /dev/null +++ b/breakpad/client/windows/handler/exception_handler.sln @@ -0,0 +1,67 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "(crash_generation)", "..\..\..\..\crash_generation", "{71054F76-E083-ED71-B3F9-3E9B872F3E9E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "(handler)", "..\..\..\..\handler", "{07BF0989-2B77-D3C5-75FC-813F97B41E10}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "..\common.vcxproj", "{EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_server", "..\crash_generation\crash_generation_server.vcxproj", "{7893E300-3ED0-7F4C-158F-67EA63934C57}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler", "exception_handler.vcxproj", "{B7399F39-300F-450E-F471-9490F959D2A7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|x64 = Release|x64 + Purify|Win32 = Purify|Win32 + Purify|x64 = Purify|x64 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|Win32.ActiveCfg = Debug|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|Win32.Build.0 = Debug|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|x64.ActiveCfg = Release|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|x64.Build.0 = Release|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|Win32.ActiveCfg = Purify|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|Win32.Build.0 = Purify|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|x64.ActiveCfg = Purify|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Purify|x64.Build.0 = Purify|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|x64.ActiveCfg = Debug|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Debug|x64.Build.0 = Debug|x64 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|Win32.ActiveCfg = Release|Win32 + {7893E300-3ED0-7F4C-158F-67EA63934C57}.Release|Win32.Build.0 = Release|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|Win32.ActiveCfg = Debug|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|Win32.Build.0 = Debug|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|x64.ActiveCfg = Release|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|x64.Build.0 = Release|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|Win32.ActiveCfg = Purify|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|Win32.Build.0 = Purify|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|x64.ActiveCfg = Purify|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Purify|x64.Build.0 = Purify|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|x64.ActiveCfg = Debug|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Debug|x64.Build.0 = Debug|x64 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|Win32.ActiveCfg = Release|Win32 + {B7399F39-300F-450E-F471-9490F959D2A7}.Release|Win32.Build.0 = Release|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|Win32.Build.0 = Debug|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|x64.ActiveCfg = Release|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|x64.Build.0 = Release|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|Win32.ActiveCfg = Purify|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|Win32.Build.0 = Purify|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|x64.ActiveCfg = Purify|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Purify|x64.Build.0 = Purify|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|x64.ActiveCfg = Debug|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Debug|x64.Build.0 = Debug|x64 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|Win32.ActiveCfg = Release|Win32 + {EA1242CF-BB42-B1AC-9B6A-A508D96D1CB7}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {7893E300-3ED0-7F4C-158F-67EA63934C57} = {71054F76-E083-ED71-B3F9-3E9B872F3E9E} + {B7399F39-300F-450E-F471-9490F959D2A7} = {07BF0989-2B77-D3C5-75FC-813F97B41E10} + EndGlobalSection +EndGlobal diff --git a/breakpad/client/windows/handler/exception_handler.vcxproj b/breakpad/client/windows/handler/exception_handler.vcxproj new file mode 100644 index 0000000000..455efffc6a --- /dev/null +++ b/breakpad/client/windows/handler/exception_handler.vcxproj @@ -0,0 +1,380 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Purify + Win32 + + + Purify + x64 + + + Release + Win32 + + + Release + x64 + + + + {B7399F39-300F-450E-F471-9490F959D2A7} + Win32Proj + exception_handler + + + + Unicode + StaticLibrary + + + + + + + + + $(ExecutablePath);$(MSBuildProjectDirectory)\..\..\..\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\..\..\third_party\python_26\ + $(SolutionDir)$(Configuration)\$(Platform)\ + $(OutDir)obj\$(ProjectName)\ + false + false + false + false + true + true + $(ProjectName) + $(OutDir)\$(ProjectName).lib + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + false + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + false + false + true + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + true + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + true + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib32\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib32\ + + + + + ..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + + + 4100;4127;4396;4503;4512;4819;4995;4800;%(DisableSpecificWarnings) + Sync + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreadedDLL + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)\$(ProjectName).lib + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies) + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + mkdir $(SolutionDir)\lib64\ 2> nul +copy $(TargetPath) $(SolutionDir)\lib64\ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/breakpad/common/basictypes.h b/breakpad/common/basictypes.h new file mode 100644 index 0000000000..84668b79d9 --- /dev/null +++ b/breakpad/common/basictypes.h @@ -0,0 +1,41 @@ +// Copyright (c) 2011 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_BASICTYPES_H_ +#define COMMON_BASICTYPES_H_ + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif // DISALLOW_COPY_AND_ASSIGN + +#endif // COMMON_BASICTYPES_H_ diff --git a/breakpad/common/byte_cursor.h b/breakpad/common/byte_cursor.h new file mode 100644 index 0000000000..accd54e0a4 --- /dev/null +++ b/breakpad/common/byte_cursor.h @@ -0,0 +1,265 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// byte_cursor.h: Classes for parsing values from a buffer of bytes. +// The ByteCursor class provides a convenient interface for reading +// fixed-size integers of arbitrary endianness, being thorough about +// checking for buffer overruns. + +#ifndef COMMON_BYTE_CURSOR_H_ +#define COMMON_BYTE_CURSOR_H_ + +#include +#include +#include +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A buffer holding a series of bytes. +struct ByteBuffer { + ByteBuffer() : start(0), end(0) { } + ByteBuffer(const uint8_t *set_start, size_t set_size) + : start(set_start), end(set_start + set_size) { } + ~ByteBuffer() { }; + + // Equality operators. Useful in unit tests, and when we're using + // ByteBuffers to refer to regions of a larger buffer. + bool operator==(const ByteBuffer &that) const { + return start == that.start && end == that.end; + } + bool operator!=(const ByteBuffer &that) const { + return start != that.start || end != that.end; + } + + // Not C++ style guide compliant, but this definitely belongs here. + size_t Size() const { + assert(start <= end); + return end - start; + } + + const uint8_t *start, *end; +}; + +// A cursor pointing into a ByteBuffer that can parse numbers of various +// widths and representations, strings, and data blocks, advancing through +// the buffer as it goes. All ByteCursor operations check that accesses +// haven't gone beyond the end of the enclosing ByteBuffer. +class ByteCursor { + public: + // Create a cursor reading bytes from the start of BUFFER. By default, the + // cursor reads multi-byte values in little-endian form. + ByteCursor(const ByteBuffer *buffer, bool big_endian = false) + : buffer_(buffer), here_(buffer->start), + big_endian_(big_endian), complete_(true) { } + + // Accessor and setter for this cursor's endianness flag. + bool big_endian() const { return big_endian_; } + void set_big_endian(bool big_endian) { big_endian_ = big_endian; } + + // Accessor and setter for this cursor's current position. The setter + // returns a reference to this cursor. + const uint8_t *here() const { return here_; } + ByteCursor &set_here(const uint8_t *here) { + assert(buffer_->start <= here && here <= buffer_->end); + here_ = here; + return *this; + } + + // Return the number of bytes available to read at the cursor. + size_t Available() const { return size_t(buffer_->end - here_); } + + // Return true if this cursor is at the end of its buffer. + bool AtEnd() const { return Available() == 0; } + + // When used as a boolean value this cursor converts to true if all + // prior reads have been completed, or false if we ran off the end + // of the buffer. + operator bool() const { return complete_; } + + // Read a SIZE-byte integer at this cursor, signed if IS_SIGNED is true, + // unsigned otherwise, using the cursor's established endianness, and set + // *RESULT to the number. If we read off the end of our buffer, clear + // this cursor's complete_ flag, and store a dummy value in *RESULT. + // Return a reference to this cursor. + template + ByteCursor &Read(size_t size, bool is_signed, T *result) { + if (CheckAvailable(size)) { + T v = 0; + if (big_endian_) { + for (size_t i = 0; i < size; i++) + v = (v << 8) + here_[i]; + } else { + // This loop condition looks weird, but size_t is unsigned, so + // decrementing i after it is zero yields the largest size_t value. + for (size_t i = size - 1; i < size; i--) + v = (v << 8) + here_[i]; + } + if (is_signed && size < sizeof(T)) { + size_t sign_bit = (T)1 << (size * 8 - 1); + v = (v ^ sign_bit) - sign_bit; + } + here_ += size; + *result = v; + } else { + *result = (T) 0xdeadbeef; + } + return *this; + } + + // Read an integer, using the cursor's established endianness and + // *RESULT's size and signedness, and set *RESULT to the number. If we + // read off the end of our buffer, clear this cursor's complete_ flag. + // Return a reference to this cursor. + template + ByteCursor &operator>>(T &result) { + bool T_is_signed = (T)-1 < 0; + return Read(sizeof(T), T_is_signed, &result); + } + + // Copy the SIZE bytes at the cursor to BUFFER, and advance this + // cursor to the end of them. If we read off the end of our buffer, + // clear this cursor's complete_ flag, and set *POINTER to NULL. + // Return a reference to this cursor. + ByteCursor &Read(uint8_t *buffer, size_t size) { + if (CheckAvailable(size)) { + memcpy(buffer, here_, size); + here_ += size; + } + return *this; + } + + // Set STR to a copy of the '\0'-terminated string at the cursor. If the + // byte buffer does not contain a terminating zero, clear this cursor's + // complete_ flag, and set STR to the empty string. Return a reference to + // this cursor. + ByteCursor &CString(string *str) { + const uint8_t *end + = static_cast(memchr(here_, '\0', Available())); + if (end) { + str->assign(reinterpret_cast(here_), end - here_); + here_ = end + 1; + } else { + str->clear(); + here_ = buffer_->end; + complete_ = false; + } + return *this; + } + + // Like CString(STR), but extract the string from a fixed-width buffer + // LIMIT bytes long, which may or may not contain a terminating '\0' + // byte. Specifically: + // + // - If there are not LIMIT bytes available at the cursor, clear the + // cursor's complete_ flag and set STR to the empty string. + // + // - Otherwise, if the LIMIT bytes at the cursor contain any '\0' + // characters, set *STR to a copy of the bytes before the first '\0', + // and advance the cursor by LIMIT bytes. + // + // - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the + // cursor by LIMIT bytes. + ByteCursor &CString(string *str, size_t limit) { + if (CheckAvailable(limit)) { + const uint8_t *end + = static_cast(memchr(here_, '\0', limit)); + if (end) + str->assign(reinterpret_cast(here_), end - here_); + else + str->assign(reinterpret_cast(here_), limit); + here_ += limit; + } else { + str->clear(); + } + return *this; + } + + // Set *POINTER to point to the SIZE bytes at the cursor, and advance + // this cursor to the end of them. If SIZE is omitted, don't move the + // cursor. If we read off the end of our buffer, clear this cursor's + // complete_ flag, and set *POINTER to NULL. Return a reference to this + // cursor. + ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) { + if (CheckAvailable(size)) { + *pointer = here_; + here_ += size; + } else { + *pointer = NULL; + } + return *this; + } + + // Skip SIZE bytes at the cursor. If doing so would advance us off + // the end of our buffer, clear this cursor's complete_ flag, and + // set *POINTER to NULL. Return a reference to this cursor. + ByteCursor &Skip(size_t size) { + if (CheckAvailable(size)) + here_ += size; + return *this; + } + + private: + // If there are at least SIZE bytes available to read from the buffer, + // return true. Otherwise, set here_ to the end of the buffer, set + // complete_ to false, and return false. + bool CheckAvailable(size_t size) { + if (Available() >= size) { + return true; + } else { + here_ = buffer_->end; + complete_ = false; + return false; + } + } + + // The buffer we're reading bytes from. + const ByteBuffer *buffer_; + + // The next byte within buffer_ that we'll read. + const uint8_t *here_; + + // True if we should read numbers in big-endian form; false if we + // should read in little-endian form. + bool big_endian_; + + // True if we've been able to read all we've been asked to. + bool complete_; +}; + +} // namespace google_breakpad + +#endif // COMMON_BYTE_CURSOR_H_ diff --git a/breakpad/common/byte_cursor_unittest.cc b/breakpad/common/byte_cursor_unittest.cc new file mode 100644 index 0000000000..06bfd89d73 --- /dev/null +++ b/breakpad/common/byte_cursor_unittest.cc @@ -0,0 +1,776 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer +// and google_breakpad::ByteCursor. + +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/byte_cursor.h" +#include "common/using_std_string.h" + +using google_breakpad::ByteBuffer; +using google_breakpad::ByteCursor; + +TEST(Buffer, SizeOfNothing) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + EXPECT_EQ(0U, buffer.Size()); +} + +TEST(Buffer, SizeOfSomething) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + EXPECT_EQ(10U, buffer.Size()); +} + +TEST(Extent, AvailableEmpty) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + EXPECT_EQ(0U, cursor.Available()); +} + +TEST(Extent, AtEndEmpty) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + EXPECT_TRUE(cursor.AtEnd()); +} + +TEST(Extent, AsBoolEmpty) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + EXPECT_TRUE(cursor); +} + +TEST(Extent, AvailableSome) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + EXPECT_EQ(10U, cursor.Available()); +} + +TEST(Extent, AtEndSome) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + EXPECT_FALSE(cursor.AtEnd()); + EXPECT_TRUE(cursor.Skip(sizeof(data)).AtEnd()); +} + +TEST(Extent, AsBoolSome) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + EXPECT_TRUE(cursor); + EXPECT_TRUE(cursor.Skip(sizeof(data))); + EXPECT_FALSE(cursor.Skip(1)); +} + +TEST(Extent, Cursor) { + uint8_t data[] = { 0xf7, + 0x9f, 0xbe, + 0x67, 0xfb, 0xd3, 0x58, + 0x6f, 0x36, 0xde, 0xd1, + 0x2a, 0x2a, 0x2a }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t a; + uint16_t b; + uint32_t c; + uint32_t d; + uint8_t stars[3]; + + EXPECT_EQ(data + 0U, cursor.here()); + + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(data + 1U, cursor.here()); + + EXPECT_TRUE(cursor >> b); + EXPECT_EQ(data + 3U, cursor.here()); + + EXPECT_TRUE(cursor >> c); + EXPECT_EQ(data + 7U, cursor.here()); + + EXPECT_TRUE(cursor.Skip(4)); + EXPECT_EQ(data + 11U, cursor.here()); + + EXPECT_TRUE(cursor.Read(stars, 3)); + EXPECT_EQ(data + 14U, cursor.here()); + + EXPECT_FALSE(cursor >> d); + EXPECT_EQ(data + 14U, cursor.here()); +} + +TEST(Extent, SetOffset) { + uint8_t data[] = { 0x5c, 0x79, 0x8c, 0xd5 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t a, b, c, d, e; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0x5cU, a); + EXPECT_EQ(data + 1U, cursor.here()); + EXPECT_TRUE(((cursor >> b).set_here(data + 3) >> c).set_here(data + 1) + >> d >> e); + EXPECT_EQ(0x79U, b); + EXPECT_EQ(0xd5U, c); + EXPECT_EQ(0x79U, d); + EXPECT_EQ(0x8cU, e); + EXPECT_EQ(data + 3U, cursor.here()); +} + +TEST(BigEndian, Signed1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, true, &a) + .Read(1, true, &b) + .Read(1, true, &c) + .Read(1, true, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(-0x80, c); + EXPECT_EQ(-1, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, true, &e)); +} + +TEST(BigEndian, Signed2) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff, + 0x80, 0x00, 0x80, 0x80, 0xff, 0xff, + 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + int a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, true, &a) + .Read(2, true, &b) + .Read(2, true, &c) + .Read(2, true, &d) + .Read(2, true, &e) + .Read(2, true, &f) + .Read(2, true, &g) + .Read(2, true, &h) + .Read(2, true, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(-0x8000, d); + EXPECT_EQ(-0x7f80, e); + EXPECT_EQ(-1, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(-0x7544, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, true, &j)); +} + +TEST(BigEndian, Signed4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0xb6, 0xb1, 0xff, 0xef, + 0x19, 0x6a, 0xca, 0x46 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, true, &a) + .Read(4, true, &b) + .Read(4, true, &c) + .Read(4, true, &d) + .Read(4, true, &e) + .Read(4, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(-0x80000000LL, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int32_t) 0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, true, &g)); +} + +TEST(BigEndian, Signed8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c, + 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, true, &a) + .Read(8, true, &b) + .Read(8, true, &c) + .Read(8, true, &d) + .Read(8, true, &e) + .Read(8, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffffffffffffLL, b); + EXPECT_EQ(-0x7fffffffffffffffLL - 1, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4LL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, true, &g)); +} + +TEST(BigEndian, Unsigned1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int32_t a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, false, &a) + .Read(1, false, &b) + .Read(1, false, &c) + .Read(1, false, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(0x80, c); + EXPECT_EQ(0xff, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, false, &e)); +} + +TEST(BigEndian, Unsigned2) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff, + 0x80, 0x00, 0x80, 0x80, 0xff, 0xff, + 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + int64_t a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, false, &a) + .Read(2, false, &b) + .Read(2, false, &c) + .Read(2, false, &d) + .Read(2, false, &e) + .Read(2, false, &f) + .Read(2, false, &g) + .Read(2, false, &h) + .Read(2, false, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(0x8000, d); + EXPECT_EQ(0x8080, e); + EXPECT_EQ(0xffff, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(0x8abc, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, false, &j)); +} + +TEST(BigEndian, Unsigned4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0xb6, 0xb1, 0xff, 0xef, + 0x19, 0x6a, 0xca, 0x46 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, false, &a) + .Read(4, false, &b) + .Read(4, false, &c) + .Read(4, false, &d) + .Read(4, false, &e) + .Read(4, false, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(0x80000000, c); + EXPECT_EQ(0xffffffff, d); + EXPECT_EQ(0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, false, &g)); +} + +TEST(BigEndian, Unsigned8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c, + 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + uint64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, false, &a) + .Read(8, false, &b) + .Read(8, false, &c) + .Read(8, false, &d) + .Read(8, false, &e) + .Read(8, false, &f)); + EXPECT_EQ(0U, a); + EXPECT_EQ(0x7fffffffffffffffULL, b); + EXPECT_EQ(0x8000000000000000ULL, c); + EXPECT_EQ(0xffffffffffffffffULL, d); + EXPECT_EQ(0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4ULL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, false, &g)); +} + +TEST(LittleEndian, Signed1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, true, &a) + .Read(1, true, &b) + .Read(1, true, &c) + .Read(1, true, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(-0x80, c); + EXPECT_EQ(-1, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, true, &e)); +} + +TEST(LittleEndian, Signed2) { + uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f, + 0x00, 0x80, 0x80, 0x80, 0xff, 0xff, + 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, false); + int32_t a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, true, &a) + .Read(2, true, &b) + .Read(2, true, &c) + .Read(2, true, &d) + .Read(2, true, &e) + .Read(2, true, &f) + .Read(2, true, &g) + .Read(2, true, &h) + .Read(2, true, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(-0x8000, d); + EXPECT_EQ(-0x7f80, e); + EXPECT_EQ(-1, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(-0x7544, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, true, &j)); +} + +TEST(LittleEndian, Signed4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xb1, 0xb6, + 0x46, 0xca, 0x6a, 0x19 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, true, &a) + .Read(4, true, &b) + .Read(4, true, &c) + .Read(4, true, &d) + .Read(4, true, &e) + .Read(4, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(-0x80000000LL, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int32_t) 0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, true, &g)); +} + +TEST(LittleEndian, Signed8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93, + 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, false); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, true, &a) + .Read(8, true, &b) + .Read(8, true, &c) + .Read(8, true, &d) + .Read(8, true, &e) + .Read(8, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffffffffffffLL, b); + EXPECT_EQ(-0x7fffffffffffffffLL - 1, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4LL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, true, &g)); +} + +TEST(LittleEndian, Unsigned1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, false, &a) + .Read(1, false, &b) + .Read(1, false, &c) + .Read(1, false, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(0x80, c); + EXPECT_EQ(0xff, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, false, &e)); +} + +TEST(LittleEndian, Unsigned2) { + uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f, + 0x00, 0x80, 0x80, 0x80, 0xff, 0xff, + 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, false, &a) + .Read(2, false, &b) + .Read(2, false, &c) + .Read(2, false, &d) + .Read(2, false, &e) + .Read(2, false, &f) + .Read(2, false, &g) + .Read(2, false, &h) + .Read(2, false, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(0x8000, d); + EXPECT_EQ(0x8080, e); + EXPECT_EQ(0xffff, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(0x8abc, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, false, &j)); +} + +TEST(LittleEndian, Unsigned4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xb1, 0xb6, + 0x46, 0xca, 0x6a, 0x19 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, false, &a) + .Read(4, false, &b) + .Read(4, false, &c) + .Read(4, false, &d) + .Read(4, false, &e) + .Read(4, false, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(0x80000000, c); + EXPECT_EQ(0xffffffff, d); + EXPECT_EQ(0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, false, &g)); +} + +TEST(LittleEndian, Unsigned8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93, + 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, false, &a) + .Read(8, false, &b) + .Read(8, false, &c) + .Read(8, false, &d) + .Read(8, false, &e) + .Read(8, false, &f)); + EXPECT_EQ(0U, a); + EXPECT_EQ(0x7fffffffffffffffULL, b); + EXPECT_EQ(0x8000000000000000ULL, c); + EXPECT_EQ(0xffffffffffffffffULL, d); + EXPECT_EQ(0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4ULL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, false, &g)); +} + +TEST(Extractor, Signed1) { + uint8_t data[] = { 0xfd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int8_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(-3, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Signed2) { + uint8_t data[] = { 0x13, 0xcd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int16_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(-13037, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Signed4) { + uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a; + // For some reason, G++ 4.4.1 complains: + // warning: array subscript is above array bounds + // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but + // I'm not able to see how such a reference would occur. + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(-380377902, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Unsigned1) { + uint8_t data[] = { 0xfd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint8_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0xfd, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Unsigned2) { + uint8_t data[] = { 0x13, 0xcd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint16_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0xcd13, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Unsigned4) { + uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint32_t a; + // For some reason, G++ 4.4.1 complains: + // warning: array subscript is above array bounds + // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but + // I'm not able to see how such a reference would occur. + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0xe953e4d2, a); + EXPECT_FALSE(cursor >> a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Mixed) { + uint8_t data[] = { 0x42, + 0x25, 0x0b, + 0x3d, 0x25, 0xed, 0x2a, + 0xec, 0x16, 0x9e, 0x14, 0x61, 0x5b, 0x2c, 0xcf, + 0xd8, + 0x22, 0xa5, + 0x3a, 0x02, 0x6a, 0xd7, + 0x93, 0x2a, 0x2d, 0x8d, 0xb4, 0x95, 0xe0, 0xc6 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int z; + EXPECT_FALSE(cursor.AtEnd()); + EXPECT_TRUE(cursor >> a >> b >> c >> d >> e >> f >> g >> h); + EXPECT_EQ(0x42U, a); + EXPECT_EQ(0x250bU, b); + EXPECT_EQ(0x3d25ed2aU, c); + EXPECT_EQ(0xec169e14615b2ccfULL, d); + EXPECT_EQ(-40, e); + EXPECT_EQ(0x22a5, f); + EXPECT_EQ(0x3a026ad7, g); + EXPECT_EQ(-7842405714468937530LL, h); + + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor >> z); +} + +TEST(Strings, Zero) { + uint8_t data[] = { 0xa6 }; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + + uint8_t received[1]; + received[0] = 0xc2; + EXPECT_TRUE(cursor.Read(received, 0)); + EXPECT_EQ(0xc2U, received[0]); +} + +TEST(Strings, Some) { + uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t received[7] = { 0xa7, 0xf7, 0x43, 0x0c, 0x27, 0xea, 0xed }; + EXPECT_TRUE(cursor.Skip(2).Read(received, 5)); + uint8_t expected[7] = { 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xea, 0xed }; + EXPECT_TRUE(memcmp(received, expected, 7) == 0); +} + +TEST(Strings, TooMuch) { + uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t received1[3]; + uint8_t received2[3]; + uint8_t received3[3]; + EXPECT_FALSE(cursor + .Read(received1, 3) + .Read(received2, 3) + .Read(received3, 3)); + uint8_t expected1[3] = { 0x5d, 0x31, 0x09 }; + uint8_t expected2[3] = { 0xa6, 0x2e, 0x2c }; + + EXPECT_TRUE(memcmp(received1, expected1, 3) == 0); + EXPECT_TRUE(memcmp(received2, expected2, 3) == 0); +} + +TEST(Strings, PointTo) { + uint8_t data[] = { 0x83, 0x80, 0xb4, 0x38, 0x00, 0x2c, 0x0a, 0x27 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + const uint8_t *received1; + const uint8_t *received2; + const uint8_t *received3; + const uint8_t *received4; + EXPECT_FALSE(cursor + .PointTo(&received1, 3) + .PointTo(&received2, 3) + .PointTo(&received3) + .PointTo(&received4, 3)); + EXPECT_EQ(data + 0, received1); + EXPECT_EQ(data + 3, received2); + EXPECT_EQ(data + 6, received3); + EXPECT_EQ(NULL, received4); +} + +TEST(Strings, CString) { + uint8_t data[] = "abc\0\0foo"; + ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0' + ByteCursor cursor(&buffer); + + string a, b, c; + EXPECT_TRUE(cursor.CString(&a).CString(&b)); + EXPECT_EQ("abc", a); + EXPECT_EQ("", b); + EXPECT_FALSE(cursor.CString(&c)); + EXPECT_EQ("", c); + EXPECT_TRUE(cursor.AtEnd()); +} + +TEST(Strings, CStringLimit) { + uint8_t data[] = "abcdef\0\0foobar"; + ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0' + ByteCursor cursor(&buffer); + + string a, b, c, d, e; + + EXPECT_TRUE(cursor.CString(&a, 3)); + EXPECT_EQ("abc", a); + + EXPECT_TRUE(cursor.CString(&b, 0)); + EXPECT_EQ("", b); + + EXPECT_TRUE(cursor.CString(&c, 6)); + EXPECT_EQ("def", c); + + EXPECT_TRUE(cursor.CString(&d, 4)); + EXPECT_EQ("ooba", d); + + EXPECT_FALSE(cursor.CString(&e, 4)); + EXPECT_EQ("", e); + + EXPECT_TRUE(cursor.AtEnd()); +} + +// uint8_t data[] = { 0xa6, 0x54, 0xdf, 0x67, 0x51, 0x43, 0xac, 0xf1 }; +// ByteBuffer buffer(data, sizeof(data)); diff --git a/breakpad/common/convert_UTF.c b/breakpad/common/convert_UTF.c new file mode 100644 index 0000000000..80178d35ef --- /dev/null +++ b/breakpad/common/convert_UTF.c @@ -0,0 +1,533 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Source code file. +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Sept 2001: fixed const & error conditions per +mods suggested by S. Parent & A. Lillich. +June 2002: Tim Dodd added detection and handling of incomplete +source sequences, enhanced error detection, added casts +to eliminate compiler warnings. +July 2003: slight mods to back out aggressive FFFE detection. +Jan 2004: updated switches in from-UTF8 conversions. +Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + +See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "convert_UTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG + if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); + } +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. +* Constants have been gathered. Loops & conditionals have been removed as +* much as possible for efficiency, in favor of drop-through switches. +* (See "Note A" at the bottom of the file for equivalent code.) +* If your compiler supports it, the "isLegalUTF8" call can be turned +* into an inline function. +*/ + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + +Note A. +The fall-through switches in UTF-8 reading code save a +temp variable, some decrements & conditionals. The switches +are equivalent to the following loop: +{ + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); +} +In UTF-8 writing code, the switches on "bytesToWrite" are +similarly unrolled loops. + +--------------------------------------------------------------------- */ diff --git a/breakpad/common/convert_UTF.h b/breakpad/common/convert_UTF.h new file mode 100644 index 0000000000..b1556de81e --- /dev/null +++ b/breakpad/common/convert_UTF.h @@ -0,0 +1,143 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Header file. + +Several funtions are included here, forming a complete set of +conversions between the three formats. UTF-7 is not included +here, but is handled in a separate source file. + +Each of these routines takes pointers to input buffers and output +buffers. The input buffers are const. + +Each routine converts the text between *sourceStart and sourceEnd, +putting the result into the buffer between *targetStart and +targetEnd. Note: the end pointers are *after* the last item: e.g. +*(sourceEnd - 1) is the last item. + +The return result indicates whether the conversion was successful, +and if not, whether the problem was in the source or target buffers. +(Only the first encountered problem is indicated.) + +After the conversion, *sourceStart and *targetStart are both +updated to point to the end of last text successfully converted in +the respective buffers. + +Input parameters: +sourceStart - pointer to a pointer to the source buffer. +The contents of this are modified on return so that +it points at the next thing to be converted. +targetStart - similarly, pointer to pointer to the target buffer. +sourceEnd, targetEnd - respectively pointers to the ends of the +two buffers, for overflow checking only. + +These conversion functions take a ConversionFlags argument. When this +flag is set to strict, both irregular sequences and isolated surrogates +will cause an error. When the flag is set to lenient, both irregular +sequences and isolated surrogates are converted. + +Whether the flag is strict or lenient, all illegal sequences will cause +an error return. This includes sequences such as: , , +or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code +must check for illegal sequences. + +When the flag is set to lenient, characters over 0x10FFFF are converted +to the replacement character; otherwise (when the flag is set to strict) +they constitute an error. + +Output parameters: +The value "sourceIllegal" is returned from some routines if the input +sequence is malformed. When "sourceIllegal" is returned, the source +value will point to the illegal value that caused the problem. E.g., +in UTF-8 when a sequence is malformed, it points to the start of the +malformed sequence. + +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- +The following 4 definitions are compiler-specific. +The C standard does not guarantee that wchar_t has at least +16 bits, so wchar_t is no less portable than unsigned short! +All should be unsigned values to avoid sign extension during +bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned long UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ diff --git a/breakpad/common/dwarf_cfi_to_module.cc b/breakpad/common/dwarf_cfi_to_module.cc new file mode 100644 index 0000000000..15904d7599 --- /dev/null +++ b/breakpad/common/dwarf_cfi_to_module.cc @@ -0,0 +1,258 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// Implementation of google_breakpad::DwarfCFIToModule. +// See dwarf_cfi_to_module.h for details. + +#include + +#include "common/dwarf_cfi_to_module.h" + +namespace google_breakpad { + +using std::ostringstream; + +vector DwarfCFIToModule::RegisterNames::MakeVector( + const char * const *strings, + size_t size) { + vector names(strings, strings + size); + return names; +} + +vector DwarfCFIToModule::RegisterNames::I386() { + static const char *const names[] = { + "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", + "$eip", "$eflags", "$unused1", + "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", + "$unused2", "$unused3", + "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", + "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", + "$fcw", "$fsw", "$mxcsr", + "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", + "$tr", "$ldtr" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +vector DwarfCFIToModule::RegisterNames::X86_64() { + static const char *const names[] = { + "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", + "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", + "$rip", + "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", + "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", + "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", + "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", + "$rflags", + "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2", + "$fs.base", "$gs.base", "$unused3", "$unused4", + "$tr", "$ldtr", + "$mxcsr", "$fcw", "$fsw" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +// Per ARM IHI 0040A, section 3.1 +vector DwarfCFIToModule::RegisterNames::ARM() { + static const char *const names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "fps", "cpsr", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", + "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", + "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, + uint8 version, const string &augmentation, + unsigned return_address) { + assert(!entry_); + + // If dwarf2reader::CallFrameInfo can handle this version and + // augmentation, then we should be okay with that, so there's no + // need to check them here. + + // Get ready to collect entries. + entry_ = new Module::StackFrameEntry; + entry_->address = address; + entry_->size = length; + entry_offset_ = offset; + return_address_ = return_address; + + // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI + // may not establish any rule for .ra if the return address column + // is an ordinary register, and that register holds the return + // address on entry to the function. So establish an initial .ra + // rule citing the return address register. + if (return_address_ < register_names_.size()) + entry_->initial_rules[ra_name_] = register_names_[return_address_]; + + return true; +} + +string DwarfCFIToModule::RegisterName(int i) { + assert(entry_); + if (i < 0) { + assert(i == kCFARegister); + return cfa_name_; + } + unsigned reg = i; + if (reg == return_address_) + return ra_name_; + + // Ensure that a non-empty name exists for this register value. + if (reg < register_names_.size() && !register_names_[reg].empty()) + return register_names_[reg]; + + reporter_->UnnamedRegister(entry_offset_, reg); + char buf[30]; + sprintf(buf, "unnamed_register%u", reg); + return buf; +} + +void DwarfCFIToModule::Record(Module::Address address, int reg, + const string &rule) { + assert(entry_); + + // Place the name in our global set of strings, and then use the string + // from the set. Even though the assignment looks like a copy, all the + // major std::string implementations use reference counting internally, + // so the effect is to have all our data structures share copies of rules + // whenever possible. Since register names are drawn from a + // vector, register names are already shared. + string shared_rule = *common_strings_.insert(rule).first; + + // Is this one of this entry's initial rules? + if (address == entry_->address) + entry_->initial_rules[RegisterName(reg)] = shared_rule; + // File it under the appropriate address. + else + entry_->rule_changes[address][RegisterName(reg)] = shared_rule; +} + +bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { + reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); + // Treat this as a non-fatal error. + return true; +} + +bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { + ostringstream s; + s << RegisterName(reg); + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, + int base_register, long offset) { + ostringstream s; + s << RegisterName(base_register) << " " << offset << " + ^"; + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, + int base_register, long offset) { + ostringstream s; + s << RegisterName(base_register) << " " << offset << " +"; + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, + int base_register) { + ostringstream s; + s << RegisterName(base_register); + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, + const string &expression) { + reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); + // Treat this as a non-fatal error. + return true; +} + +bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, + const string &expression) { + reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); + // Treat this as a non-fatal error. + return true; +} + +bool DwarfCFIToModule::End() { + module_->AddStackFrameEntry(entry_); + entry_ = NULL; + return true; +} + +void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { + fprintf(stderr, "%s, section '%s': " + "the call frame entry at offset 0x%zx refers to register %d," + " whose name we don't know\n", + file_.c_str(), section_.c_str(), offset, reg); +} + +void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, + const string ®) { + fprintf(stderr, "%s, section '%s': " + "the call frame entry at offset 0x%zx sets the rule for " + "register '%s' to 'undefined', but the Breakpad symbol file format" + " cannot express this\n", + file_.c_str(), section_.c_str(), offset, reg.c_str()); +} + +void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, + const string ®) { + fprintf(stderr, "%s, section '%s': " + "the call frame entry at offset 0x%zx uses a DWARF expression to" + " describe how to recover register '%s', " + " but this translator cannot yet translate DWARF expressions to" + " Breakpad postfix expressions\n", + file_.c_str(), section_.c_str(), offset, reg.c_str()); +} + +} // namespace google_breakpad diff --git a/breakpad/common/dwarf_cfi_to_module.h b/breakpad/common/dwarf_cfi_to_module.h new file mode 100644 index 0000000000..7db552a68a --- /dev/null +++ b/breakpad/common/dwarf_cfi_to_module.h @@ -0,0 +1,196 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dwarf_cfi_to_module.h: Define the DwarfCFIToModule class, which +// accepts parsed DWARF call frame info and adds it to a +// google_breakpad::Module object, which can write that information to +// a Breakpad symbol file. + +#ifndef COMMON_LINUX_DWARF_CFI_TO_MODULE_H +#define COMMON_LINUX_DWARF_CFI_TO_MODULE_H + +#include +#include + +#include +#include +#include + +#include "common/module.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using dwarf2reader::CallFrameInfo; +using google_breakpad::Module; +using std::set; +using std::vector; + +// A class that accepts parsed call frame information from the DWARF +// CFI parser and populates a google_breakpad::Module object with the +// contents. +class DwarfCFIToModule: public CallFrameInfo::Handler { + public: + + // DwarfCFIToModule uses an instance of this class to report errors + // detected while converting DWARF CFI to Breakpad STACK CFI records. + class Reporter { + public: + // Create a reporter that writes messages to the standard error + // stream. FILE is the name of the file we're processing, and + // SECTION is the name of the section within that file that we're + // looking at (.debug_frame, .eh_frame, etc.). + Reporter(const string &file, const string §ion) + : file_(file), section_(section) { } + virtual ~Reporter() { } + + // The DWARF CFI entry at OFFSET cites register REG, but REG is not + // covered by the vector of register names passed to the + // DwarfCFIToModule constructor, nor does it match the return + // address column number for this entry. + virtual void UnnamedRegister(size_t offset, int reg); + + // The DWARF CFI entry at OFFSET says that REG is undefined, but the + // Breakpad symbol file format cannot express this. + virtual void UndefinedNotSupported(size_t offset, const string ®); + + // The DWARF CFI entry at OFFSET says that REG uses a DWARF + // expression to find its value, but DwarfCFIToModule is not + // capable of translating DWARF expressions to Breakpad postfix + // expressions. + virtual void ExpressionsNotSupported(size_t offset, const string ®); + + protected: + string file_, section_; + }; + + // Register name tables. If TABLE is a vector returned by one of these + // functions, then TABLE[R] is the name of the register numbered R in + // DWARF call frame information. + class RegisterNames { + public: + // Intel's "x86" or IA-32. + static vector I386(); + + // AMD x86_64, AMD64, Intel EM64T, or Intel 64 + static vector X86_64(); + + // ARM. + static vector ARM(); + + private: + // Given STRINGS, an array of C strings with SIZE elements, return an + // equivalent vector. + static vector MakeVector(const char * const *strings, size_t size); + }; + + // Create a handler for the dwarf2reader::CallFrameInfo parser that + // records the stack unwinding information it receives in MODULE. + // + // Use REGISTER_NAMES[I] as the name of register number I; *this + // keeps a reference to the vector, so the vector should remain + // alive for as long as the DwarfCFIToModule does. + // + // Use REPORTER for reporting problems encountered in the conversion + // process. + DwarfCFIToModule(Module *module, const vector ®ister_names, + Reporter *reporter) + : module_(module), register_names_(register_names), reporter_(reporter), + entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") { + } + virtual ~DwarfCFIToModule() { delete entry_; } + + virtual bool Entry(size_t offset, uint64 address, uint64 length, + uint8 version, const string &augmentation, + unsigned return_address); + virtual bool UndefinedRule(uint64 address, int reg); + virtual bool SameValueRule(uint64 address, int reg); + virtual bool OffsetRule(uint64 address, int reg, + int base_register, long offset); + virtual bool ValOffsetRule(uint64 address, int reg, + int base_register, long offset); + virtual bool RegisterRule(uint64 address, int reg, int base_register); + virtual bool ExpressionRule(uint64 address, int reg, + const string &expression); + virtual bool ValExpressionRule(uint64 address, int reg, + const string &expression); + virtual bool End(); + + private: + // Return the name to use for register REG. + string RegisterName(int i); + + // Record RULE for register REG at ADDRESS. + void Record(Module::Address address, int reg, const string &rule); + + // The module to which we should add entries. + Module *module_; + + // Map from register numbers to register names. + const vector ®ister_names_; + + // The reporter to use to report problems. + Reporter *reporter_; + + // The current entry we're constructing. + Module::StackFrameEntry *entry_; + + // The section offset of the current frame description entry, for + // use in error messages. + size_t entry_offset_; + + // The return address column for that entry. + unsigned return_address_; + + // The names of the return address and canonical frame address. Putting + // these here instead of using string literals allows us to share their + // texts in reference-counted std::string implementations (all the + // popular ones). Many, many rules cite these strings. + string cfa_name_, ra_name_; + + // A set of strings used by this CFI. Before storing a string in one of + // our data structures, insert it into this set, and then use the string + // from the set. + // + // Because std::string uses reference counting internally, simply using + // strings from this set, even if passed by value, assigned, or held + // directly in structures and containers (map, for example), + // causes those strings to share a single instance of each distinct piece + // of text. + set common_strings_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H diff --git a/breakpad/common/dwarf_cfi_to_module_unittest.cc b/breakpad/common/dwarf_cfi_to_module_unittest.cc new file mode 100644 index 0000000000..807d1b20c3 --- /dev/null +++ b/breakpad/common/dwarf_cfi_to_module_unittest.cc @@ -0,0 +1,306 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf_cfi_to_module.h" +#include "common/using_std_string.h" + +using std::vector; + +using google_breakpad::Module; +using google_breakpad::DwarfCFIToModule; +using testing::ContainerEq; +using testing::Test; +using testing::_; + +struct MockCFIReporter: public DwarfCFIToModule::Reporter { + MockCFIReporter(const string &file, const string §ion) + : Reporter(file, section) { } + MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); + MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); + MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); +}; + +struct DwarfCFIToModuleFixture { + DwarfCFIToModuleFixture() + : module("module name", "module os", "module arch", "module id"), + reporter("reporter file", "reporter section"), + handler(&module, register_names, &reporter) { + register_names.push_back("reg0"); + register_names.push_back("reg1"); + register_names.push_back("reg2"); + register_names.push_back("reg3"); + register_names.push_back("reg4"); + register_names.push_back("reg5"); + register_names.push_back("reg6"); + register_names.push_back("reg7"); + register_names.push_back("sp"); + register_names.push_back("pc"); + register_names.push_back(""); + + EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0); + EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0); + EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0); + } + + Module module; + vector register_names; + MockCFIReporter reporter; + DwarfCFIToModule handler; + vector entries; +}; + +class Entry: public DwarfCFIToModuleFixture, public Test { }; + +TEST_F(Entry, Accept) { + ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL, + 0xb440ce248169c8d6ULL, 3, "", 0xea93c106)); + ASSERT_TRUE(handler.End()); + module.GetStackFrameEntries(&entries); + EXPECT_EQ(1U, entries.size()); + EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address); + EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Entry, AcceptOldVersion) { + ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL, + 0xc771f44958d40bbcULL, 1, "", 0x093c945e)); + ASSERT_TRUE(handler.End()); + module.GetStackFrameEntries(&entries); + EXPECT_EQ(1U, entries.size()); + EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address); + EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +struct RuleFixture: public DwarfCFIToModuleFixture { + RuleFixture() : DwarfCFIToModuleFixture() { + entry_address = 0x89327ebf86b47492ULL; + entry_size = 0x2f8cd573072fe02aULL; + return_reg = 0x7886a346; + } + void StartEntry() { + ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size, + 3, "", return_reg)); + } + void CheckEntry() { + module.GetStackFrameEntries(&entries); + EXPECT_EQ(1U, entries.size()); + EXPECT_EQ(entry_address, entries[0]->address); + EXPECT_EQ(entry_size, entries[0]->size); + } + uint64 entry_address, entry_size; + unsigned return_reg; +}; + +class Rule: public RuleFixture, public Test { }; + +TEST_F(Rule, UndefinedRule) { + EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7")); + StartEntry(); + ASSERT_TRUE(handler.UndefinedRule(entry_address, 7)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, RegisterWithEmptyName) { + EXPECT_CALL(reporter, UnnamedRegister(_, 10)); + EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10")); + StartEntry(); + ASSERT_TRUE(handler.UndefinedRule(entry_address, 10)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, SameValueRule) { + StartEntry(); + ASSERT_TRUE(handler.SameValueRule(entry_address, 6)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial["reg6"] = "reg6"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, OffsetRule) { + StartEntry(); + ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg, + DwarfCFIToModule::kCFARegister, + 16927065)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST_F(Rule, OffsetRuleNegative) { + StartEntry(); + ASSERT_TRUE(handler.OffsetRule(entry_address + 1, + DwarfCFIToModule::kCFARegister, 4, -34530721)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST_F(Rule, ValOffsetRule) { + // Use an unnamed register number, to exercise that branch of RegisterName. + EXPECT_CALL(reporter, UnnamedRegister(_, 11)); + StartEntry(); + ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7, + DwarfCFIToModule::kCFARegister, + 11, 61812979)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 0x5ab7][".cfa"] = + "unnamed_register11 61812979 +"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST_F(Rule, RegisterRule) { + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg3"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, ExpressionRule) { + EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2")); + StartEntry(); + ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2, + "it takes two to tango")); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, ValExpressionRule) { + EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0")); + StartEntry(); + ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0, + "bit off more than he could chew")); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, DefaultReturnAddressRule) { + return_reg = 2; + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg2"; + expected_initial["reg0"] = "reg1"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, DefaultReturnAddressRuleOverride) { + return_reg = 2; + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg1"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, DefaultReturnAddressRuleLater) { + return_reg = 2; + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg2"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 1][".ra"] = "reg1"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST(RegisterNames, I386) { + vector names = DwarfCFIToModule::RegisterNames::I386(); + + EXPECT_EQ("$eax", names[0]); + EXPECT_EQ("$ecx", names[1]); + EXPECT_EQ("$esp", names[4]); + EXPECT_EQ("$eip", names[8]); +} + +TEST(RegisterNames, ARM) { + vector names = DwarfCFIToModule::RegisterNames::ARM(); + + EXPECT_EQ("r0", names[0]); + EXPECT_EQ("r10", names[10]); + EXPECT_EQ("sp", names[13]); + EXPECT_EQ("lr", names[14]); + EXPECT_EQ("pc", names[15]); +} + +TEST(RegisterNames, X86_64) { + vector names = DwarfCFIToModule::RegisterNames::X86_64(); + + EXPECT_EQ("$rax", names[0]); + EXPECT_EQ("$rdx", names[1]); + EXPECT_EQ("$rbp", names[6]); + EXPECT_EQ("$rsp", names[7]); + EXPECT_EQ("$rip", names[16]); +} diff --git a/breakpad/common/dwarf_cu_to_module.cc b/breakpad/common/dwarf_cu_to_module.cc new file mode 100644 index 0000000000..8246daf9c2 --- /dev/null +++ b/breakpad/common/dwarf_cu_to_module.cc @@ -0,0 +1,1054 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// Implement the DwarfCUToModule class; see dwarf_cu_to_module.h. + +// For PRI* macros, before anything else might #include it. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ + +#include "common/dwarf_cu_to_module.h" + +#include +#if !defined(__ANDROID__) +#include +#endif +#include +#include + +#include +#include +#include + +#include "common/dwarf_line_to_module.h" + +namespace google_breakpad { + +using std::map; +using std::pair; +using std::set; +using std::sort; +using std::vector; + +// Data provided by a DWARF specification DIE. +// +// In DWARF, the DIE for a definition may contain a DW_AT_specification +// attribute giving the offset of the corresponding declaration DIE, and +// the definition DIE may omit information given in the declaration. For +// example, it's common for a function's address range to appear only in +// its definition DIE, but its name to appear only in its declaration +// DIE. +// +// The dumper needs to be able to follow DW_AT_specification links to +// bring all this information together in a FUNC record. Conveniently, +// DIEs that are the target of such links have a DW_AT_declaration flag +// set, so we can identify them when we first see them, and record their +// contents for later reference. +// +// A Specification holds information gathered from a declaration DIE that +// we may need if we find a DW_AT_specification link pointing to it. +struct DwarfCUToModule::Specification { + // The qualified name that can be found by demangling DW_AT_MIPS_linkage_name. + string qualified_name; + + // The name of the enclosing scope, or the empty string if there is none. + string enclosing_name; + + // The name for the specification DIE itself, without any enclosing + // name components. + string unqualified_name; +}; + +// An abstract origin -- base definition of an inline function. +struct AbstractOrigin { + AbstractOrigin() : name() {} + explicit AbstractOrigin(const string& name) : name(name) {} + + string name; +}; + +typedef map AbstractOriginByOffset; + +// Data global to the DWARF-bearing file that is private to the +// DWARF-to-Module process. +struct DwarfCUToModule::FilePrivate { + // A set of strings used in this CU. Before storing a string in one of + // our data structures, insert it into this set, and then use the string + // from the set. + // + // In some STL implementations, strings are reference-counted internally, + // meaning that simply using strings from this set, even if passed by + // value, assigned, or held directly in structures and containers + // (map, for example), causes those strings to share a + // single instance of each distinct piece of text. GNU's libstdc++ uses + // reference counts, and I believe MSVC did as well, at some point. + // However, C++ '11 implementations are moving away from reference + // counting. + // + // In other implementations, string assignments copy the string's text, + // so this set will actually hold yet another copy of the string (although + // everything will still work). To improve memory consumption portably, + // we will probably need to use pointers to strings held in this set. + set common_strings; + + // A map from offsets of DIEs within the .debug_info section to + // Specifications describing those DIEs. Specification references can + // cross compilation unit boundaries. + SpecificationByOffset specifications; + + AbstractOriginByOffset origins; +}; + +DwarfCUToModule::FileContext::FileContext(const string &filename, + Module *module, + bool handle_inter_cu_refs) + : filename_(filename), + module_(module), + handle_inter_cu_refs_(handle_inter_cu_refs), + file_private_(new FilePrivate()) { +} + +DwarfCUToModule::FileContext::~FileContext() { +} + +void DwarfCUToModule::FileContext::AddSectionToSectionMap( + const string& name, const char* contents, uint64 length) { + section_map_[name] = std::make_pair(contents, length); +} + +void DwarfCUToModule::FileContext::ClearSectionMapForTest() { + section_map_.clear(); +} + +const dwarf2reader::SectionMap& +DwarfCUToModule::FileContext::section_map() const { + return section_map_; +} + +void DwarfCUToModule::FileContext::ClearSpecifications() { + if (!handle_inter_cu_refs_) + file_private_->specifications.clear(); +} + +bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( + uint64 offset, uint64 compilation_unit_start) const { + if (handle_inter_cu_refs_) + return false; + return offset < compilation_unit_start; +} + +// Information global to the particular compilation unit we're +// parsing. This is for data shared across the CU's entire DIE tree, +// and parameters from the code invoking the CU parser. +struct DwarfCUToModule::CUContext { + CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg) + : file_context(file_context_arg), + reporter(reporter_arg), + language(Language::CPlusPlus) {} + + ~CUContext() { + for (vector::iterator it = functions.begin(); + it != functions.end(); ++it) { + delete *it; + } + }; + + // The DWARF-bearing file into which this CU was incorporated. + FileContext *file_context; + + // For printing error messages. + WarningReporter *reporter; + + // The source language of this compilation unit. + const Language *language; + + // The functions defined in this compilation unit. We accumulate + // them here during parsing. Then, in DwarfCUToModule::Finish, we + // assign them lines and add them to file_context->module. + // + // Destroying this destroys all the functions this vector points to. + vector functions; +}; + +// Information about the context of a particular DIE. This is for +// information that changes as we descend the tree towards the leaves: +// the containing classes/namespaces, etc. +struct DwarfCUToModule::DIEContext { + // The fully-qualified name of the context. For example, for a + // tree like: + // + // DW_TAG_namespace Foo + // DW_TAG_class Bar + // DW_TAG_subprogram Baz + // + // in a C++ compilation unit, the DIEContext's name for the + // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's + // name for the DW_TAG_namespace DIE would be "". + string name; +}; + +// An abstract base class for all the dumper's DIE handlers. +class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { + public: + // Create a handler for the DIE at OFFSET whose compilation unit is + // described by CU_CONTEXT, and whose immediate context is described + // by PARENT_CONTEXT. + GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, + uint64 offset) + : cu_context_(cu_context), + parent_context_(parent_context), + offset_(offset), + declaration_(false), + specification_(NULL) { } + + // Derived classes' ProcessAttributeUnsigned can defer to this to + // handle DW_AT_declaration, or simply not override it. + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + // Derived classes' ProcessAttributeReference can defer to this to + // handle DW_AT_specification, or simply not override it. + void ProcessAttributeReference(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + // Derived classes' ProcessAttributeReference can defer to this to + // handle DW_AT_specification, or simply not override it. + void ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string &data); + + protected: + // Compute and return the fully-qualified name of the DIE. If this + // DIE is a declaration DIE, to be cited by other DIEs' + // DW_AT_specification attributes, record its enclosing name and + // unqualified name in the specification table. + // + // Use this from EndAttributes member functions, not ProcessAttribute* + // functions; only the former can be sure that all the DIE's attributes + // have been seen. + string ComputeQualifiedName(); + + CUContext *cu_context_; + DIEContext *parent_context_; + uint64 offset_; + + // Place the name in the global set of strings. Even though this looks + // like a copy, all the major std::string implementations use reference + // counting internally, so the effect is to have all the data structures + // share copies of strings whenever possible. + // FIXME: Should this return something like a string_ref to avoid the + // assumption about how strings are implemented? + string AddStringToPool(const string &str); + + // If this DIE has a DW_AT_declaration attribute, this is its value. + // It is false on DIEs with no DW_AT_declaration attribute. + bool declaration_; + + // If this DIE has a DW_AT_specification attribute, this is the + // Specification structure for the DIE the attribute refers to. + // Otherwise, this is NULL. + Specification *specification_; + + // The value of the DW_AT_name attribute, or the empty string if the + // DIE has no such attribute. + string name_attribute_; + + // The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty + // string if the DIE has no such attribute or its content could not be + // demangled. + string demangled_name_; +}; + +void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; + default: break; + } +} + +void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_specification: { + FileContext *file_context = cu_context_->file_context; + if (file_context->IsUnhandledInterCUReference( + data, cu_context_->reporter->cu_offset())) { + cu_context_->reporter->UnhandledInterCUReference(offset_, data); + break; + } + // Find the Specification to which this attribute refers, and + // set specification_ appropriately. We could do more processing + // here, but it's better to leave the real work to our + // EndAttribute member function, at which point we know we have + // seen all the DIE's attributes. + SpecificationByOffset *specifications = + &file_context->file_private_->specifications; + SpecificationByOffset::iterator spec = specifications->find(data); + if (spec != specifications->end()) { + specification_ = &spec->second; + } else { + // Technically, there's no reason a DW_AT_specification + // couldn't be a forward reference, but supporting that would + // be a lot of work (changing to a two-pass structure), and I + // don't think any producers we care about ever emit such + // things. + cu_context_->reporter->UnknownSpecification(offset_, data); + } + break; + } + default: break; + } +} + +string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) { + pair::iterator, bool> result = + cu_context_->file_context->file_private_->common_strings.insert(str); + return *result.first; +} + +void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( + enum DwarfAttribute attr, + enum DwarfForm form, + const string &data) { + switch (attr) { + case dwarf2reader::DW_AT_name: + name_attribute_ = AddStringToPool(data); + break; + case dwarf2reader::DW_AT_MIPS_linkage_name: { + char* demangled = NULL; +#if !defined(__ANDROID__) + demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL); +#endif + if (demangled) { + demangled_name_ = AddStringToPool(demangled); + free(reinterpret_cast(demangled)); + } + break; + } + default: break; + } +} + +string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { + // Use the demangled name, if one is available. Demangled names are + // preferable to those inferred from the DWARF structure because they + // include argument types. + const string *qualified_name = NULL; + if (!demangled_name_.empty()) { + // Found it is this DIE. + qualified_name = &demangled_name_; + } else if (specification_ && !specification_->qualified_name.empty()) { + // Found it on the specification. + qualified_name = &specification_->qualified_name; + } + + const string *unqualified_name; + const string *enclosing_name; + if (!qualified_name) { + // Find our unqualified name. If the DIE has its own DW_AT_name + // attribute, then use that; otherwise, check our specification. + if (name_attribute_.empty() && specification_) + unqualified_name = &specification_->unqualified_name; + else + unqualified_name = &name_attribute_; + + // Find the name of our enclosing context. If we have a + // specification, it's the specification's enclosing context that + // counts; otherwise, use this DIE's context. + if (specification_) + enclosing_name = &specification_->enclosing_name; + else + enclosing_name = &parent_context_->name; + } + + // If this DIE was marked as a declaration, record its names in the + // specification table. + if (declaration_) { + Specification spec; + if (qualified_name) { + spec.qualified_name = *qualified_name; + } else { + spec.enclosing_name = *enclosing_name; + spec.unqualified_name = *unqualified_name; + } + cu_context_->file_context->file_private_->specifications[offset_] = spec; + } + + if (qualified_name) + return *qualified_name; + + // Combine the enclosing name and unqualified name to produce our + // own fully-qualified name. + return cu_context_->language->MakeQualifiedName(*enclosing_name, + *unqualified_name); +} + +// A handler class for DW_TAG_subprogram DIEs. +class DwarfCUToModule::FuncHandler: public GenericDIEHandler { + public: + FuncHandler(CUContext *cu_context, DIEContext *parent_context, + uint64 offset) + : GenericDIEHandler(cu_context, parent_context, offset), + low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), + abstract_origin_(NULL), inline_(false) { } + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + void ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data); + void ProcessAttributeReference(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + bool EndAttributes(); + void Finish(); + + private: + // The fully-qualified name, as derived from name_attribute_, + // specification_, parent_context_. Computed in EndAttributes. + string name_; + uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc + DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. + const AbstractOrigin* abstract_origin_; + bool inline_; +}; + +void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + // If this attribute is present at all --- even if its value is + // DW_INL_not_inlined --- then GCC may cite it as someone else's + // DW_AT_abstract_origin attribute. + case dwarf2reader::DW_AT_inline: inline_ = true; break; + + case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; + case dwarf2reader::DW_AT_high_pc: + high_pc_form_ = form; + high_pc_ = data; + break; + + default: + GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); + break; + } +} + +void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + switch (attr) { + // If this attribute is present at all --- even if its value is + // DW_INL_not_inlined --- then GCC may cite it as someone else's + // DW_AT_abstract_origin attribute. + case dwarf2reader::DW_AT_inline: inline_ = true; break; + + default: + break; + } +} + +void DwarfCUToModule::FuncHandler::ProcessAttributeReference( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_abstract_origin: { + const AbstractOriginByOffset& origins = + cu_context_->file_context->file_private_->origins; + AbstractOriginByOffset::const_iterator origin = origins.find(data); + if (origin != origins.end()) { + abstract_origin_ = &(origin->second); + } else { + cu_context_->reporter->UnknownAbstractOrigin(offset_, data); + } + break; + } + default: + GenericDIEHandler::ProcessAttributeReference(attr, form, data); + break; + } +} + +bool DwarfCUToModule::FuncHandler::EndAttributes() { + // Compute our name, and record a specification, if appropriate. + name_ = ComputeQualifiedName(); + if (name_.empty() && abstract_origin_) { + name_ = abstract_origin_->name; + } + return true; +} + +void DwarfCUToModule::FuncHandler::Finish() { + // Make high_pc_ an address, if it isn't already. + if (high_pc_form_ != dwarf2reader::DW_FORM_addr) { + high_pc_ += low_pc_; + } + + // Did we collect the information we need? Not all DWARF function + // entries have low and high addresses (for example, inlined + // functions that were never used), but all the ones we're + // interested in cover a non-empty range of bytes. + if (low_pc_ < high_pc_) { + // Create a Module::Function based on the data we've gathered, and + // add it to the functions_ list. + Module::Function *func = new Module::Function; + // Malformed DWARF may omit the name, but all Module::Functions must + // have names. + if (!name_.empty()) { + func->name = name_; + } else { + cu_context_->reporter->UnnamedFunction(offset_); + func->name = ""; + } + func->address = low_pc_; + func->size = high_pc_ - low_pc_; + func->parameter_size = 0; + if (func->address) { + // If the function address is zero this is a sign that this function + // description is just empty debug data and should just be discarded. + cu_context_->functions.push_back(func); + } + } else if (inline_) { + AbstractOrigin origin(name_); + cu_context_->file_context->file_private_->origins[offset_] = origin; + } +} + +// A handler for DIEs that contain functions and contribute a +// component to their names: namespaces, classes, etc. +class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { + public: + NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, + uint64 offset) + : GenericDIEHandler(cu_context, parent_context, offset) { } + bool EndAttributes(); + DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag); + + private: + DIEContext child_context_; // A context for our children. +}; + +bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { + child_context_.name = ComputeQualifiedName(); + return true; +} + +dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( + uint64 offset, + enum DwarfTag tag) { + switch (tag) { + case dwarf2reader::DW_TAG_subprogram: + return new FuncHandler(cu_context_, &child_context_, offset); + case dwarf2reader::DW_TAG_namespace: + case dwarf2reader::DW_TAG_class_type: + case dwarf2reader::DW_TAG_structure_type: + case dwarf2reader::DW_TAG_union_type: + return new NamedScopeHandler(cu_context_, &child_context_, offset); + default: + return NULL; + } +} + +void DwarfCUToModule::WarningReporter::CUHeading() { + if (printed_cu_header_) + return; + fprintf(stderr, "%s: in compilation unit '%s' (offset 0x%llx):\n", + filename_.c_str(), cu_name_.c_str(), cu_offset_); + printed_cu_header_ = true; +} + +void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, + uint64 target) { + CUHeading(); + fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_specification" + " attribute referring to the die at offset 0x%llx, which either" + " was not marked as a declaration, or comes later in the file\n", + filename_.c_str(), offset, target); +} + +void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64 offset, + uint64 target) { + CUHeading(); + fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_abstract_origin" + " attribute referring to the die at offset 0x%llx, which either" + " was not marked as an inline, or comes later in the file\n", + filename_.c_str(), offset, target); +} + +void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { + CUHeading(); + fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", + filename_.c_str(), name.c_str()); +} + +void DwarfCUToModule::WarningReporter::BadLineInfoOffset(uint64 offset) { + CUHeading(); + fprintf(stderr, "%s: warning: line number data offset beyond end" + " of '.debug_line' section\n", + filename_.c_str()); +} + +void DwarfCUToModule::WarningReporter::UncoveredHeading() { + if (printed_unpaired_header_) + return; + CUHeading(); + fprintf(stderr, "%s: warning: skipping unpaired lines/functions:\n", + filename_.c_str()); + printed_unpaired_header_ = true; +} + +void DwarfCUToModule::WarningReporter::UncoveredFunction( + const Module::Function &function) { + if (!uncovered_warnings_enabled_) + return; + UncoveredHeading(); + fprintf(stderr, " function%s: %s\n", + function.size == 0 ? " (zero-length)" : "", + function.name.c_str()); +} + +void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { + if (!uncovered_warnings_enabled_) + return; + UncoveredHeading(); + fprintf(stderr, " line%s: %s:%d at 0x%" PRIx64 "\n", + (line.size == 0 ? " (zero-length)" : ""), + line.file->name.c_str(), line.number, line.address); +} + +void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) { + CUHeading(); + fprintf(stderr, "%s: warning: function at offset 0x%llx has no name\n", + filename_.c_str(), offset); +} + +void DwarfCUToModule::WarningReporter::UnhandledInterCUReference( + uint64 offset, uint64 target) { + CUHeading(); + fprintf(stderr, "%s: warning: the DIE at offset 0x%llx has a " + "DW_FORM_ref_addr attribute with an inter-CU reference to " + "0x%llx, but inter-CU reference handling is turned off.\n", + filename_.c_str(), offset, target); +} + +DwarfCUToModule::DwarfCUToModule(FileContext *file_context, + LineToModuleHandler *line_reader, + WarningReporter *reporter) + : line_reader_(line_reader), + cu_context_(new CUContext(file_context, reporter)), + child_context_(new DIEContext()), + has_source_line_info_(false) { +} + +DwarfCUToModule::~DwarfCUToModule() { +} + +void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + switch (attr) { + case dwarf2reader::DW_AT_language: // source language of this CU + SetLanguage(static_cast(data)); + break; + default: + break; + } +} + +void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_stmt_list: // Line number information. + has_source_line_info_ = true; + source_line_offset_ = data; + break; + case dwarf2reader::DW_AT_language: // source language of this CU + SetLanguage(static_cast(data)); + break; + default: + break; + } +} + +void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string &data) { + switch (attr) { + case dwarf2reader::DW_AT_name: + cu_context_->reporter->SetCUName(data); + break; + case dwarf2reader::DW_AT_comp_dir: + line_reader_->StartCompilationUnit(data); + break; + default: + break; + } +} + +bool DwarfCUToModule::EndAttributes() { + return true; +} + +dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( + uint64 offset, + enum DwarfTag tag) { + switch (tag) { + case dwarf2reader::DW_TAG_subprogram: + return new FuncHandler(cu_context_.get(), child_context_.get(), offset); + case dwarf2reader::DW_TAG_namespace: + case dwarf2reader::DW_TAG_class_type: + case dwarf2reader::DW_TAG_structure_type: + case dwarf2reader::DW_TAG_union_type: + return new NamedScopeHandler(cu_context_.get(), child_context_.get(), + offset); + default: + return NULL; + } +} + +void DwarfCUToModule::SetLanguage(DwarfLanguage language) { + switch (language) { + case dwarf2reader::DW_LANG_Java: + cu_context_->language = Language::Java; + break; + + // DWARF has no generic language code for assembly language; this is + // what the GNU toolchain uses. + case dwarf2reader::DW_LANG_Mips_Assembler: + cu_context_->language = Language::Assembler; + break; + + // C++ covers so many cases that it probably has some way to cope + // with whatever the other languages throw at us. So make it the + // default. + // + // Objective C and Objective C++ seem to create entries for + // methods whose DW_AT_name values are already fully-qualified: + // "-[Classname method:]". These appear at the top level. + // + // DWARF data for C should never include namespaces or functions + // nested in struct types, but if it ever does, then C++'s + // notation is probably not a bad choice for that. + default: + case dwarf2reader::DW_LANG_ObjC: + case dwarf2reader::DW_LANG_ObjC_plus_plus: + case dwarf2reader::DW_LANG_C: + case dwarf2reader::DW_LANG_C89: + case dwarf2reader::DW_LANG_C99: + case dwarf2reader::DW_LANG_C_plus_plus: + cu_context_->language = Language::CPlusPlus; + break; + } +} + +void DwarfCUToModule::ReadSourceLines(uint64 offset) { + const dwarf2reader::SectionMap §ion_map + = cu_context_->file_context->section_map(); + dwarf2reader::SectionMap::const_iterator map_entry + = section_map.find(".debug_line"); + // Mac OS X puts DWARF data in sections whose names begin with "__" + // instead of ".". + if (map_entry == section_map.end()) + map_entry = section_map.find("__debug_line"); + if (map_entry == section_map.end()) { + cu_context_->reporter->MissingSection(".debug_line"); + return; + } + const char *section_start = map_entry->second.first; + uint64 section_length = map_entry->second.second; + if (offset >= section_length) { + cu_context_->reporter->BadLineInfoOffset(offset); + return; + } + line_reader_->ReadProgram(section_start + offset, section_length - offset, + cu_context_->file_context->module_, &lines_); +} + +namespace { +// Return true if ADDRESS falls within the range of ITEM. +template +inline bool within(const T &item, Module::Address address) { + // Because Module::Address is unsigned, and unsigned arithmetic + // wraps around, this will be false if ADDRESS falls before the + // start of ITEM, or if it falls after ITEM's end. + return address - item.address < item.size; +} +} + +void DwarfCUToModule::AssignLinesToFunctions() { + vector *functions = &cu_context_->functions; + WarningReporter *reporter = cu_context_->reporter; + + // This would be simpler if we assumed that source line entries + // don't cross function boundaries. However, there's no real reason + // to assume that (say) a series of function definitions on the same + // line wouldn't get coalesced into one line number entry. The + // DWARF spec certainly makes no such promises. + // + // So treat the functions and lines as peers, and take the trouble + // to compute their ranges' intersections precisely. In any case, + // the hair here is a constant factor for performance; the + // complexity from here on out is linear. + + // Put both our functions and lines in order by address. + std::sort(functions->begin(), functions->end(), + Module::Function::CompareByAddress); + std::sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress); + + // The last line that we used any piece of. We use this only for + // generating warnings. + const Module::Line *last_line_used = NULL; + + // The last function and line we warned about --- so we can avoid + // doing so more than once. + const Module::Function *last_function_cited = NULL; + const Module::Line *last_line_cited = NULL; + + // Make a single pass through both vectors from lower to higher + // addresses, populating each Function's lines vector with lines + // from our lines_ vector that fall within the function's address + // range. + vector::iterator func_it = functions->begin(); + vector::const_iterator line_it = lines_.begin(); + + Module::Address current; + + // Pointers to the referents of func_it and line_it, or NULL if the + // iterator is at the end of the sequence. + Module::Function *func; + const Module::Line *line; + + // Start current at the beginning of the first line or function, + // whichever is earlier. + if (func_it != functions->end() && line_it != lines_.end()) { + func = *func_it; + line = &*line_it; + current = std::min(func->address, line->address); + } else if (line_it != lines_.end()) { + func = NULL; + line = &*line_it; + current = line->address; + } else if (func_it != functions->end()) { + func = *func_it; + line = NULL; + current = (*func_it)->address; + } else { + return; + } + + while (func || line) { + // This loop has two invariants that hold at the top. + // + // First, at least one of the iterators is not at the end of its + // sequence, and those that are not refer to the earliest + // function or line that contains or starts after CURRENT. + // + // Note that every byte is in one of four states: it is covered + // or not covered by a function, and, independently, it is + // covered or not covered by a line. + // + // The second invariant is that CURRENT refers to a byte whose + // state is different from its predecessor, or it refers to the + // first byte in the address space. In other words, CURRENT is + // always the address of a transition. + // + // Note that, although each iteration advances CURRENT from one + // transition address to the next in each iteration, it might + // not advance the iterators. Suppose we have a function that + // starts with a line, has a gap, and then a second line, and + // suppose that we enter an iteration with CURRENT at the end of + // the first line. The next transition address is the start of + // the second line, after the gap, so the iteration should + // advance CURRENT to that point. At the head of that iteration, + // the invariants require that the line iterator be pointing at + // the second line. But this is also true at the head of the + // next. And clearly, the iteration must not change the function + // iterator. So neither iterator moves. + + // Assert the first invariant (see above). + assert(!func || current < func->address || within(*func, current)); + assert(!line || current < line->address || within(*line, current)); + + // The next transition after CURRENT. + Module::Address next_transition; + + // Figure out which state we're in, add lines or warn, and compute + // the next transition address. + if (func && current >= func->address) { + if (line && current >= line->address) { + // Covered by both a line and a function. + Module::Address func_left = func->size - (current - func->address); + Module::Address line_left = line->size - (current - line->address); + // This may overflow, but things work out. + next_transition = current + std::min(func_left, line_left); + Module::Line l = *line; + l.address = current; + l.size = next_transition - current; + func->lines.push_back(l); + last_line_used = line; + } else { + // Covered by a function, but no line. + if (func != last_function_cited) { + reporter->UncoveredFunction(*func); + last_function_cited = func; + } + if (line && within(*func, line->address)) + next_transition = line->address; + else + // If this overflows, we'll catch it below. + next_transition = func->address + func->size; + } + } else { + if (line && current >= line->address) { + // Covered by a line, but no function. + // + // If GCC emits padding after one function to align the start + // of the next, then it will attribute the padding + // instructions to the last source line of function (to reduce + // the size of the line number info), but omit it from the + // DW_AT_{low,high}_pc range given in .debug_info (since it + // costs nothing to be precise there). If we did use at least + // some of the line we're about to skip, and it ends at the + // start of the next function, then assume this is what + // happened, and don't warn. + if (line != last_line_cited + && !(func + && line == last_line_used + && func->address - line->address == line->size)) { + reporter->UncoveredLine(*line); + last_line_cited = line; + } + if (func && within(*line, func->address)) + next_transition = func->address; + else + // If this overflows, we'll catch it below. + next_transition = line->address + line->size; + } else { + // Covered by neither a function nor a line. By the invariant, + // both func and line begin after CURRENT. The next transition + // is the start of the next function or next line, whichever + // is earliest. + assert(func || line); + if (func && line) + next_transition = std::min(func->address, line->address); + else if (func) + next_transition = func->address; + else + next_transition = line->address; + } + } + + // If a function or line abuts the end of the address space, then + // next_transition may end up being zero, in which case we've completed + // our pass. Handle that here, instead of trying to deal with it in + // each place we compute next_transition. + if (!next_transition) + break; + + // Advance iterators as needed. If lines overlap or functions overlap, + // then we could go around more than once. We don't worry too much + // about what result we produce in that case, just as long as we don't + // hang or crash. + while (func_it != functions->end() + && next_transition >= (*func_it)->address + && !within(**func_it, next_transition)) + func_it++; + func = (func_it != functions->end()) ? *func_it : NULL; + while (line_it != lines_.end() + && next_transition >= line_it->address + && !within(*line_it, next_transition)) + line_it++; + line = (line_it != lines_.end()) ? &*line_it : NULL; + + // We must make progress. + assert(next_transition > current); + current = next_transition; + } +} + +void DwarfCUToModule::Finish() { + // Assembly language files have no function data, and that gives us + // no place to store our line numbers (even though the GNU toolchain + // will happily produce source line info for assembly language + // files). To avoid spurious warnings about lines we can't assign + // to functions, skip CUs in languages that lack functions. + if (!cu_context_->language->HasFunctions()) + return; + + // Read source line info, if we have any. + if (has_source_line_info_) + ReadSourceLines(source_line_offset_); + + vector *functions = &cu_context_->functions; + + // Dole out lines to the appropriate functions. + AssignLinesToFunctions(); + + // Add our functions, which now have source lines assigned to them, + // to module_. + cu_context_->file_context->module_->AddFunctions(functions->begin(), + functions->end()); + + // Ownership of the function objects has shifted from cu_context to + // the Module. + functions->clear(); + + cu_context_->file_context->ClearSpecifications(); +} + +bool DwarfCUToModule::StartCompilationUnit(uint64 offset, + uint8 address_size, + uint8 offset_size, + uint64 cu_length, + uint8 dwarf_version) { + return dwarf_version >= 2; +} + +bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag) { + // We don't deal with partial compilation units (the only other tag + // likely to be used for root DIE). + return tag == dwarf2reader::DW_TAG_compile_unit; +} + +} // namespace google_breakpad diff --git a/breakpad/common/dwarf_cu_to_module.h b/breakpad/common/dwarf_cu_to_module.h new file mode 100644 index 0000000000..ab95485fc7 --- /dev/null +++ b/breakpad/common/dwarf_cu_to_module.h @@ -0,0 +1,315 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// Add DWARF debugging information to a Breakpad symbol file. This +// file defines the DwarfCUToModule class, which accepts parsed DWARF +// data and populates a google_breakpad::Module with the results; the +// Module can then write its contents as a Breakpad symbol file. + +#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__ +#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__ + +#include + +#include "common/language.h" +#include "common/module.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2diehandler.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using dwarf2reader::DwarfAttribute; +using dwarf2reader::DwarfForm; +using dwarf2reader::DwarfLanguage; +using dwarf2reader::DwarfTag; + +// Populate a google_breakpad::Module with DWARF debugging information. +// +// An instance of this class can be provided as a handler to a +// dwarf2reader::DIEDispatcher, which can in turn be a handler for a +// dwarf2reader::CompilationUnit DWARF parser. The handler uses the results +// of parsing to populate a google_breakpad::Module with source file, +// function, and source line information. +class DwarfCUToModule: public dwarf2reader::RootDIEHandler { + struct FilePrivate; + public: + // Information global to the DWARF-bearing file we are processing, + // for use by DwarfCUToModule. Each DwarfCUToModule instance deals + // with a single compilation unit within the file, but information + // global to the whole file is held here. The client is responsible + // for filling it in appropriately (except for the 'file_private' + // field, which the constructor and destructor take care of), and + // then providing it to the DwarfCUToModule instance for each + // compilation unit we process in that file. Set HANDLE_INTER_CU_REFS + // to true to handle debugging symbols with DW_FORM_ref_addr entries. + class FileContext { + public: + FileContext(const string &filename, + Module *module, + bool handle_inter_cu_refs); + ~FileContext(); + + // Add CONTENTS of size LENGTH to the section map as NAME. + void AddSectionToSectionMap(const string& name, + const char* contents, + uint64 length); + + // Clear the section map for testing. + void ClearSectionMapForTest(); + + const dwarf2reader::SectionMap& section_map() const; + + private: + friend class DwarfCUToModule; + + // Clears all the Specifications if HANDLE_INTER_CU_REFS_ is false. + void ClearSpecifications(); + + // Given an OFFSET and a CU that starts at COMPILATION_UNIT_START, returns + // true if this is an inter-compilation unit reference that is not being + // handled. + bool IsUnhandledInterCUReference(uint64 offset, + uint64 compilation_unit_start) const; + + // The name of this file, for use in error messages. + const string filename_; + + // A map of this file's sections, used for finding other DWARF + // sections that the .debug_info section may refer to. + dwarf2reader::SectionMap section_map_; + + // The Module to which we're contributing definitions. + Module *module_; + + // True if we are handling references between compilation units. + const bool handle_inter_cu_refs_; + + // Inter-compilation unit data used internally by the handlers. + scoped_ptr file_private_; + }; + + // An abstract base class for handlers that handle DWARF line data + // for DwarfCUToModule. DwarfCUToModule could certainly just use + // dwarf2reader::LineInfo itself directly, but decoupling things + // this way makes unit testing a little easier. + class LineToModuleHandler { + public: + LineToModuleHandler() { } + virtual ~LineToModuleHandler() { } + + // Called at the beginning of a new compilation unit, prior to calling + // ReadProgram(). compilation_dir will indicate the path that the + // current compilation unit was compiled in, consistent with the + // DW_AT_comp_dir DIE. + virtual void StartCompilationUnit(const string& compilation_dir) = 0; + + // Populate MODULE and LINES with source file names and code/line + // mappings, given a pointer to some DWARF line number data + // PROGRAM, and an overestimate of its size. Add no zero-length + // lines to LINES. + virtual void ReadProgram(const char *program, uint64 length, + Module *module, vector *lines) = 0; + }; + + // The interface DwarfCUToModule uses to report warnings. The member + // function definitions for this class write messages to stderr, but + // you can override them if you'd like to detect or report these + // conditions yourself. + class WarningReporter { + public: + // Warn about problems in the DWARF file FILENAME, in the + // compilation unit at OFFSET. + WarningReporter(const string &filename, uint64 cu_offset) + : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false), + printed_unpaired_header_(false), + uncovered_warnings_enabled_(false) { } + virtual ~WarningReporter() { } + + // Set the name of the compilation unit we're processing to NAME. + virtual void SetCUName(const string &name) { cu_name_ = name; } + + // Accessor and setter for uncovered_warnings_enabled_. + // UncoveredFunction and UncoveredLine only report a problem if that is + // true. By default, these warnings are disabled, because those + // conditions occur occasionally in healthy code. + virtual bool uncovered_warnings_enabled() const { + return uncovered_warnings_enabled_; + } + virtual void set_uncovered_warnings_enabled(bool value) { + uncovered_warnings_enabled_ = value; + } + + // A DW_AT_specification in the DIE at OFFSET refers to a DIE we + // haven't processed yet, or that wasn't marked as a declaration, + // at TARGET. + virtual void UnknownSpecification(uint64 offset, uint64 target); + + // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we + // haven't processed yet, or that wasn't marked as inline, at TARGET. + virtual void UnknownAbstractOrigin(uint64 offset, uint64 target); + + // We were unable to find the DWARF section named SECTION_NAME. + virtual void MissingSection(const string §ion_name); + + // The CU's DW_AT_stmt_list offset OFFSET is bogus. + virtual void BadLineInfoOffset(uint64 offset); + + // FUNCTION includes code covered by no line number data. + virtual void UncoveredFunction(const Module::Function &function); + + // Line number NUMBER in LINE_FILE, of length LENGTH, includes code + // covered by no function. + virtual void UncoveredLine(const Module::Line &line); + + // The DW_TAG_subprogram DIE at OFFSET has no name specified directly + // in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin + // link. + virtual void UnnamedFunction(uint64 offset); + + // The DW_FORM_ref_addr at OFFSET to TARGET was not handled because + // FilePrivate did not retain the inter-CU specification data. + virtual void UnhandledInterCUReference(uint64 offset, uint64 target); + + uint64 cu_offset() const { + return cu_offset_; + } + + protected: + const string filename_; + const uint64 cu_offset_; + string cu_name_; + bool printed_cu_header_; + bool printed_unpaired_header_; + bool uncovered_warnings_enabled_; + + private: + // Print a per-CU heading, once. + void CUHeading(); + // Print an unpaired function/line heading, once. + void UncoveredHeading(); + }; + + // Create a DWARF debugging info handler for a compilation unit + // within FILE_CONTEXT. This uses information received from the + // dwarf2reader::CompilationUnit DWARF parser to populate + // FILE_CONTEXT->module. Use LINE_READER to handle the compilation + // unit's line number data. Use REPORTER to report problems with the + // data we find. + DwarfCUToModule(FileContext *file_context, + LineToModuleHandler *line_reader, + WarningReporter *reporter); + ~DwarfCUToModule(); + + void ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data); + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + void ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string &data); + bool EndAttributes(); + DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag); + + // Assign all our source Lines to the Functions that cover their + // addresses, and then add them to module_. + void Finish(); + + bool StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version); + bool StartRootDIE(uint64 offset, enum DwarfTag tag); + + private: + // Used internally by the handler. Full definitions are in + // dwarf_cu_to_module.cc. + struct CUContext; + struct DIEContext; + struct Specification; + class GenericDIEHandler; + class FuncHandler; + class NamedScopeHandler; + + // A map from section offsets to specifications. + typedef map SpecificationByOffset; + + // Set this compilation unit's source language to LANGUAGE. + void SetLanguage(DwarfLanguage language); + + // Read source line information at OFFSET in the .debug_line + // section. Record source files in module_, but record source lines + // in lines_; we apportion them to functions in + // AssignLinesToFunctions. + void ReadSourceLines(uint64 offset); + + // Assign the lines in lines_ to the individual line lists of the + // functions in functions_. (DWARF line information maps an entire + // compilation unit at a time, and gives no indication of which + // lines belong to which functions, beyond their addresses.) + void AssignLinesToFunctions(); + + // The only reason cu_context_ and child_context_ are pointers is + // that we want to keep their definitions private to + // dwarf_cu_to_module.cc, instead of listing them all here. They are + // owned by this DwarfCUToModule: the constructor sets them, and the + // destructor deletes them. + + // The handler to use to handle line number data. + LineToModuleHandler *line_reader_; + + // This compilation unit's context. + scoped_ptr cu_context_; + + // A context for our children. + scoped_ptr child_context_; + + // True if this compilation unit has source line information. + bool has_source_line_info_; + + // The offset of this compilation unit's line number information in + // the .debug_line section. + uint64 source_line_offset_; + + // The line numbers we have seen thus far. We accumulate these here + // during parsing. Then, in Finish, we call AssignLinesToFunctions + // to dole them out to the appropriate functions. + vector lines_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__ diff --git a/breakpad/common/dwarf_cu_to_module_unittest.cc b/breakpad/common/dwarf_cu_to_module_unittest.cc new file mode 100644 index 0000000000..5f61a58e9a --- /dev/null +++ b/breakpad/common/dwarf_cu_to_module_unittest.cc @@ -0,0 +1,1780 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf_cu_to_module.h" +#include "common/using_std_string.h" + +using std::make_pair; +using std::vector; + +using dwarf2reader::DIEHandler; +using dwarf2reader::DwarfTag; +using dwarf2reader::DwarfAttribute; +using dwarf2reader::DwarfForm; +using dwarf2reader::DwarfInline; +using dwarf2reader::RootDIEHandler; +using google_breakpad::DwarfCUToModule; +using google_breakpad::Module; + +using ::testing::_; +using ::testing::AtMost; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::Test; +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::ValuesIn; + +// Mock classes. + +class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler { + public: + MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir)); + MOCK_METHOD4(ReadProgram, void(const char* program, uint64 length, + Module *module, vector *lines)); +}; + +class MockWarningReporter: public DwarfCUToModule::WarningReporter { + public: + MockWarningReporter(const string &filename, uint64 cu_offset) + : DwarfCUToModule::WarningReporter(filename, cu_offset) { } + MOCK_METHOD1(SetCUName, void(const string &name)); + MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target)); + MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target)); + MOCK_METHOD1(MissingSection, void(const string §ion_name)); + MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset)); + MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); + MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); + MOCK_METHOD1(UnnamedFunction, void(uint64 offset)); + MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target)); +}; + +// A fixture class including all the objects needed to handle a +// compilation unit, and their entourage. It includes member functions +// for doing common kinds of setup and tests. +class CUFixtureBase { + public: + // If we have: + // + // vector lines; + // AppendLinesFunctor appender(lines); + // + // then doing: + // + // appender(line_program, length, module, line_vector); + // + // will append lines to the end of line_vector. We can use this with + // MockLineToModuleHandler like this: + // + // MockLineToModuleHandler l2m; + // EXPECT_CALL(l2m, ReadProgram(_,_,_,_)) + // .WillOnce(DoAll(Invoke(appender), Return())); + // + // in which case calling l2m with some line vector will append lines. + class AppendLinesFunctor { + public: + explicit AppendLinesFunctor( + const vector *lines) : lines_(lines) { } + void operator()(const char *program, uint64 length, + Module *module, vector *lines) { + lines->insert(lines->end(), lines_->begin(), lines_->end()); + } + private: + const vector *lines_; + }; + + CUFixtureBase() + : module_("module-name", "module-os", "module-arch", "module-id"), + file_context_("dwarf-filename", &module_, true), + language_(dwarf2reader::DW_LANG_none), + language_signed_(false), + appender_(&lines_), + reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), + root_handler_(&file_context_, &line_reader_, &reporter_), + functions_filled_(false) { + // By default, expect no warnings to be reported, and expect the + // compilation unit's name to be provided. The test can override + // these expectations. + EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1); + EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0); + EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0); + EXPECT_CALL(reporter_, MissingSection(_)).Times(0); + EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0); + EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0); + EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0); + EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0); + + // By default, expect the line program reader not to be invoked. We + // may override this in StartCU. + EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0); + EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0); + + // The handler will consult this section map to decide what to + // pass to our line reader. + file_context_.AddSectionToSectionMap(".debug_line", + dummy_line_program_, + dummy_line_size_); + } + + // Add a line with the given address, size, filename, and line + // number to the end of the statement list the handler will receive + // when it invokes its LineToModuleHandler. Call this before calling + // StartCU. + void PushLine(Module::Address address, Module::Address size, + const string &filename, int line_number); + + // Use LANGUAGE for the compilation unit. More precisely, arrange + // for StartCU to pass the compilation unit's root DIE a + // DW_AT_language attribute whose value is LANGUAGE. + void SetLanguage(dwarf2reader::DwarfLanguage language) { + language_ = language; + } + + // If SIGNED true, have StartCU report DW_AT_language as a signed + // attribute; if false, have it report it as unsigned. + void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; } + + // Call the handler this.root_handler_'s StartCompilationUnit and + // StartRootDIE member functions, passing it appropriate attributes as + // determined by prior calls to PushLine and SetLanguage. Leave + // this.root_handler_ ready to hear about children: call + // this.root_handler_.EndAttributes, but not this.root_handler_.Finish. + void StartCU(); + + // Have HANDLER process some strange attribute/form/value triples. + void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler); + + // Start a child DIE of PARENT with the given tag and name. Leave + // the handler ready to hear about children: call EndAttributes, but + // not Finish. + DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, + const string &name); + + // Start a child DIE of PARENT with the given tag and a + // DW_AT_specification attribute whose value is SPECIFICATION. Leave + // the handler ready to hear about children: call EndAttributes, but + // not Finish. If NAME is non-zero, use it as the DW_AT_name + // attribute. + DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, + uint64 specification, const char *name = NULL); + + // Define a function as a child of PARENT with the given name, address, and + // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute + // will be written as an address; otherwise it will be written as the + // function's size. Call EndAttributes and Finish; one cannot define + // children of the defined function's DIE. + void DefineFunction(DIEHandler *parent, const string &name, + Module::Address address, Module::Address size, + const char* mangled_name, + DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr); + + // Create a declaration DIE as a child of PARENT with the given + // offset, tag and name. If NAME is the empty string, don't provide + // a DW_AT_name attribute. Call EndAttributes and Finish. + void DeclarationDIE(DIEHandler *parent, uint64 offset, + DwarfTag tag, const string &name, + const string &mangled_name); + + // Create a definition DIE as a child of PARENT with the given tag + // that refers to the declaration DIE at offset SPECIFICATION as its + // specification. If NAME is non-empty, pass it as the DW_AT_name + // attribute. If SIZE is non-zero, record ADDRESS and SIZE as + // low_pc/high_pc attributes. + void DefinitionDIE(DIEHandler *parent, DwarfTag tag, + uint64 specification, const string &name, + Module::Address address = 0, Module::Address size = 0); + + // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If + // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at + // offset SPECIFICATION as its specification. If Name is non-empty, pass it + // as the DW_AT_name attribute. + void AbstractInstanceDIE(DIEHandler *parent, uint64 offset, + DwarfInline type, uint64 specification, + const string &name, + DwarfForm form = dwarf2reader::DW_FORM_data1); + + // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to + // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty + // string, don't provide a DW_AT_name attribute. + void DefineInlineInstanceDIE(DIEHandler *parent, const string &name, + uint64 origin, Module::Address address, + Module::Address size); + + // The following Test* functions should be called after calling + // this.root_handler_.Finish. After that point, no further calls + // should be made on the handler. + + // Test that the number of functions defined in the module this.module_ is + // equal to EXPECTED. + void TestFunctionCount(size_t expected); + + // Test that the I'th function (ordered by address) in the module + // this.module_ has the given name, address, and size, and that its + // parameter size is zero. + void TestFunction(int i, const string &name, + Module::Address address, Module::Address size); + + // Test that the number of source lines owned by the I'th function + // in the module this.module_ is equal to EXPECTED. + void TestLineCount(int i, size_t expected); + + // Test that the J'th line (ordered by address) of the I'th function + // (again, by address) has the given address, size, filename, and + // line number. + void TestLine(int i, int j, Module::Address address, Module::Address size, + const string &filename, int number); + + // Actual objects under test. + Module module_; + DwarfCUToModule::FileContext file_context_; + + // If this is not DW_LANG_none, we'll pass it as a DW_AT_language + // attribute to the compilation unit. This defaults to DW_LANG_none. + dwarf2reader::DwarfLanguage language_; + + // If this is true, report DW_AT_language as a signed value; if false, + // report it as an unsigned value. + bool language_signed_; + + // If this is not empty, we'll give the CU a DW_AT_comp_dir attribute that + // indicates the path that this compilation unit was compiled in. + string compilation_dir_; + + // If this is not empty, we'll give the CU a DW_AT_stmt_list + // attribute that, when passed to line_reader_, adds these lines to the + // provided lines array. + vector lines_; + + // Mock line program reader. + MockLineToModuleHandler line_reader_; + AppendLinesFunctor appender_; + static const char dummy_line_program_[]; + static const size_t dummy_line_size_; + + MockWarningReporter reporter_; + DwarfCUToModule root_handler_; + + private: + // Fill functions_, if we haven't already. + void FillFunctions(); + + // If functions_filled_ is true, this is a table of functions we've + // extracted from module_, sorted by address. + vector functions_; + // True if we have filled the above vector with this.module_'s function list. + bool functions_filled_; +}; + +const char CUFixtureBase::dummy_line_program_[] = "lots of fun data"; +const size_t CUFixtureBase::dummy_line_size_ = + sizeof(CUFixtureBase::dummy_line_program_); + +void CUFixtureBase::PushLine(Module::Address address, Module::Address size, + const string &filename, int line_number) { + Module::Line l; + l.address = address; + l.size = size; + l.file = module_.FindFile(filename); + l.number = line_number; + lines_.push_back(l); +} + +void CUFixtureBase::StartCU() { + if (!compilation_dir_.empty()) + EXPECT_CALL(line_reader_, + StartCompilationUnit(compilation_dir_)).Times(1); + + // If we have lines, make the line reader expect to be invoked at + // most once. (Hey, if the handler can pass its tests without + // bothering to read the line number data, that's great.) + // Have it add the lines passed to PushLine. Otherwise, leave the + // initial expectation (no calls) in force. + if (!lines_.empty()) + EXPECT_CALL(line_reader_, + ReadProgram(&dummy_line_program_[0], dummy_line_size_, + &module_, _)) + .Times(AtMost(1)) + .WillOnce(DoAll(Invoke(appender_), Return())); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44, + 0x4241b4f33720dd5cULL, 3)); + { + ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, + dwarf2reader::DW_TAG_compile_unit)); + } + root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + "compilation-unit-name"); + if (!compilation_dir_.empty()) + root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir, + dwarf2reader::DW_FORM_strp, + compilation_dir_); + if (!lines_.empty()) + root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, + dwarf2reader::DW_FORM_ref4, + 0); + if (language_ != dwarf2reader::DW_LANG_none) { + if (language_signed_) + root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language, + dwarf2reader::DW_FORM_sdata, + language_); + else + root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language, + dwarf2reader::DW_FORM_udata, + language_); + } + ASSERT_TRUE(root_handler_.EndAttributes()); +} + +void CUFixtureBase::ProcessStrangeAttributes( + dwarf2reader::DIEHandler *handler) { + handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead, + (DwarfForm) 0x4106e4db, + 0xa592571997facda1ULL); + handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095, + (DwarfForm) 0x0f16fe87, + 0x12602a4e3bf1f446LL); + handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f, + (DwarfForm) 0x829e038a, + 0x50fddef44734fdecULL); + static const char buffer[10] = "frobynode"; + handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51, + (DwarfForm) 0x2f43b041, + buffer, sizeof(buffer)); + handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041, + (DwarfForm) 0x895ffa23, + "strange string"); +} + +DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, + DwarfTag tag, + const string &name) { + dwarf2reader::DIEHandler *handler + = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); + if (!handler) + return NULL; + handler->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + ProcessStrangeAttributes(handler); + if (!handler->EndAttributes()) { + handler->Finish(); + delete handler; + return NULL; + } + + return handler; +} + +DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, + DwarfTag tag, + uint64 specification, + const char *name) { + dwarf2reader::DIEHandler *handler + = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); + if (!handler) + return NULL; + if (name) + handler->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification, + dwarf2reader::DW_FORM_ref4, + specification); + if (!handler->EndAttributes()) { + handler->Finish(); + delete handler; + return NULL; + } + + return handler; +} + +void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, + const string &name, Module::Address address, + Module::Address size, + const char* mangled_name, + DwarfForm high_pc_form) { + dwarf2reader::DIEHandler *func + = parent->FindChildHandler(0xe34797c7e68590a8LL, + dwarf2reader::DW_TAG_subprogram); + ASSERT_TRUE(func != NULL); + func->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + address); + + Module::Address high_pc = size; + if (high_pc_form == dwarf2reader::DW_FORM_addr) { + high_pc += address; + } + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + high_pc_form, + high_pc); + + if (mangled_name) + func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, + dwarf2reader::DW_FORM_strp, + mangled_name); + + ProcessStrangeAttributes(func); + EXPECT_TRUE(func->EndAttributes()); + func->Finish(); + delete func; +} + +void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset, + DwarfTag tag, + const string &name, + const string &mangled_name) { + dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag); + ASSERT_TRUE(die != NULL); + if (!name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + if (!mangled_name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, + dwarf2reader::DW_FORM_strp, + mangled_name); + + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration, + dwarf2reader::DW_FORM_flag, + 1); + EXPECT_TRUE(die->EndAttributes()); + die->Finish(); + delete die; +} + +void CUFixtureBase::DefinitionDIE(DIEHandler *parent, + DwarfTag tag, + uint64 specification, + const string &name, + Module::Address address, + Module::Address size) { + dwarf2reader::DIEHandler *die + = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag); + ASSERT_TRUE(die != NULL); + die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, + dwarf2reader::DW_FORM_ref4, + specification); + if (!name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + if (size) { + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + address); + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + dwarf2reader::DW_FORM_addr, + address + size); + } + EXPECT_TRUE(die->EndAttributes()); + die->Finish(); + delete die; +} + +void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, + uint64 offset, + DwarfInline type, + uint64 specification, + const string &name, + DwarfForm form) { + dwarf2reader::DIEHandler *die + = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram); + ASSERT_TRUE(die != NULL); + if (specification != 0ULL) + die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, + dwarf2reader::DW_FORM_ref4, + specification); + if (form == dwarf2reader::DW_FORM_sdata) { + die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type); + } else { + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type); + } + if (!name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + + EXPECT_TRUE(die->EndAttributes()); + die->Finish(); + delete die; +} + +void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, + const string &name, + uint64 origin, + Module::Address address, + Module::Address size) { + dwarf2reader::DIEHandler *func + = parent->FindChildHandler(0x11c70f94c6e87ccdLL, + dwarf2reader::DW_TAG_subprogram); + ASSERT_TRUE(func != NULL); + if (!name.empty()) { + func->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + } + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + address); + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + dwarf2reader::DW_FORM_addr, + address + size); + func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin, + dwarf2reader::DW_FORM_ref4, + origin); + ProcessStrangeAttributes(func); + EXPECT_TRUE(func->EndAttributes()); + func->Finish(); + delete func; +} + +void CUFixtureBase::FillFunctions() { + if (functions_filled_) + return; + module_.GetFunctions(&functions_, functions_.end()); + sort(functions_.begin(), functions_.end(), + Module::Function::CompareByAddress); + functions_filled_ = true; +} + +void CUFixtureBase::TestFunctionCount(size_t expected) { + FillFunctions(); + ASSERT_EQ(expected, functions_.size()); +} + +void CUFixtureBase::TestFunction(int i, const string &name, + Module::Address address, + Module::Address size) { + FillFunctions(); + ASSERT_LT((size_t) i, functions_.size()); + + Module::Function *function = functions_[i]; + EXPECT_EQ(name, function->name); + EXPECT_EQ(address, function->address); + EXPECT_EQ(size, function->size); + EXPECT_EQ(0U, function->parameter_size); +} + +void CUFixtureBase::TestLineCount(int i, size_t expected) { + FillFunctions(); + ASSERT_LT((size_t) i, functions_.size()); + + ASSERT_EQ(expected, functions_[i]->lines.size()); +} + +void CUFixtureBase::TestLine(int i, int j, + Module::Address address, Module::Address size, + const string &filename, int number) { + FillFunctions(); + ASSERT_LT((size_t) i, functions_.size()); + ASSERT_LT((size_t) j, functions_[i]->lines.size()); + + Module::Line *line = &functions_[i]->lines[j]; + EXPECT_EQ(address, line->address); + EXPECT_EQ(size, line->size); + EXPECT_EQ(filename, line->file->name.c_str()); + EXPECT_EQ(number, line->number); +} + +// Include caller locations for our test subroutines. +#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0) +#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) +#define SetLanguage(a) TRACE(SetLanguage(a)) +#define StartCU() TRACE(StartCU()) +#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e))) +// (DefineFunction) instead of DefineFunction to avoid macro expansion. +#define DefineFunction6(a,b,c,d,e,f) \ + TRACE((DefineFunction)((a),(b),(c),(d),(e),(f))) +#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e))) +#define DefinitionDIE(a,b,c,d,e,f) \ + TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) +#define TestFunctionCount(a) TRACE(TestFunctionCount(a)) +#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) +#define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) +#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) + +class SimpleCU: public CUFixtureBase, public Test { +}; + +TEST_F(SimpleCU, CompilationDir) { + compilation_dir_ = "/src/build/"; + + StartCU(); + root_handler_.Finish(); +} + +TEST_F(SimpleCU, OneFunc) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); + TestLineCount(0, 1); + TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", + 246571772); +} + +// As above, only DW_AT_high_pc is a length rather than an address. +TEST_F(SimpleCU, OneFuncHighPcIsLength) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction6(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL, + dwarf2reader::DW_FORM_udata); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); + TestLineCount(0, 1); + TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", + 246571772); +} + +TEST_F(SimpleCU, MangledName) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "_ZN1n1fEi"); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "n::f(int)", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); +} + +TEST_F(SimpleCU, IrrelevantRootChildren) { + StartCU(); + EXPECT_FALSE(root_handler_ + .FindChildHandler(0x7db32bff4e2dcfb1ULL, + dwarf2reader::DW_TAG_lexical_block)); +} + +TEST_F(SimpleCU, IrrelevantNamedScopeChildren) { + StartCU(); + DIEHandler *class_A_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + EXPECT_TRUE(class_A_handler != NULL); + EXPECT_FALSE(class_A_handler + ->FindChildHandler(0x02e55999b865e4e9ULL, + dwarf2reader::DW_TAG_lexical_block)); + delete class_A_handler; +} + +// Verify that FileContexts can safely be deleted unused. +TEST_F(SimpleCU, UnusedFileContext) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); +} + +TEST_F(SimpleCU, InlineFunction) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0, "inline-name"); + DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "inline-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +TEST_F(SimpleCU, InlineFunctionSignedAttribute) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0, "inline-name", + dwarf2reader::DW_FORM_sdata); + DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "inline-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +// Any DIE with an DW_AT_inline attribute can be cited by +// DW_AT_abstract_origin attributes --- even if the value of the +// DW_AT_inline attribute is DW_INL_not_inlined. +TEST_F(SimpleCU, AbstractOriginNotInlined) { + PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL, + dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance"); + DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL, + 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "abstract-instance", + 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); +} + +TEST_F(SimpleCU, UnknownAbstractOrigin) { + EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return()); + EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL)) + .WillOnce(Return()); + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0, "inline-name"); + DefineInlineInstanceDIE(&root_handler_, "", 1ULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +TEST_F(SimpleCU, UnnamedFunction) { + EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL)) + .WillOnce(Return()); + PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850); + + StartCU(); + DefineFunction(&root_handler_, "", + 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "", + 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL); +} + +// An address range. +struct Range { + Module::Address start, end; +}; + +// Test data for pairing functions and lines. +struct Situation { + // Two function intervals, and two line intervals. + Range functions[2], lines[2]; + + // The number of lines we expect to be assigned to each of the + // functions, and the address ranges. + int paired_count[2]; + Range paired[2][2]; + + // The number of functions that are not entirely covered by lines, + // and vice versa. + int uncovered_functions, uncovered_lines; +}; + +#define PAIRING(func1_start, func1_end, func2_start, func2_end, \ + line1_start, line1_end, line2_start, line2_end, \ + func1_num_lines, func2_num_lines, \ + func1_line1_start, func1_line1_end, \ + func1_line2_start, func1_line2_end, \ + func2_line1_start, func2_line1_end, \ + func2_line2_start, func2_line2_end, \ + uncovered_functions, uncovered_lines) \ + { { { func1_start, func1_end }, { func2_start, func2_end } }, \ + { { line1_start, line1_end }, { line2_start, line2_end } }, \ + { func1_num_lines, func2_num_lines }, \ + { { { func1_line1_start, func1_line1_end }, \ + { func1_line2_start, func1_line2_end } }, \ + { { func2_line1_start, func2_line1_end }, \ + { func2_line2_start, func2_line2_end } } }, \ + uncovered_functions, uncovered_lines }, + +Situation situations[] = { +#include "common/testdata/func-line-pairing.h" +}; + +#undef PAIRING + +class FuncLinePairing: public CUFixtureBase, + public TestWithParam { }; + +INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing, + ValuesIn(situations)); + +TEST_P(FuncLinePairing, Pairing) { + const Situation &s = GetParam(); + PushLine(s.lines[0].start, + s.lines[0].end - s.lines[0].start, + "line-file", 67636963); + PushLine(s.lines[1].start, + s.lines[1].end - s.lines[1].start, + "line-file", 67636963); + if (s.uncovered_functions) + EXPECT_CALL(reporter_, UncoveredFunction(_)) + .Times(s.uncovered_functions) + .WillRepeatedly(Return()); + if (s.uncovered_lines) + EXPECT_CALL(reporter_, UncoveredLine(_)) + .Times(s.uncovered_lines) + .WillRepeatedly(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", + s.functions[0].start, + s.functions[0].end - s.functions[0].start, NULL); + DefineFunction(&root_handler_, "function2", + s.functions[1].start, + s.functions[1].end - s.functions[1].start, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", + s.functions[0].start, + s.functions[0].end - s.functions[0].start); + TestLineCount(0, s.paired_count[0]); + for (int i = 0; i < s.paired_count[0]; i++) + TestLine(0, i, s.paired[0][i].start, + s.paired[0][i].end - s.paired[0][i].start, + "line-file", 67636963); + TestFunction(1, "function2", + s.functions[1].start, + s.functions[1].end - s.functions[1].start); + TestLineCount(1, s.paired_count[1]); + for (int i = 0; i < s.paired_count[1]; i++) + TestLine(1, i, s.paired[1][i].start, + s.paired[1][i].end - s.paired[1][i].start, + "line-file", 67636963); +} + +TEST_F(FuncLinePairing, EmptyCU) { + StartCU(); + root_handler_.Finish(); + + TestFunctionCount(0); +} + +TEST_F(FuncLinePairing, LinesNoFuncs) { + PushLine(40, 2, "line-file", 82485646); + EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); + + StartCU(); + root_handler_.Finish(); + + TestFunctionCount(0); +} + +TEST_F(FuncLinePairing, FuncsNoLines) { + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U, + NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U); +} + +TEST_F(FuncLinePairing, GapThenFunction) { + PushLine(20, 2, "line-file-2", 174314698); + PushLine(10, 2, "line-file-1", 263008005); + + StartCU(); + DefineFunction(&root_handler_, "function1", 10, 2, NULL); + DefineFunction(&root_handler_, "function2", 20, 2, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 10, 2); + TestLineCount(0, 1); + TestLine(0, 0, 10, 2, "line-file-1", 263008005); + TestFunction(1, "function2", 20, 2); + TestLineCount(1, 1); + TestLine(1, 0, 20, 2, "line-file-2", 174314698); +} + +// If GCC emits padding after one function to align the start of +// the next, then it will attribute the padding instructions to +// the last source line of function (to reduce the size of the +// line number info), but omit it from the DW_AT_{low,high}_pc +// range given in .debug_info (since it costs nothing to be +// precise there). If we did use at least some of the line +// we're about to skip, then assume this is what happened, and +// don't warn. +TEST_F(FuncLinePairing, GCCAlignmentStretch) { + PushLine(10, 10, "line-file", 63351048); + PushLine(20, 10, "line-file", 61661044); + + StartCU(); + DefineFunction(&root_handler_, "function1", 10, 5, NULL); + // five-byte gap between functions, covered by line 63351048. + // This should not elicit a warning. + DefineFunction(&root_handler_, "function2", 20, 10, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 10, 5); + TestLineCount(0, 1); + TestLine(0, 0, 10, 5, "line-file", 63351048); + TestFunction(1, "function2", 20, 10); + TestLineCount(1, 1); + TestLine(1, 0, 20, 10, "line-file", 61661044); +} + +// Unfortunately, neither the DWARF parser's handler interface nor the +// DIEHandler interface is capable of expressing a function that abuts +// the end of the address space: the high_pc value looks like zero. + +TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) { + PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048); + EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL); + DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6); + TestLineCount(0, 1); + TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048); + TestFunction(1, "function2", 0xfffffffffffffffaULL, 5); + TestLineCount(1, 1); + TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048); +} + +// A function with more than one uncovered area should only be warned +// about once. +TEST_F(FuncLinePairing, WarnOnceFunc) { + PushLine(20, 1, "line-file-2", 262951329); + PushLine(11, 1, "line-file-1", 219964021); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function", 10, 11, NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function", 10, 11); + TestLineCount(0, 2); + TestLine(0, 0, 11, 1, "line-file-1", 219964021); + TestLine(0, 1, 20, 1, "line-file-2", 262951329); +} + +// A line with more than one uncovered area should only be warned +// about once. +TEST_F(FuncLinePairing, WarnOnceLine) { + PushLine(10, 20, "filename1", 118581871); + EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", 11, 1, NULL); + DefineFunction(&root_handler_, "function2", 13, 1, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 11, 1); + TestLineCount(0, 1); + TestLine(0, 0, 11, 1, "filename1", 118581871); + TestFunction(1, "function2", 13, 1); + TestLineCount(1, 1); + TestLine(1, 0, 13, 1, "filename1", 118581871); +} + +class CXXQualifiedNames: public CUFixtureBase, + public TestWithParam { }; + +INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames, + Values(dwarf2reader::DW_TAG_class_type, + dwarf2reader::DW_TAG_structure_type, + dwarf2reader::DW_TAG_union_type, + dwarf2reader::DW_TAG_namespace)); + +TEST_P(CXXQualifiedNames, TwoFunctions) { + DwarfTag tag = GetParam(); + + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + PushLine(10, 1, "filename1", 69819327); + PushLine(20, 1, "filename2", 95115701); + + StartCU(); + DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag, + "Enclosure"); + EXPECT_TRUE(enclosure_handler != NULL); + DefineFunction(enclosure_handler, "func_B", 10, 1, NULL); + DefineFunction(enclosure_handler, "func_C", 20, 1, NULL); + enclosure_handler->Finish(); + delete enclosure_handler; + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "Enclosure::func_B", 10, 1); + TestFunction(1, "Enclosure::func_C", 20, 1); +} + +TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { + DwarfTag tag = GetParam(); + + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + PushLine(10, 1, "line-file", 69819327); + + StartCU(); + DIEHandler *namespace_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "Namespace"); + EXPECT_TRUE(namespace_handler != NULL); + DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, + "Enclosure"); + EXPECT_TRUE(enclosure_handler != NULL); + DefineFunction(enclosure_handler, "function", 10, 1, NULL); + enclosure_handler->Finish(); + delete enclosure_handler; + namespace_handler->Finish(); + delete namespace_handler; + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "Namespace::Enclosure::function", 10, 1); +} + +TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + PushLine(10, 1, "filename1", 69819327); + + StartCU(); + DIEHandler *namespace_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "namespace_A"); + EXPECT_TRUE(namespace_handler != NULL); + DIEHandler *struct_handler + = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, + "struct_B"); + EXPECT_TRUE(struct_handler != NULL); + DIEHandler *class_handler + = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, + "class_C"); + DefineFunction(class_handler, "function_D", 10, 1, NULL); + class_handler->Finish(); + delete class_handler; + struct_handler->Finish(); + delete struct_handler; + namespace_handler->Finish(); + delete namespace_handler; + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1); +} + +struct LanguageAndQualifiedName { + dwarf2reader::DwarfLanguage language; + const char *name; +}; + +const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { + { dwarf2reader::DW_LANG_none, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C89, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C99, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" }, + { dwarf2reader::DW_LANG_Java, "class_A.function_B" }, + { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" }, + { dwarf2reader::DW_LANG_Mips_Assembler, NULL } +}; + +class QualifiedForLanguage + : public CUFixtureBase, + public TestWithParam { }; + +INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, + ValuesIn(LanguageAndQualifiedNameCases)); + +TEST_P(QualifiedForLanguage, MemberFunction) { + const LanguageAndQualifiedName ¶m = GetParam(); + + PushLine(10, 1, "line-file", 212966758); + SetLanguage(param.language); + + StartCU(); + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "class_A"); + DefineFunction(class_handler, "function_B", 10, 1, NULL); + class_handler->Finish(); + delete class_handler; + root_handler_.Finish(); + + if (param.name) { + TestFunctionCount(1); + TestFunction(0, param.name, 10, 1); + } else { + TestFunctionCount(0); + } +} + +TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { + const LanguageAndQualifiedName ¶m = GetParam(); + + PushLine(10, 1, "line-file", 212966758); + SetLanguage(param.language); + SetLanguageSigned(true); + + StartCU(); + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "class_A"); + DefineFunction(class_handler, "function_B", 10, 1, NULL); + class_handler->Finish(); + delete class_handler; + root_handler_.Finish(); + + if (param.name) { + TestFunctionCount(1); + TestFunction(0, param.name, 10, 1); + } else { + TestFunctionCount(0); + } +} + +class Specifications: public CUFixtureBase, public Test { }; + +TEST_F(Specifications, Function) { + PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); + + StartCU(); + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xcd3c51b946fb1eeeLL, "", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "declaration-name", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); +} + +TEST_F(Specifications, MangledName) { + PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); + + StartCU(); + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", + "_ZN1C1fEi"); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xcd3c51b946fb1eeeLL, "", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "C::f(int)", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); +} + +TEST_F(Specifications, MemberFunction) { + PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691); + + StartCU(); + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + DeclarationDIE(class_handler, 0x7d83028c431406e8ULL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + class_handler->Finish(); + delete class_handler; + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x7d83028c431406e8ULL, "", + 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "class_A::declaration-name", + 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); +} + +// This case should gather the name from both the definition and the +// declaration's parent. +TEST_F(Specifications, FunctionDeclarationParent) { + PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922); + + StartCU(); + { + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "class_A"); + ASSERT_TRUE(class_handler != NULL); + DeclarationDIE(class_handler, 0x0e0e877c8404544aULL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + class_handler->Finish(); + delete class_handler; + } + + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x0e0e877c8404544aULL, "definition-name", + 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); + + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "class_A::definition-name", + 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); +} + +// Named scopes should also gather enclosing name components from +// their declarations. +TEST_F(Specifications, NamedScopeDeclarationParent) { + PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604); + + StartCU(); + { + DIEHandler *space_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "space_A"); + ASSERT_TRUE(space_handler != NULL); + DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL, + dwarf2reader::DW_TAG_class_type, "class-declaration-name", + ""); + space_handler->Finish(); + delete space_handler; + } + + { + DIEHandler *class_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + 0x419bb1d12f9a73a2ULL, "class-definition-name"); + ASSERT_TRUE(class_handler != NULL); + DefineFunction(class_handler, "function", + 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL); + class_handler->Finish(); + delete class_handler; + } + + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "space_A::class-definition-name::function", + 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); +} + +// This test recreates bug 364. +TEST_F(Specifications, InlineFunction) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "inline-name", ""); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); + DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "inline-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +// Check name construction for a long chain containing each combination of: +// - struct, union, class, namespace +// - direct and definition +TEST_F(Specifications, LongChain) { + PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926); + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + + StartCU(); + // The structure we're building here is: + // space_A full definition + // space_B declaration + // space_B definition + // struct_C full definition + // struct_D declaration + // struct_D definition + // union_E full definition + // union_F declaration + // union_F definition + // class_G full definition + // class_H declaration + // class_H definition + // func_I declaration + // func_I definition + // + // So: + // - space_A, struct_C, union_E, and class_G don't use specifications; + // - space_B, struct_D, union_F, and class_H do. + // - func_I uses a specification. + // + // The full name for func_I is thus: + // + // space_A::space_B::struct_C::struct_D::union_E::union_F:: + // class_G::class_H::func_I + { + DIEHandler *space_A_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "space_A"); + DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL, + dwarf2reader::DW_TAG_namespace, "space_B", ""); + space_A_handler->Finish(); + delete space_A_handler; + } + + { + DIEHandler *space_B_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + 0x2e111126496596e2ULL); + DIEHandler *struct_C_handler + = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, + "struct_C"); + DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL, + dwarf2reader::DW_TAG_structure_type, "struct_D", ""); + struct_C_handler->Finish(); + delete struct_C_handler; + space_B_handler->Finish(); + delete space_B_handler; + } + + { + DIEHandler *struct_D_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, + 0x20cd423bf2a25a4cULL); + DIEHandler *union_E_handler + = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, + "union_E"); + DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL, + dwarf2reader::DW_TAG_union_type, "union_F", ""); + union_E_handler->Finish(); + delete union_E_handler; + struct_D_handler->Finish(); + delete struct_D_handler; + } + + { + DIEHandler *union_F_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, + 0xe25c84805aa58c32ULL); + DIEHandler *class_G_handler + = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, + "class_G"); + DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL, + dwarf2reader::DW_TAG_class_type, "class_H", ""); + class_G_handler->Finish(); + delete class_G_handler; + union_F_handler->Finish(); + delete union_F_handler; + } + + { + DIEHandler *class_H_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + 0xb70d960dcc173b6eULL); + DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL, + dwarf2reader::DW_TAG_subprogram, "func_I", ""); + class_H_handler->Finish(); + delete class_H_handler; + } + + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x27ff829e3bf69f37ULL, "", + 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F" + "::class_G::class_H::func_I", + 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); +} + +TEST_F(Specifications, InterCU) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + MockLineToModuleHandler lr; + EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + // First CU. Declares class_A. + { + DwarfCUToModule root1_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root1_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ProcessStrangeAttributes(&root1_handler); + ASSERT_TRUE(root1_handler.EndAttributes()); + DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, + dwarf2reader::DW_TAG_class_type, "class_A", ""); + root1_handler.Finish(); + } + + // Second CU. Defines class_A, declares member_func_B. + { + DwarfCUToModule root2_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root2_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root2_handler.EndAttributes()); + DIEHandler *class_A_handler + = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + 0xb8fbfdd5f0b26fceULL); + DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, + dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + class_A_handler->Finish(); + delete class_A_handler; + root2_handler.Finish(); + } + + // Third CU. Defines member_func_B. + { + DwarfCUToModule root3_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root3_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root3_handler.EndAttributes()); + DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + 0xb01fef8b380bd1a2ULL, "", + 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); + root3_handler.Finish(); + } + + vector functions; + m.GetFunctions(&functions, functions.end()); + EXPECT_EQ(1U, functions.size()); + EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); +} + +TEST_F(Specifications, UnhandledInterCU) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, false); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + MockLineToModuleHandler lr; + EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + // First CU. Declares class_A. + { + DwarfCUToModule root1_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root1_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ProcessStrangeAttributes(&root1_handler); + ASSERT_TRUE(root1_handler.EndAttributes()); + DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, + dwarf2reader::DW_TAG_class_type, "class_A", ""); + root1_handler.Finish(); + } + + // Second CU. Defines class_A, declares member_func_B. + { + DwarfCUToModule root2_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root2_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root2_handler.EndAttributes()); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); + DIEHandler *class_A_handler + = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + 0xb8fbfdd5f0b26fceULL); + DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, + dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + class_A_handler->Finish(); + delete class_A_handler; + root2_handler.Finish(); + } + + // Third CU. Defines member_func_B. + { + DwarfCUToModule root3_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root3_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root3_handler.EndAttributes()); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); + EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1); + DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + 0xb01fef8b380bd1a2ULL, "", + 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); + root3_handler.Finish(); + } +} + +TEST_F(Specifications, BadOffset) { + PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); + EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) + .WillOnce(Return()); + + StartCU(); + DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL, + dwarf2reader::DW_TAG_subprogram, "", ""); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x2be953efa6f9a996ULL, "function", + 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL); + root_handler_.Finish(); +} + +TEST_F(Specifications, FunctionDefinitionHasOwnName) { + PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403); + + StartCU(); + DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xc34ff4786cae78bdULL, "definition-name", + 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "definition-name", + 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); +} + +TEST_F(Specifications, ClassDefinitionHasOwnName) { + PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241); + + StartCU(); + DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL, + dwarf2reader::DW_TAG_class_type, "class-declaration-name", ""); + + dwarf2reader::DIEHandler *class_definition + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + 0xd0fe467ec2f1a58cULL, "class-definition-name"); + ASSERT_TRUE(class_definition); + DeclarationDIE(class_definition, 0x6d028229c15623dbULL, + dwarf2reader::DW_TAG_subprogram, + "function-declaration-name", ""); + class_definition->Finish(); + delete class_definition; + + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x6d028229c15623dbULL, "function-definition-name", + 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); + + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "class-definition-name::function-definition-name", + 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); +} + +// DIEs that cite a specification should prefer the specification's +// parents over their own when choosing qualified names. In this test, +// we take the name from our definition but the enclosing scope name +// from our declaration. I don't see why they'd ever be different, but +// we want to verify what DwarfCUToModule is looking at. +TEST_F(Specifications, PreferSpecificationParents) { + PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694); + + StartCU(); + { + dwarf2reader::DIEHandler *declaration_class_handler = + StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "declaration-class"); + DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, + dwarf2reader::DW_TAG_subprogram, "function-declaration", + ""); + declaration_class_handler->Finish(); + delete declaration_class_handler; + } + { + dwarf2reader::DIEHandler *definition_class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "definition-class"); + DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram, + 0x9ddb35517455ef7aULL, "function-definition", + 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); + definition_class_handler->Finish(); + delete definition_class_handler; + } + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "declaration-class::function-definition", + 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); +} + +class CUErrors: public CUFixtureBase, public Test { }; + +TEST_F(CUErrors, BadStmtList) { + EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd, + 0x2d7d19546cf6590cULL, 3)); + ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL, + dwarf2reader::DW_TAG_compile_unit)); + root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + "compilation-unit-name"); + root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, + dwarf2reader::DW_FORM_ref4, + dummy_line_size_ + 10); + root_handler_.EndAttributes(); + root_handler_.Finish(); +} + +TEST_F(CUErrors, NoLineSection) { + EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1); + PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290); + // Delete the entry for .debug_line added by the fixture class's constructor. + file_context_.ClearSectionMapForTest(); + + StartCU(); + root_handler_.Finish(); +} + +TEST_F(CUErrors, BadDwarfVersion1) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_FALSE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 1)); +} + +TEST_F(CUErrors, GoodDwarfVersion2) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 2)); +} + +TEST_F(CUErrors, GoodDwarfVersion3) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 3)); +} + +TEST_F(CUErrors, BadCURootDIETag) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 3)); + + ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, + dwarf2reader::DW_TAG_subprogram)); +} + +// Tests for DwarfCUToModule::Reporter. These just produce (or fail to +// produce) output, so their results need to be checked by hand. +struct Reporter: public Test { + Reporter() + : reporter("filename", 0x123456789abcdef0ULL) { + reporter.SetCUName("compilation-unit-name"); + + function.name = "function name"; + function.address = 0x19c45c30770c1eb0ULL; + function.size = 0x89808a5bdfa0a6a3ULL; + function.parameter_size = 0x6a329f18683dcd51ULL; + + file.name = "source file name"; + + line.address = 0x3606ac6267aebeccULL; + line.size = 0x5de482229f32556aULL; + line.file = &file; + line.number = 93400201; + } + + DwarfCUToModule::WarningReporter reporter; + Module::Function function; + Module::File file; + Module::Line line; +}; + +TEST_F(Reporter, UnknownSpecification) { + reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); +} + +TEST_F(Reporter, UnknownAbstractOrigin) { + reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); +} + +TEST_F(Reporter, MissingSection) { + reporter.MissingSection("section name"); +} + +TEST_F(Reporter, BadLineInfoOffset) { + reporter.BadLineInfoOffset(0x123456789abcdef1ULL); +} + +TEST_F(Reporter, UncoveredFunctionDisabled) { + reporter.UncoveredFunction(function); + EXPECT_FALSE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UncoveredFunctionEnabled) { + reporter.set_uncovered_warnings_enabled(true); + reporter.UncoveredFunction(function); + EXPECT_TRUE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UncoveredLineDisabled) { + reporter.UncoveredLine(line); + EXPECT_FALSE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UncoveredLineEnabled) { + reporter.set_uncovered_warnings_enabled(true); + reporter.UncoveredLine(line); + EXPECT_TRUE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UnnamedFunction) { + reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL); +} + +// Would be nice to also test: +// - overlapping lines, functions diff --git a/breakpad/common/dwarf_line_to_module.cc b/breakpad/common/dwarf_line_to_module.cc new file mode 100644 index 0000000000..258b0b603f --- /dev/null +++ b/breakpad/common/dwarf_line_to_module.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. +// See dwarf_line_to_module.h for details. + +#include + +#include + +#include "common/dwarf_line_to_module.h" +#include "common/using_std_string.h" + +// Trying to support Windows paths in a reasonable way adds a lot of +// variations to test; it would be better to just put off dealing with +// it until we actually have to deal with DWARF on Windows. + +// Return true if PATH is an absolute path, false if it is relative. +static bool PathIsAbsolute(const string &path) { + return (path.size() >= 1 && path[0] == '/'); +} + +static bool HasTrailingSlash(const string &path) { + return (path.size() >= 1 && path[path.size() - 1] == '/'); +} + +// If PATH is an absolute path, return PATH. If PATH is a relative path, +// treat it as relative to BASE and return the combined path. +static string ExpandPath(const string &path, + const string &base) { + if (PathIsAbsolute(path) || base.empty()) + return path; + return base + (HasTrailingSlash(base) ? "" : "/") + path; +} + +namespace google_breakpad { + +void DwarfLineToModule::DefineDir(const string &name, uint32 dir_num) { + // Directory number zero is reserved to mean the compilation + // directory. Silently ignore attempts to redefine it. + if (dir_num != 0) + directories_[dir_num] = ExpandPath(name, compilation_dir_); +} + +void DwarfLineToModule::DefineFile(const string &name, int32 file_num, + uint32 dir_num, uint64 mod_time, + uint64 length) { + if (file_num == -1) + file_num = ++highest_file_number_; + else if (file_num > highest_file_number_) + highest_file_number_ = file_num; + + string dir_name; + if (dir_num == 0) { + // Directory number zero is the compilation directory, and is stored as + // an attribute on the compilation unit, rather than in the program table. + dir_name = compilation_dir_; + } else { + DirectoryTable::const_iterator directory_it = directories_.find(dir_num); + if (directory_it != directories_.end()) { + dir_name = directory_it->second; + } else { + if (!warned_bad_directory_number_) { + fprintf(stderr, "warning: DWARF line number data refers to undefined" + " directory numbers\n"); + warned_bad_directory_number_ = true; + } + } + } + + string full_name = ExpandPath(name, dir_name); + + // Find a Module::File object of the given name, and add it to the + // file table. + files_[file_num] = module_->FindFile(full_name); +} + +void DwarfLineToModule::AddLine(uint64 address, uint64 length, + uint32 file_num, uint32 line_num, + uint32 column_num) { + if (length == 0) + return; + + // Clip lines not to extend beyond the end of the address space. + if (address + length < address) + length = -address; + + // Should we omit this line? (See the comments for omitted_line_end_.) + if (address == 0 || address == omitted_line_end_) { + omitted_line_end_ = address + length; + return; + } else { + omitted_line_end_ = 0; + } + + // Find the source file being referred to. + Module::File *file = files_[file_num]; + if (!file) { + if (!warned_bad_file_number_) { + fprintf(stderr, "warning: DWARF line number data refers to " + "undefined file numbers\n"); + warned_bad_file_number_ = true; + } + return; + } + Module::Line line; + line.address = address; + // We set the size when we get the next line or the EndSequence call. + line.size = length; + line.file = file; + line.number = line_num; + lines_->push_back(line); +} + +} // namespace google_breakpad diff --git a/breakpad/common/dwarf_line_to_module.h b/breakpad/common/dwarf_line_to_module.h new file mode 100644 index 0000000000..1fdd4cb716 --- /dev/null +++ b/breakpad/common/dwarf_line_to_module.h @@ -0,0 +1,188 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// The DwarfLineToModule class accepts line number information from a +// DWARF parser and adds it to a google_breakpad::Module. The Module +// can write that data out as a Breakpad symbol file. + +#ifndef COMMON_LINUX_DWARF_LINE_TO_MODULE_H +#define COMMON_LINUX_DWARF_LINE_TO_MODULE_H + +#include + +#include "common/module.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A class for producing a vector of google_breakpad::Module::Line +// instances from parsed DWARF line number data. +// +// An instance of this class can be provided as a handler to a +// dwarf2reader::LineInfo DWARF line number information parser. The +// handler accepts source location information from the parser and +// uses it to produce a vector of google_breakpad::Module::Line +// objects, referring to google_breakpad::Module::File objects added +// to a particular google_breakpad::Module. +// +// GNU toolchain omitted sections support: +// ====================================== +// +// Given the right options, the GNU toolchain will omit unreferenced +// functions from the final executable. Unfortunately, when it does so, it +// does not remove the associated portions of the DWARF line number +// program; instead, it gives the DW_LNE_set_address instructions referring +// to the now-deleted code addresses of zero. Given this input, the DWARF +// line parser will call AddLine with a series of lines starting at address +// zero. For example, here is the output from 'readelf -wl' for a program +// with four functions, the first three of which have been omitted: +// +// Line Number Statements: +// Extended opcode 2: set Address to 0x0 +// Advance Line by 14 to 15 +// Copy +// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 +// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 +// Advance PC by 2 to 0xd +// Extended opcode 1: End of Sequence +// +// Extended opcode 2: set Address to 0x0 +// Advance Line by 14 to 15 +// Copy +// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 +// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 +// Advance PC by 2 to 0xd +// Extended opcode 1: End of Sequence +// +// Extended opcode 2: set Address to 0x0 +// Advance Line by 19 to 20 +// Copy +// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 21 +// Special opcode 76: advance Address by 5 to 0x8 and Line by 1 to 22 +// Advance PC by 2 to 0xa +// Extended opcode 1: End of Sequence +// +// Extended opcode 2: set Address to 0x80483a4 +// Advance Line by 23 to 24 +// Copy +// Special opcode 202: advance Address by 14 to 0x80483b2 and Line by 1 to 25 +// Special opcode 76: advance Address by 5 to 0x80483b7 and Line by 1 to 26 +// Advance PC by 6 to 0x80483bd +// Extended opcode 1: End of Sequence +// +// Instead of collecting runs of lines describing code that is not there, +// we try to recognize and drop them. Since the linker doesn't explicitly +// distinguish references to dropped sections from genuine references to +// code at address zero, we must use a heuristic. We have chosen: +// +// - If a line starts at address zero, omit it. (On the platforms +// breakpad targets, it is extremely unlikely that there will be code +// at address zero.) +// +// - If a line starts immediately after an omitted line, omit it too. +class DwarfLineToModule: public dwarf2reader::LineInfoHandler { + public: + // As the DWARF line info parser passes us line records, add source + // files to MODULE, and add all lines to the end of LINES. LINES + // need not be empty. If the parser hands us a zero-length line, we + // omit it. If the parser hands us a line that extends beyond the + // end of the address space, we clip it. It's up to our client to + // sort out which lines belong to which functions; we don't add them + // to any particular function in MODULE ourselves. + DwarfLineToModule(Module *module, const string& compilation_dir, + vector *lines) + : module_(module), + compilation_dir_(compilation_dir), + lines_(lines), + highest_file_number_(-1), + omitted_line_end_(0), + warned_bad_file_number_(false), + warned_bad_directory_number_(false) { } + + ~DwarfLineToModule() { } + + void DefineDir(const string &name, uint32 dir_num); + void DefineFile(const string &name, int32 file_num, + uint32 dir_num, uint64 mod_time, + uint64 length); + void AddLine(uint64 address, uint64 length, + uint32 file_num, uint32 line_num, uint32 column_num); + + private: + + typedef std::map DirectoryTable; + typedef std::map FileTable; + + // The module we're contributing debugging info to. Owned by our + // client. + Module *module_; + + // The compilation directory for the current compilation unit whose + // lines are being accumulated. + string compilation_dir_; + + // The vector of lines we're accumulating. Owned by our client. + // + // In a Module, as in a breakpad symbol file, lines belong to + // specific functions, but DWARF simply assigns lines to addresses; + // one must infer the line/function relationship using the + // functions' beginning and ending addresses. So we can't add these + // to the appropriate function from module_ until we've read the + // function info as well. Instead, we accumulate lines here, and let + // whoever constructed this sort it all out. + vector *lines_; + + // A table mapping directory numbers to paths. + DirectoryTable directories_; + + // A table mapping file numbers to Module::File pointers. + FileTable files_; + + // The highest file number we've seen so far, or -1 if we've seen + // none. Used for dynamically defined file numbers. + int32 highest_file_number_; + + // This is the ending address of the last line we omitted, or zero if we + // didn't omit the previous line. It is zero before we have received any + // AddLine calls. + uint64 omitted_line_end_; + + // True if we've warned about: + bool warned_bad_file_number_; // bad file numbers + bool warned_bad_directory_number_; // bad directory numbers +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_LINE_TO_MODULE_H diff --git a/breakpad/common/dwarf_line_to_module_unittest.cc b/breakpad/common/dwarf_line_to_module_unittest.cc new file mode 100644 index 0000000000..7c0fcfd35a --- /dev/null +++ b/breakpad/common/dwarf_line_to_module_unittest.cc @@ -0,0 +1,391 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. + +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf_line_to_module.h" + +using std::vector; + +using google_breakpad::DwarfLineToModule; +using google_breakpad::Module; +using google_breakpad::Module; + +TEST(SimpleModule, One) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("file1", 0x30bf0f27, 0, 0, 0); + h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27, + 0x4c090cbf, 0x1cf9fe0d); + + vector files; + m.GetFiles(&files); + EXPECT_EQ(1U, files.size()); + EXPECT_STREQ("/file1", files[0]->name.c_str()); + + EXPECT_EQ(1U, lines.size()); + EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address); + EXPECT_EQ(0x63c9a14cf556712bULL, lines[0].size); + EXPECT_TRUE(lines[0].file == files[0]); + EXPECT_EQ(0x4c090cbf, lines[0].number); +} + +TEST(SimpleModule, Many) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 0x838299ab); + h.DefineDir("directory2", 0xf85de023); + h.DefineFile("file1", 0x2b80377a, 0x838299ab, 0, 0); + h.DefineFile("file1", 0x63beb4a4, 0xf85de023, 0, 0); + h.DefineFile("file2", 0x1d161d56, 0x838299ab, 0, 0); + h.DefineFile("file2", 0x1e7a667c, 0xf85de023, 0, 0); + h.AddLine(0x69900c5d553b7274ULL, 0x90fded183f0d0d3cULL, 0x2b80377a, + 0x15b0f0a9U, 0x3ff5abd6U); + h.AddLine(0x45811219a39b7101ULL, 0x25a5e6a924afc41fULL, 0x63beb4a4, + 0x4d259ce9U, 0x41c5ee32U); + h.AddLine(0xfa90514c1dc9704bULL, 0x0063efeabc02f313ULL, 0x1d161d56, + 0x1ee9fa4fU, 0xbf70e46aU); + h.AddLine(0x556b55fb6a647b10ULL, 0x3f3089ca2bfd80f5ULL, 0x1e7a667c, + 0x77fc280eU, 0x2c4a728cU); + h.DefineFile("file3", -1, 0, 0, 0); + h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5, + 0x75047044U, 0xb6a0016cU); + + vector files; + m.GetFiles(&files); + ASSERT_EQ(5U, files.size()); + EXPECT_STREQ("/directory1/file1", files[0]->name.c_str()); + EXPECT_STREQ("/directory1/file2", files[1]->name.c_str()); + EXPECT_STREQ("/directory2/file1", files[2]->name.c_str()); + EXPECT_STREQ("/directory2/file2", files[3]->name.c_str()); + EXPECT_STREQ("/file3", files[4]->name.c_str()); + + ASSERT_EQ(5U, lines.size()); + + EXPECT_EQ(0x69900c5d553b7274ULL, lines[0].address); + EXPECT_EQ(0x90fded183f0d0d3cULL, lines[0].size); + EXPECT_TRUE(lines[0].file == files[0]); + EXPECT_EQ(0x15b0f0a9, lines[0].number); + + EXPECT_EQ(0x45811219a39b7101ULL, lines[1].address); + EXPECT_EQ(0x25a5e6a924afc41fULL, lines[1].size); + EXPECT_TRUE(lines[1].file == files[2]); + EXPECT_EQ(0x4d259ce9, lines[1].number); + + EXPECT_EQ(0xfa90514c1dc9704bULL, lines[2].address); + EXPECT_EQ(0x0063efeabc02f313ULL, lines[2].size); + EXPECT_TRUE(lines[2].file == files[1]); + EXPECT_EQ(0x1ee9fa4f, lines[2].number); + + EXPECT_EQ(0x556b55fb6a647b10ULL, lines[3].address); + EXPECT_EQ(0x3f3089ca2bfd80f5ULL, lines[3].size); + EXPECT_TRUE(lines[3].file == files[3]); + EXPECT_EQ(0x77fc280e, lines[3].number); + + EXPECT_EQ(0xe2d72a37f8d9403aULL, lines[4].address); + EXPECT_EQ(0x034dfab5b0d4d236ULL, lines[4].size); + EXPECT_TRUE(lines[4].file == files[4]); + EXPECT_EQ(0x75047044, lines[4].number); +} + +TEST(Filenames, Absolute) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("/absolute", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + vector files; + m.GetFiles(&files); + ASSERT_EQ(1U, files.size()); + EXPECT_STREQ("/absolute", files[0]->name.c_str()); + ASSERT_EQ(1U, lines.size()); + EXPECT_TRUE(lines[0].file == files[0]); +} + +TEST(Filenames, Relative) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("relative", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + vector files; + m.GetFiles(&files); + ASSERT_EQ(1U, files.size()); + EXPECT_STREQ("/directory1/relative", files[0]->name.c_str()); + ASSERT_EQ(1U, lines.size()); + EXPECT_TRUE(lines[0].file == files[0]); +} + +TEST(Filenames, StrangeFile) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("", 1, 1, 0, 0); + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/directory1/", lines[0].file->name.c_str()); +} + +TEST(Filenames, StrangeDirectory) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("", 1); + h.DefineFile("file1", 1, 1, 0, 0); + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/file1", lines[0].file->name.c_str()); +} + +TEST(Filenames, StrangeDirectoryAndFile) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("", 1); + h.DefineFile("", 1, 1, 0, 0); + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/", lines[0].file->name.c_str()); +} + +// We should use the compilation directory when encountering a file for +// directory number zero. +TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "src/build", &lines); + + h.DefineDir("Dir", 1); + h.DefineFile("File", 1, 0, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("src/build/File", lines[0].file->name.c_str()); +} + +// We should treat non-absolute directories as relative to the compilation +// directory. +TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "src/build", &lines); + + h.DefineDir("Dir", 1); + h.DefineFile("File", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("src/build/Dir/File", lines[0].file->name.c_str()); +} + +// We should treat absolute directories as absolute, and not relative to +// the compilation dir. +TEST(Filenames, IncludeDirectoryAbsolute) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "src/build", &lines); + + h.DefineDir("/Dir", 1); + h.DefineFile("File", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/Dir/File", lines[0].file->name.c_str()); +} + +// We should silently ignore attempts to define directory number zero, +// since that is always the compilation directory. +TEST(ModuleErrors, DirectoryZero) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory0", 0); // should be ignored + h.DefineFile("relative", 1, 0, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/relative", lines[0].file->name.c_str()); +} + +// We should refuse to add lines with bogus file numbers. We should +// produce only one warning, however. +TEST(ModuleErrors, BadFileNumber) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("relative", 1, 0, 0, 0); + h.AddLine(1, 1, 2, 0, 0); // bad file number + h.AddLine(2, 1, 2, 0, 0); // bad file number (no duplicate warning) + + EXPECT_EQ(0U, lines.size()); +} + +// We should treat files with bogus directory numbers as relative to +// the compilation unit. +TEST(ModuleErrors, BadDirectoryNumber) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number + h.DefineFile("baddirnumber2", 2, 2, 0, 0); // bad dir number (no warning) + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("baddirnumber1", lines[0].file->name.c_str()); +} + +// We promise not to report empty lines. +TEST(ModuleErrors, EmptyLine) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(1, 0, 1, 0, 0); + + ASSERT_EQ(0U, lines.size()); +} + +// We are supposed to clip lines that extend beyond the end of the +// address space. +TEST(ModuleErrors, BigLine) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_EQ(1U, lines[0].size); +} + +// The 'Omitted' tests verify that we correctly omit line information +// for code in sections that the linker has dropped. See "GNU +// toolchain omitted sections support" at the top of the +// DwarfLineToModule class. + +TEST(Omitted, DroppedThenGood) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0, 10, 1, 83816211, 0); // should be omitted + h.AddLine(20, 10, 1, 13059195, 0); // should be recorded + + ASSERT_EQ(1U, lines.size()); + EXPECT_EQ(13059195, lines[0].number); +} + +TEST(Omitted, GoodThenDropped) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded + h.AddLine(0, 10, 1, 44793413, 0); // should be omitted + + ASSERT_EQ(1U, lines.size()); + EXPECT_EQ(41454594, lines[0].number); +} + +TEST(Omitted, Mix1) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded + h.AddLine(0xdfb5a72d, 10, 1, 39847385, 0); // should be recorded + h.AddLine(0, 0x78, 1, 23053829, 0); // should be omitted + h.AddLine(0x78, 0x6a, 1, 65317783, 0); // should be omitted + h.AddLine(0x78 + 0x6a, 0x2a, 1, 77601423, 0); // should be omitted + h.AddLine(0x9fe0cea5, 10, 1, 91806582, 0); // should be recorded + h.AddLine(0x7e41a109, 10, 1, 56169221, 0); // should be recorded + + ASSERT_EQ(4U, lines.size()); + EXPECT_EQ(58932642, lines[0].number); + EXPECT_EQ(39847385, lines[1].number); + EXPECT_EQ(91806582, lines[2].number); + EXPECT_EQ(56169221, lines[3].number); +} + +TEST(Omitted, Mix2) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted + h.AddLine(0xf2, 0xb9, 1, 78958222, 0); // should be omitted + h.AddLine(0xf2 + 0xb9, 0xf7, 1, 64861892, 0); // should be omitted + h.AddLine(0x4e4d271e, 9, 1, 67355743, 0); // should be recorded + h.AddLine(0xdfb5a72d, 30, 1, 23365776, 0); // should be recorded + h.AddLine(0, 0x64, 1, 76196762, 0); // should be omitted + h.AddLine(0x64, 0x33, 1, 71066611, 0); // should be omitted + h.AddLine(0x64 + 0x33, 0xe3, 1, 61749337, 0); // should be omitted + + ASSERT_EQ(2U, lines.size()); + EXPECT_EQ(67355743, lines[0].number); + EXPECT_EQ(23365776, lines[1].number); +} diff --git a/breakpad/common/language.cc b/breakpad/common/language.cc new file mode 100644 index 0000000000..c2fd81f644 --- /dev/null +++ b/breakpad/common/language.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// language.cc: Subclasses and singletons for google_breakpad::Language. +// See language.h for details. + +#include "common/language.h" + +namespace google_breakpad { + +// C++ language-specific operations. +class CPPLanguage: public Language { + public: + CPPLanguage() {} + string MakeQualifiedName(const string &parent_name, + const string &name) const { + if (parent_name.empty()) + return name; + else + return parent_name + "::" + name; + } +}; + +CPPLanguage CPPLanguageSingleton; + +// Java language-specific operations. +class JavaLanguage: public Language { + public: + string MakeQualifiedName(const string &parent_name, + const string &name) const { + if (parent_name.empty()) + return name; + else + return parent_name + "." + name; + } +}; + +JavaLanguage JavaLanguageSingleton; + +// Assembler language-specific operations. +class AssemblerLanguage: public Language { + bool HasFunctions() const { return false; } + string MakeQualifiedName(const string &parent_name, + const string &name) const { + return name; + } +}; + +AssemblerLanguage AssemblerLanguageSingleton; + +const Language * const Language::CPlusPlus = &CPPLanguageSingleton; +const Language * const Language::Java = &JavaLanguageSingleton; +const Language * const Language::Assembler = &AssemblerLanguageSingleton; + +} // namespace google_breakpad diff --git a/breakpad/common/language.h b/breakpad/common/language.h new file mode 100644 index 0000000000..bbe303347a --- /dev/null +++ b/breakpad/common/language.h @@ -0,0 +1,88 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// language.h: Define google_breakpad::Language. Instances of +// subclasses of this class provide language-appropriate operations +// for the Breakpad symbol dumper. + +#ifndef COMMON_LINUX_LANGUAGE_H__ +#define COMMON_LINUX_LANGUAGE_H__ + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// An abstract base class for language-specific operations. We choose +// an instance of a subclass of this when we find the CU's language. +// This class's definitions are appropriate for CUs with no specified +// language. +class Language { + public: + // A base class destructor should be either public and virtual, + // or protected and nonvirtual. + virtual ~Language() {} + + // Return true if this language has functions to which we can assign + // line numbers. (Debugging info for assembly language, for example, + // can have source location information, but does not have functions + // recorded using DW_TAG_subprogram DIEs.) + virtual bool HasFunctions() const { return true; } + + // Construct a fully-qualified, language-appropriate form of NAME, + // given that PARENT_NAME is the name of the construct enclosing + // NAME. If PARENT_NAME is the empty string, then NAME is a + // top-level name. + // + // This API sort of assumes that a fully-qualified name is always + // some simple textual composition of the unqualified name and its + // parent's name, and that we don't need to know anything else about + // the parent or the child (say, their DIEs' tags) to do the job. + // This is true for the languages we support at the moment, and + // keeps things concrete. Perhaps a more refined operation would + // take into account the parent and child DIE types, allow languages + // to use their own data type for complex parent names, etc. But if + // C++ doesn't need all that, who would? + virtual string MakeQualifiedName (const string &parent_name, + const string &name) const = 0; + + // Instances for specific languages. + static const Language * const CPlusPlus, + * const Java, + * const Assembler; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_LANGUAGE_H__ diff --git a/breakpad/common/md5.cc b/breakpad/common/md5.cc new file mode 100644 index 0000000000..bccf61c603 --- /dev/null +++ b/breakpad/common/md5.cc @@ -0,0 +1,251 @@ +/* + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include + +#include "common/md5.h" + +namespace google_breakpad { + +#ifndef WORDS_BIGENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + u32 t; + do { + t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(u32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +static void MD5Transform(u32 buf[4], u32 const in[16]); + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((u32 *) ctx->in)[14] = ctx->bits[0]; + ((u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(u32 buf[4], u32 const in[16]) +{ + register u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +} // namespace google_breakpad + diff --git a/breakpad/common/md5.h b/breakpad/common/md5.h new file mode 100644 index 0000000000..e96521eedd --- /dev/null +++ b/breakpad/common/md5.h @@ -0,0 +1,27 @@ +// Copyright 2007 Google Inc. All Rights Reserved. +// Author: liuli@google.com (Liu Li) +#ifndef COMMON_MD5_H__ +#define COMMON_MD5_H__ + +#include + +namespace google_breakpad { + +typedef uint32_t u32; +typedef uint8_t u8; + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +void MD5Init(struct MD5Context *ctx); + +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len); + +void MD5Final(unsigned char digest[16], struct MD5Context *ctx); + +} // namespace google_breakpad + +#endif // COMMON_MD5_H__ diff --git a/breakpad/common/memory.h b/breakpad/common/memory.h new file mode 100644 index 0000000000..5f94445278 --- /dev/null +++ b/breakpad/common/memory.h @@ -0,0 +1,201 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_ +#define GOOGLE_BREAKPAD_COMMON_MEMORY_H_ + +#include +#include +#include +#include + +#include +#include + +#ifdef __APPLE__ +#define sys_mmap mmap +#define sys_mmap2 mmap +#define sys_munmap munmap +#define MAP_ANONYMOUS MAP_ANON +#else +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace google_breakpad { + +// This is very simple allocator which fetches pages from the kernel directly. +// Thus, it can be used even when the heap may be corrupted. +// +// There is no free operation. The pages are only freed when the object is +// destroyed. +class PageAllocator { + public: + PageAllocator() + : page_size_(getpagesize()), + last_(NULL), + current_page_(NULL), + page_offset_(0) { + } + + ~PageAllocator() { + FreeAll(); + } + + void *Alloc(unsigned bytes) { + if (!bytes) + return NULL; + + if (current_page_ && page_size_ - page_offset_ >= bytes) { + uint8_t *const ret = current_page_ + page_offset_; + page_offset_ += bytes; + if (page_offset_ == page_size_) { + page_offset_ = 0; + current_page_ = NULL; + } + + return ret; + } + + const unsigned pages = + (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; + uint8_t *const ret = GetNPages(pages); + if (!ret) + return NULL; + + page_offset_ = + (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % + page_size_; + current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; + + return ret + sizeof(PageHeader); + } + + // Checks whether the page allocator owns the passed-in pointer. + // This method exists for testing pursposes only. + bool OwnsPointer(const void* p) { + for (PageHeader* header = last_; header; header = header->next) { + const char* current = reinterpret_cast(header); + if ((p >= current) && (p < current + header->num_pages * page_size_)) + return true; + } + + return false; + } + + private: + uint8_t *GetNPages(unsigned num_pages) { +#ifdef __x86_64 + void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#else + void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif + if (a == MAP_FAILED) + return NULL; + + struct PageHeader *header = reinterpret_cast(a); + header->next = last_; + header->num_pages = num_pages; + last_ = header; + + return reinterpret_cast(a); + } + + void FreeAll() { + PageHeader *next; + + for (PageHeader *cur = last_; cur; cur = next) { + next = cur->next; + sys_munmap(cur, cur->num_pages * page_size_); + } + } + + struct PageHeader { + PageHeader *next; // pointer to the start of the next set of pages. + unsigned num_pages; // the number of pages in this set. + }; + + const unsigned page_size_; + PageHeader *last_; + uint8_t *current_page_; + unsigned page_offset_; +}; + +// Wrapper to use with STL containers +template +struct PageStdAllocator : public std::allocator { + typedef typename std::allocator::pointer pointer; + typedef typename std::allocator::size_type size_type; + + explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {} + template PageStdAllocator(const PageStdAllocator& other) + : allocator_(other.allocator_) {} + + inline pointer allocate(size_type n, const void* = 0) { + return static_cast(allocator_.Alloc(sizeof(T) * n)); + } + + inline void deallocate(pointer, size_type) { + // The PageAllocator doesn't free. + } + + template struct rebind { + typedef PageStdAllocator other; + }; + + private: + // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will + // otherwise complain that `other.allocator_` is private in the constructor + // code. + template friend struct PageStdAllocator; + + PageAllocator& allocator_; +}; + +// A wasteful vector is a std::vector, except that it allocates memory from a +// PageAllocator. It's wasteful because, when resizing, it always allocates a +// whole new array since the PageAllocator doesn't support realloc. +template +class wasteful_vector : public std::vector > { + public: + wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) + : std::vector >(PageStdAllocator(*allocator)) { + std::vector >::reserve(size_hint); + } +}; + +} // namespace google_breakpad + +inline void* operator new(size_t nbytes, + google_breakpad::PageAllocator& allocator) { + return allocator.Alloc(nbytes); +} + +#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_ diff --git a/breakpad/common/memory_range.h b/breakpad/common/memory_range.h new file mode 100644 index 0000000000..41dd2da622 --- /dev/null +++ b/breakpad/common/memory_range.h @@ -0,0 +1,145 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// memory_range.h: Define the google_breakpad::MemoryRange class, which +// is a lightweight wrapper with a pointer and a length to encapsulate +// a contiguous range of memory. + +#ifndef COMMON_MEMORY_RANGE_H_ +#define COMMON_MEMORY_RANGE_H_ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +// A lightweight wrapper with a pointer and a length to encapsulate a +// contiguous range of memory. It provides helper methods for checked +// access of a subrange of the memory. Its implemementation does not +// allocate memory or call into libc functions, and is thus safer to use +// in a crashed environment. +class MemoryRange { + public: + MemoryRange() : data_(NULL), length_(0) {} + + MemoryRange(const void* data, size_t length) { + Set(data, length); + } + + // Returns true if this memory range contains no data. + bool IsEmpty() const { + // Set() guarantees that |length_| is zero if |data_| is NULL. + return length_ == 0; + } + + // Resets to an empty range. + void Reset() { + data_ = NULL; + length_ = 0; + } + + // Sets this memory range to point to |data| and its length to |length|. + void Set(const void* data, size_t length) { + data_ = reinterpret_cast(data); + // Always set |length_| to zero if |data_| is NULL. + length_ = data ? length : 0; + } + + // Returns true if this range covers a subrange of |sub_length| bytes + // at |sub_offset| bytes of this memory range, or false otherwise. + bool Covers(size_t sub_offset, size_t sub_length) const { + // The following checks verify that: + // 1. sub_offset is within [ 0 .. length_ - 1 ] + // 2. sub_offset + sub_length is within + // [ sub_offset .. length_ ] + return sub_offset < length_ && + sub_offset + sub_length >= sub_offset && + sub_offset + sub_length <= length_; + } + + // Returns a raw data pointer to a subrange of |sub_length| bytes at + // |sub_offset| bytes of this memory range, or NULL if the subrange + // is out of bounds. + const void* GetData(size_t sub_offset, size_t sub_length) const { + return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL; + } + + // Same as the two-argument version of GetData() but uses sizeof(DataType) + // as the subrange length and returns an |DataType| pointer for convenience. + template + const DataType* GetData(size_t sub_offset) const { + return reinterpret_cast( + GetData(sub_offset, sizeof(DataType))); + } + + // Returns a raw pointer to the |element_index|-th element of an array + // of elements of length |element_size| starting at |sub_offset| bytes + // of this memory range, or NULL if the element is out of bounds. + const void* GetArrayElement(size_t element_offset, + size_t element_size, + unsigned element_index) const { + size_t sub_offset = element_offset + element_index * element_size; + return GetData(sub_offset, element_size); + } + + // Same as the three-argument version of GetArrayElement() but deduces + // the element size using sizeof(ElementType) and returns an |ElementType| + // pointer for convenience. + template + const ElementType* GetArrayElement(size_t element_offset, + unsigned element_index) const { + return reinterpret_cast( + GetArrayElement(element_offset, sizeof(ElementType), element_index)); + } + + // Returns a subrange of |sub_length| bytes at |sub_offset| bytes of + // this memory range, or an empty range if the subrange is out of bounds. + MemoryRange Subrange(size_t sub_offset, size_t sub_length) const { + return Covers(sub_offset, sub_length) ? + MemoryRange(data_ + sub_offset, sub_length) : MemoryRange(); + } + + // Returns a pointer to the beginning of this memory range. + const uint8_t* data() const { return data_; } + + // Returns the length, in bytes, of this memory range. + size_t length() const { return length_; } + + private: + // Pointer to the beginning of this memory range. + const uint8_t* data_; + + // Length, in bytes, of this memory range. + size_t length_; +}; + +} // namespace google_breakpad + +#endif // COMMON_MEMORY_RANGE_H_ diff --git a/breakpad/common/memory_range_unittest.cc b/breakpad/common/memory_range_unittest.cc new file mode 100644 index 0000000000..f6cf8c8b2a --- /dev/null +++ b/breakpad/common/memory_range_unittest.cc @@ -0,0 +1,193 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// memory_range_unittest.cc: Unit tests for google_breakpad::MemoryRange. + +#include "breakpad_googletest_includes.h" +#include "common/memory_range.h" + +using google_breakpad::MemoryRange; +using testing::Message; + +namespace { + +const uint32_t kBuffer[10] = { 0 }; +const size_t kBufferSize = sizeof(kBuffer); +const uint8_t* kBufferPointer = reinterpret_cast(kBuffer); + +// Test vectors for verifying Covers, GetData, and Subrange. +const struct { + bool valid; + size_t offset; + size_t length; +} kSubranges[] = { + { true, 0, 0 }, + { true, 0, 2 }, + { true, 0, kBufferSize }, + { true, 2, 0 }, + { true, 2, 4 }, + { true, 2, kBufferSize - 2 }, + { true, kBufferSize - 1, 1 }, + { false, kBufferSize, 0 }, + { false, kBufferSize, static_cast(-1) }, + { false, kBufferSize + 1, 0 }, + { false, static_cast(-1), 2 }, + { false, 1, kBufferSize }, + { false, kBufferSize - 1, 2 }, + { false, 0, static_cast(-1) }, + { false, 1, static_cast(-1) }, +}; +const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]); + +// Test vectors for verifying GetArrayElement. +const struct { + size_t offset; + size_t size; + size_t index; + const void* const pointer; +} kElements[] = { + // Valid array elemenets + { 0, 1, 0, kBufferPointer }, + { 0, 1, 1, kBufferPointer + 1 }, + { 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 }, + { 0, 2, 1, kBufferPointer + 2 }, + { 0, 4, 2, kBufferPointer + 8 }, + { 0, 4, 9, kBufferPointer + 36 }, + { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, + // Invalid array elemenets + { 0, 1, kBufferSize, NULL }, + { 0, 4, 10, NULL }, + { kBufferSize - 1, 1, 1, NULL }, + { kBufferSize - 1, 2, 0, NULL }, + { kBufferSize, 1, 0, NULL }, +}; +const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); + +} // namespace + +TEST(MemoryRangeTest, DefaultConstructor) { + MemoryRange range; + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MemoryRangeTest, ConstructorWithDataAndLength) { + MemoryRange range(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); +} + +TEST(MemoryRangeTest, Reset) { + MemoryRange range; + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); + + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MemoryRangeTest, Set) { + MemoryRange range; + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Set(NULL, 0); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MemoryRangeTest, SubrangeOfEmptyMemoryRange) { + MemoryRange range; + MemoryRange subrange = range.Subrange(0, 10); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); +} + +TEST(MemoryRangeTest, SubrangeAndGetData) { + MemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumSubranges; ++i) { + bool valid = kSubranges[i].valid; + size_t sub_offset = kSubranges[i].offset; + size_t sub_length = kSubranges[i].length; + SCOPED_TRACE(Message() << "offset=" << sub_offset + << ", length=" << sub_length); + + MemoryRange subrange = range.Subrange(sub_offset, sub_length); + if (valid) { + EXPECT_TRUE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, + range.GetData(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); + EXPECT_EQ(sub_length, subrange.length()); + } else { + EXPECT_FALSE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); + } + } +} + +TEST(MemoryRangeTest, GetDataWithTemplateType) { + MemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetData(0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), char_pointer); + const int* int_pointer = range.GetData(0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), int_pointer); +} + +TEST(MemoryRangeTest, GetArrayElement) { + MemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumElements; ++i) { + size_t element_offset = kElements[i].offset; + size_t element_size = kElements[i].size; + unsigned element_index = kElements[i].index; + const void* const element_pointer = kElements[i].pointer; + SCOPED_TRACE(Message() << "offset=" << element_offset + << ", size=" << element_size + << ", index=" << element_index); + EXPECT_EQ(element_pointer, range.GetArrayElement( + element_offset, element_size, element_index)); + } +} + +TEST(MemoryRangeTest, GetArrayElmentWithTemplateType) { + MemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetArrayElement(0, 0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), char_pointer); + const int* int_pointer = range.GetArrayElement(0, 0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), int_pointer); +} diff --git a/breakpad/common/memory_unittest.cc b/breakpad/common/memory_unittest.cc new file mode 100644 index 0000000000..1e511ca56e --- /dev/null +++ b/breakpad/common/memory_unittest.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "breakpad_googletest_includes.h" +#include "common/memory.h" + +using namespace google_breakpad; + +namespace { +typedef testing::Test PageAllocatorTest; +} + +TEST(PageAllocatorTest, Setup) { + PageAllocator allocator; +} + +TEST(PageAllocatorTest, SmallObjects) { + PageAllocator allocator; + + for (unsigned i = 1; i < 1024; ++i) { + uint8_t *p = reinterpret_cast(allocator.Alloc(i)); + ASSERT_FALSE(p == NULL); + memset(p, 0, i); + } +} + +TEST(PageAllocatorTest, LargeObject) { + PageAllocator allocator; + + uint8_t *p = reinterpret_cast(allocator.Alloc(10000)); + ASSERT_FALSE(p == NULL); + for (unsigned i = 1; i < 10; ++i) { + uint8_t *p = reinterpret_cast(allocator.Alloc(i)); + ASSERT_FALSE(p == NULL); + memset(p, 0, i); + } +} + +namespace { +typedef testing::Test WastefulVectorTest; +} + +TEST(WastefulVectorTest, Setup) { + PageAllocator allocator_; + wasteful_vector v(&allocator_); + ASSERT_TRUE(v.empty()); + ASSERT_EQ(v.size(), 0u); +} + +TEST(WastefulVectorTest, Simple) { + PageAllocator allocator_; + wasteful_vector v(&allocator_); + + for (unsigned i = 0; i < 256; ++i) { + v.push_back(i); + ASSERT_EQ(i, v.back()); + ASSERT_EQ(&v.back(), &v[i]); + } + ASSERT_FALSE(v.empty()); + ASSERT_EQ(v.size(), 256u); + for (unsigned i = 0; i < 256; ++i) + ASSERT_EQ(v[i], i); +} + +TEST(WastefulVectorTest, UsesPageAllocator) { + PageAllocator allocator_; + wasteful_vector v(&allocator_); + + v.push_back(1); + ASSERT_TRUE(allocator_.OwnsPointer(&v[0])); +} diff --git a/breakpad/common/module.cc b/breakpad/common/module.cc new file mode 100644 index 0000000000..2d2e4efc4d --- /dev/null +++ b/breakpad/common/module.cc @@ -0,0 +1,294 @@ +// Copyright (c) 2011 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// module.cc: Implement google_breakpad::Module. See module.h. + +#include "common/module.h" + +#include +#include +#include +#include + +#include +#include + +namespace google_breakpad { + +using std::dec; +using std::endl; +using std::hex; + + +Module::Module(const string &name, const string &os, + const string &architecture, const string &id) : + name_(name), + os_(os), + architecture_(architecture), + id_(id), + load_address_(0) { } + +Module::~Module() { + for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) + delete it->second; + for (FunctionSet::iterator it = functions_.begin(); + it != functions_.end(); ++it) { + delete *it; + } + for (vector::iterator it = stack_frame_entries_.begin(); + it != stack_frame_entries_.end(); ++it) { + delete *it; + } + for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) + delete *it; +} + +void Module::SetLoadAddress(Address address) { + load_address_ = address; +} + +void Module::AddFunction(Function *function) { + // FUNC lines must not hold an empty name, so catch the problem early if + // callers try to add one. + assert(!function->name.empty()); + std::pair ret = functions_.insert(function); + if (!ret.second) { + // Free the duplicate that was not inserted because this Module + // now owns it. + delete function; + } +} + +void Module::AddFunctions(vector::iterator begin, + vector::iterator end) { + for (vector::iterator it = begin; it != end; ++it) + AddFunction(*it); +} + +void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { + stack_frame_entries_.push_back(stack_frame_entry); +} + +void Module::AddExtern(Extern *ext) { + std::pair ret = externs_.insert(ext); + if (!ret.second) { + // Free the duplicate that was not inserted because this Module + // now owns it. + delete ext; + } +} + +void Module::GetFunctions(vector *vec, + vector::iterator i) { + vec->insert(i, functions_.begin(), functions_.end()); +} + +void Module::GetExterns(vector *vec, + vector::iterator i) { + vec->insert(i, externs_.begin(), externs_.end()); +} + +Module::File *Module::FindFile(const string &name) { + // A tricky bit here. The key of each map entry needs to be a + // pointer to the entry's File's name string. This means that we + // can't do the initial lookup with any operation that would create + // an empty entry for us if the name isn't found (like, say, + // operator[] or insert do), because such a created entry's key will + // be a pointer the string passed as our argument. Since the key of + // a map's value type is const, we can't fix it up once we've + // created our file. lower_bound does the lookup without doing an + // insertion, and returns a good hint iterator to pass to insert. + // Our "destiny" is where we belong, whether we're there or not now. + FileByNameMap::iterator destiny = files_.lower_bound(&name); + if (destiny == files_.end() + || *destiny->first != name) { // Repeated string comparison, boo hoo. + File *file = new File; + file->name = name; + file->source_id = -1; + destiny = files_.insert(destiny, + FileByNameMap::value_type(&file->name, file)); + } + return destiny->second; +} + +Module::File *Module::FindFile(const char *name) { + string name_string = name; + return FindFile(name_string); +} + +Module::File *Module::FindExistingFile(const string &name) { + FileByNameMap::iterator it = files_.find(&name); + return (it == files_.end()) ? NULL : it->second; +} + +void Module::GetFiles(vector *vec) { + vec->clear(); + for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) + vec->push_back(it->second); +} + +void Module::GetStackFrameEntries(vector *vec) { + *vec = stack_frame_entries_; +} + +void Module::AssignSourceIds() { + // First, give every source file an id of -1. + for (FileByNameMap::iterator file_it = files_.begin(); + file_it != files_.end(); ++file_it) { + file_it->second->source_id = -1; + } + + // Next, mark all files actually cited by our functions' line number + // info, by setting each one's source id to zero. + for (FunctionSet::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); ++func_it) { + Function *func = *func_it; + for (vector::iterator line_it = func->lines.begin(); + line_it != func->lines.end(); ++line_it) + line_it->file->source_id = 0; + } + + // Finally, assign source ids to those files that have been marked. + // We could have just assigned source id numbers while traversing + // the line numbers, but doing it this way numbers the files in + // lexicographical order by name, which is neat. + int next_source_id = 0; + for (FileByNameMap::iterator file_it = files_.begin(); + file_it != files_.end(); ++file_it) { + if (!file_it->second->source_id) + file_it->second->source_id = next_source_id++; + } +} + +bool Module::ReportError() { + fprintf(stderr, "error writing symbol file: %s\n", + strerror(errno)); + return false; +} + +bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { + for (RuleMap::const_iterator it = rule_map.begin(); + it != rule_map.end(); ++it) { + if (it != rule_map.begin()) + stream << ' '; + stream << it->first << ": " << it->second; + } + return stream.good(); +} + +bool Module::Write(std::ostream &stream, SymbolData symbol_data) { + stream << "MODULE " << os_ << " " << architecture_ << " " + << id_ << " " << name_ << endl; + if (!stream.good()) + return ReportError(); + + if (symbol_data != ONLY_CFI) { + AssignSourceIds(); + + // Write out files. + for (FileByNameMap::iterator file_it = files_.begin(); + file_it != files_.end(); ++file_it) { + File *file = file_it->second; + if (file->source_id >= 0) { + stream << "FILE " << file->source_id << " " << file->name << endl; + if (!stream.good()) + return ReportError(); + } + } + + // Write out functions and their lines. + for (FunctionSet::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); ++func_it) { + Function *func = *func_it; + stream << "FUNC " << hex + << (func->address - load_address_) << " " + << func->size << " " + << func->parameter_size << " " + << func->name << dec << endl; + if (!stream.good()) + return ReportError(); + + for (vector::iterator line_it = func->lines.begin(); + line_it != func->lines.end(); ++line_it) { + stream << hex + << (line_it->address - load_address_) << " " + << line_it->size << " " + << dec + << line_it->number << " " + << line_it->file->source_id << endl; + if (!stream.good()) + return ReportError(); + } + } + + // Write out 'PUBLIC' records. + for (ExternSet::const_iterator extern_it = externs_.begin(); + extern_it != externs_.end(); ++extern_it) { + Extern *ext = *extern_it; + stream << "PUBLIC " << hex + << (ext->address - load_address_) << " 0 " + << ext->name << dec << endl; + } + } + + if (symbol_data != NO_CFI) { + // Write out 'STACK CFI INIT' and 'STACK CFI' records. + vector::const_iterator frame_it; + for (frame_it = stack_frame_entries_.begin(); + frame_it != stack_frame_entries_.end(); ++frame_it) { + StackFrameEntry *entry = *frame_it; + stream << "STACK CFI INIT " << hex + << (entry->address - load_address_) << " " + << entry->size << " " << dec; + if (!stream.good() + || !WriteRuleMap(entry->initial_rules, stream)) + return ReportError(); + + stream << endl; + + // Write out this entry's delta rules as 'STACK CFI' records. + for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); + delta_it != entry->rule_changes.end(); ++delta_it) { + stream << "STACK CFI " << hex + << (delta_it->first - load_address_) << " " << dec; + if (!stream.good() + || !WriteRuleMap(delta_it->second, stream)) + return ReportError(); + + stream << endl; + } + } + } + + return true; +} + +} // namespace google_breakpad diff --git a/breakpad/common/module.h b/breakpad/common/module.h new file mode 100644 index 0000000000..398bc3157c --- /dev/null +++ b/breakpad/common/module.h @@ -0,0 +1,324 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// module.h: Define google_breakpad::Module. A Module holds debugging +// information, and can write that information out as a Breakpad +// symbol file. + +#ifndef COMMON_LINUX_MODULE_H__ +#define COMMON_LINUX_MODULE_H__ + +#include +#include +#include +#include +#include + +#include "common/symbol_data.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::set; +using std::vector; +using std::map; + +// A Module represents the contents of a module, and supports methods +// for adding information produced by parsing STABS or DWARF data +// --- possibly both from the same file --- and then writing out the +// unified contents as a Breakpad-format symbol file. +class Module { + public: + // The type of addresses and sizes in a symbol table. + typedef uint64_t Address; + struct File; + struct Function; + struct Line; + struct Extern; + + // Addresses appearing in File, Function, and Line structures are + // absolute, not relative to the the module's load address. That + // is, if the module were loaded at its nominal load address, the + // addresses would be correct. + + // A source file. + struct File { + // The name of the source file. + string name; + + // The file's source id. The Write member function clears this + // field and assigns source ids a fresh, so any value placed here + // before calling Write will be lost. + int source_id; + }; + + // A function. + struct Function { + // For sorting by address. (Not style-guide compliant, but it's + // stupid not to put this in the struct.) + static bool CompareByAddress(const Function *x, const Function *y) { + return x->address < y->address; + } + + // The function's name. + string name; + + // The start address and length of the function's code. + Address address, size; + + // The function's parameter size. + Address parameter_size; + + // Source lines belonging to this function, sorted by increasing + // address. + vector lines; + }; + + // A source line. + struct Line { + // For sorting by address. (Not style-guide compliant, but it's + // stupid not to put this in the struct.) + static bool CompareByAddress(const Module::Line &x, const Module::Line &y) { + return x.address < y.address; + } + + Address address, size; // The address and size of the line's code. + File *file; // The source file. + int number; // The source line number. + }; + + // An exported symbol. + struct Extern { + Address address; + string name; + }; + + // A map from register names to postfix expressions that recover + // their their values. This can represent a complete set of rules to + // follow at some address, or a set of changes to be applied to an + // extant set of rules. + typedef map RuleMap; + + // A map from addresses to RuleMaps, representing changes that take + // effect at given addresses. + typedef map RuleChangeMap; + + // A range of 'STACK CFI' stack walking information. An instance of + // this structure corresponds to a 'STACK CFI INIT' record and the + // subsequent 'STACK CFI' records that fall within its range. + struct StackFrameEntry { + // The starting address and number of bytes of machine code this + // entry covers. + Address address, size; + + // The initial register recovery rules, in force at the starting + // address. + RuleMap initial_rules; + + // A map from addresses to rule changes. To find the rules in + // force at a given address, start with initial_rules, and then + // apply the changes given in this map for all addresses up to and + // including the address you're interested in. + RuleChangeMap rule_changes; + }; + + struct FunctionCompare { + bool operator() (const Function *lhs, + const Function *rhs) const { + if (lhs->address == rhs->address) + return lhs->name < rhs->name; + return lhs->address < rhs->address; + } + }; + + struct ExternCompare { + bool operator() (const Extern *lhs, + const Extern *rhs) const { + return lhs->address < rhs->address; + } + }; + + // Create a new module with the given name, operating system, + // architecture, and ID string. + Module(const string &name, const string &os, const string &architecture, + const string &id); + ~Module(); + + // Set the module's load address to LOAD_ADDRESS; addresses given + // for functions and lines will be written to the Breakpad symbol + // file as offsets from this address. Construction initializes this + // module's load address to zero: addresses written to the symbol + // file will be the same as they appear in the Function, Line, and + // StackFrameEntry structures. + // + // Note that this member function has no effect on addresses stored + // in the data added to this module; the Write member function + // simply subtracts off the load address from addresses before it + // prints them. Only the last load address given before calling + // Write is used. + void SetLoadAddress(Address load_address); + + // Add FUNCTION to the module. FUNCTION's name must not be empty. + // This module owns all Function objects added with this function: + // destroying the module destroys them as well. + void AddFunction(Function *function); + + // Add all the functions in [BEGIN,END) to the module. + // This module owns all Function objects added with this function: + // destroying the module destroys them as well. + void AddFunctions(vector::iterator begin, + vector::iterator end); + + // Add STACK_FRAME_ENTRY to the module. + // This module owns all StackFrameEntry objects added with this + // function: destroying the module destroys them as well. + void AddStackFrameEntry(StackFrameEntry *stack_frame_entry); + + // Add PUBLIC to the module. + // This module owns all Extern objects added with this function: + // destroying the module destroys them as well. + void AddExtern(Extern *ext); + + // If this module has a file named NAME, return a pointer to it. If + // it has none, then create one and return a pointer to the new + // file. This module owns all File objects created using these + // functions; destroying the module destroys them as well. + File *FindFile(const string &name); + File *FindFile(const char *name); + + // If this module has a file named NAME, return a pointer to it. + // Otherwise, return NULL. + File *FindExistingFile(const string &name); + + // Insert pointers to the functions added to this module at I in + // VEC. The pointed-to Functions are still owned by this module. + // (Since this is effectively a copy of the function list, this is + // mostly useful for testing; other uses should probably get a more + // appropriate interface.) + void GetFunctions(vector *vec, vector::iterator i); + + // Insert pointers to the externs added to this module at I in + // VEC. The pointed-to Externs are still owned by this module. + // (Since this is effectively a copy of the extern list, this is + // mostly useful for testing; other uses should probably get a more + // appropriate interface.) + void GetExterns(vector *vec, vector::iterator i); + + // Clear VEC and fill it with pointers to the Files added to this + // module, sorted by name. The pointed-to Files are still owned by + // this module. (Since this is effectively a copy of the file list, + // this is mostly useful for testing; other uses should probably get + // a more appropriate interface.) + void GetFiles(vector *vec); + + // Clear VEC and fill it with pointers to the StackFrameEntry + // objects that have been added to this module. (Since this is + // effectively a copy of the stack frame entry list, this is mostly + // useful for testing; other uses should probably get + // a more appropriate interface.) + void GetStackFrameEntries(vector *vec); + + // Find those files in this module that are actually referred to by + // functions' line number data, and assign them source id numbers. + // Set the source id numbers for all other files --- unused by the + // source line data --- to -1. We do this before writing out the + // symbol file, at which point we omit any unused files. + void AssignSourceIds(); + + // Call AssignSourceIds, and write this module to STREAM in the + // breakpad symbol format. Return true if all goes well, or false if + // an error occurs. This method writes out: + // - a header based on the values given to the constructor, + // If symbol_data is not ONLY_CFI then: + // - the source files added via FindFile, + // - the functions added via AddFunctions, each with its lines, + // - all public records, + // If symbol_data is not NO_CFI then: + // - all CFI records. + // Addresses in the output are all relative to the load address + // established by SetLoadAddress. + bool Write(std::ostream &stream, SymbolData symbol_data); + + private: + // Report an error that has occurred writing the symbol file, using + // errno to find the appropriate cause. Return false. + static bool ReportError(); + + // Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI' + // records, without a final newline. Return true if all goes well; + // if an error occurs, return false, and leave errno set. + static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream); + + // Module header entries. + string name_, os_, architecture_, id_; + + // The module's nominal load address. Addresses for functions and + // lines are absolute, assuming the module is loaded at this + // address. + Address load_address_; + + // Relation for maps whose keys are strings shared with some other + // structure. + struct CompareStringPtrs { + bool operator()(const string *x, const string *y) const { return *x < *y; } + }; + + // A map from filenames to File structures. The map's keys are + // pointers to the Files' names. + typedef map FileByNameMap; + + // A set containing Function structures, sorted by address. + typedef set FunctionSet; + + // A set containing Extern structures, sorted by address. + typedef set ExternSet; + + // The module owns all the files and functions that have been added + // to it; destroying the module frees the Files and Functions these + // point to. + FileByNameMap files_; // This module's source files. + FunctionSet functions_; // This module's functions. + + // The module owns all the call frame info entries that have been + // added to it. + vector stack_frame_entries_; + + // The module owns all the externs that have been added to it; + // destroying the module frees the Externs these point to. + ExternSet externs_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_MODULE_H__ diff --git a/breakpad/common/module_unittest.cc b/breakpad/common/module_unittest.cc new file mode 100644 index 0000000000..5c0c697575 --- /dev/null +++ b/breakpad/common/module_unittest.cc @@ -0,0 +1,490 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// module_unittest.cc: Unit tests for google_breakpad::Module. + +#include +#include +#include +#include + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/module.h" +#include "common/using_std_string.h" + +using google_breakpad::Module; +using std::stringstream; +using std::vector; +using testing::ContainerEq; + +static Module::Function *generate_duplicate_function(const string &name) { + const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; + const Module::Address DUP_SIZE = 0x200b26e605f99071LL; + const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; + + Module::Function *function = new(Module::Function); + function->name = name; + function->address = DUP_ADDRESS; + function->size = DUP_SIZE; + function->parameter_size = DUP_PARAMETER_SIZE; + return function; +} + +#define MODULE_NAME "name with spaces" +#define MODULE_OS "os-name" +#define MODULE_ARCH "architecture" +#define MODULE_ID "id-string" + +TEST(Write, Header) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", + contents.c_str()); +} + +TEST(Write, OneLineFunc) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + Module::File *file = m.FindFile("file_name.cc"); + Module::Function *function = new(Module::Function); + function->name = "function_name"; + function->address = 0xe165bf8023b9d9abLL; + function->size = 0x1e4bb0eb1cbf5b09LL; + function->parameter_size = 0x772beee89114358aLL; + Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, + file, 67519080 }; + function->lines.push_back(line); + m.AddFunction(function); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 file_name.cc\n" + "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" + " function_name\n" + "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", + contents.c_str()); +} + +TEST(Write, RelativeLoadAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Some source files. We will expect to see them in lexicographic order. + Module::File *file1 = m.FindFile("filename-b.cc"); + Module::File *file2 = m.FindFile("filename-a.cc"); + + // A function. + Module::Function *function = new(Module::Function); + function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; + function->address = 0xbec774ea5dd935f3LL; + function->size = 0x2922088f98d3f6fcLL; + function->parameter_size = 0xe5e9aa008bd5f0d0LL; + + // Some source lines. The module should not sort these. + Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, + file1, 41676901 }; + Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, + file2, 67519080 }; + function->lines.push_back(line2); + function->lines.push_back(line1); + + m.AddFunction(function); + + // Some stack information. + Module::StackFrameEntry *entry = new Module::StackFrameEntry(); + entry->address = 0x30f9e5c83323973dULL; + entry->size = 0x49fc9ca7c7c13dc2ULL; + entry->initial_rules[".cfa"] = "he was a handsome man"; + entry->initial_rules["and"] = "what i want to know is"; + entry->rule_changes[0x30f9e5c83323973eULL]["how"] = + "do you like your blueeyed boy"; + entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; + m.AddStackFrameEntry(entry); + + // Set the load address. Doing this after adding all the data to + // the module must work fine. + m.SetLoadAddress(0x2ab698b0b6407073LL); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename-a.cc\n" + "FILE 1 filename-b.cc\n" + "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" + " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" + "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" + "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" + "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" + " .cfa: he was a handsome man" + " and: what i want to know is\n" + "STACK CFI 6434d177ce326cb" + " Mister: Death" + " how: do you like your blueeyed boy\n", + contents.c_str()); +} + +TEST(Write, OmitUnusedFiles) { + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Create some source files. + Module::File *file1 = m.FindFile("filename1"); + m.FindFile("filename2"); // not used by any line + Module::File *file3 = m.FindFile("filename3"); + + // Create a function. + Module::Function *function = new(Module::Function); + function->name = "function_name"; + function->address = 0x9b926d464f0b9384LL; + function->size = 0x4f524a4ba795e6a6LL; + function->parameter_size = 0xbbe8133a6641c9b7LL; + + // Source files that refer to some files, but not others. + Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, + file1, 137850127 }; + Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, + file3, 28113549 }; + function->lines.push_back(line1); + function->lines.push_back(line2); + m.AddFunction(function); + + m.AssignSourceIds(); + + vector vec; + m.GetFiles(&vec); + EXPECT_EQ((size_t) 3, vec.size()); + EXPECT_STREQ("filename1", vec[0]->name.c_str()); + EXPECT_NE(-1, vec[0]->source_id); + // Expect filename2 not to be used. + EXPECT_STREQ("filename2", vec[1]->name.c_str()); + EXPECT_EQ(-1, vec[1]->source_id); + EXPECT_STREQ("filename3", vec[2]->name.c_str()); + EXPECT_NE(-1, vec[2]->source_id); + + stringstream s; + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename1\n" + "FILE 1 filename3\n" + "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" + " function_name\n" + "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" + "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", + contents.c_str()); +} + +TEST(Write, NoCFI) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Some source files. We will expect to see them in lexicographic order. + Module::File *file1 = m.FindFile("filename.cc"); + + // A function. + Module::Function *function = new(Module::Function); + function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; + function->address = 0xbec774ea5dd935f3LL; + function->size = 0x2922088f98d3f6fcLL; + function->parameter_size = 0xe5e9aa008bd5f0d0LL; + + // Some source lines. The module should not sort these. + Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, + file1, 41676901 }; + function->lines.push_back(line1); + + m.AddFunction(function); + + // Some stack information. + Module::StackFrameEntry *entry = new Module::StackFrameEntry(); + entry->address = 0x30f9e5c83323973dULL; + entry->size = 0x49fc9ca7c7c13dc2ULL; + entry->initial_rules[".cfa"] = "he was a handsome man"; + entry->initial_rules["and"] = "what i want to know is"; + entry->rule_changes[0x30f9e5c83323973eULL]["how"] = + "do you like your blueeyed boy"; + entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; + m.AddStackFrameEntry(entry); + + // Set the load address. Doing this after adding all the data to + // the module must work fine. + m.SetLoadAddress(0x2ab698b0b6407073LL); + + m.Write(s, NO_CFI); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename.cc\n" + "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" + " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" + "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", + contents.c_str()); +} + +TEST(Construct, AddFunctions) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two functions. + Module::Function *function1 = new(Module::Function); + function1->name = "_without_form"; + function1->address = 0xd35024aa7ca7da5cLL; + function1->size = 0x200b26e605f99071LL; + function1->parameter_size = 0xf14ac4fed48c4a99LL; + + Module::Function *function2 = new(Module::Function); + function2->name = "_and_void"; + function2->address = 0x2987743d0b35b13fLL; + function2->size = 0xb369db048deb3010LL; + function2->parameter_size = 0x938e556cb5a79988LL; + + // Put them in a vector. + vector vec; + vec.push_back(function1); + vec.push_back(function2); + + m.AddFunctions(vec.begin(), vec.end()); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" + " _and_void\n" + "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); + + // Check that m.GetFunctions returns the functions we expect. + vec.clear(); + m.GetFunctions(&vec, vec.end()); + EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); + EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); + EXPECT_EQ((size_t) 2, vec.size()); +} + +TEST(Construct, AddFrames) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // First STACK CFI entry, with no initial rules or deltas. + Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); + entry1->address = 0xddb5f41285aa7757ULL; + entry1->size = 0x1486493370dc5073ULL; + m.AddStackFrameEntry(entry1); + + // Second STACK CFI entry, with initial rules but no deltas. + Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); + entry2->address = 0x8064f3af5e067e38ULL; + entry2->size = 0x0de2a5ee55509407ULL; + entry2->initial_rules[".cfa"] = "I think that I shall never see"; + entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; + entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; + m.AddStackFrameEntry(entry2); + + // Third STACK CFI entry, with initial rules and deltas. + Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); + entry3->address = 0x5e8d0db0a7075c6cULL; + entry3->size = 0x1c7edb12a7aea229ULL; + entry3->initial_rules[".cfa"] = "Whose woods are these"; + entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = + "the village though"; + entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + "he will not see me stopping here"; + entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = + "his house is in"; + entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = + "I think I know"; + m.AddStackFrameEntry(entry3); + + // Check that Write writes STACK CFI records properly. + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" + "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" + " .cfa: I think that I shall never see" + " cannoli: a tree whose hungry mouth is prest" + " stromboli: a poem lovely as a tree\n" + "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" + " .cfa: Whose woods are these\n" + "STACK CFI 36682fad3763ffff" + " .cfa: I think I know" + " stromboli: his house is in\n" + "STACK CFI 47ceb0f63c269d7f" + " calzone: the village though" + " cannoli: he will not see me stopping here\n", + contents.c_str()); + + // Check that GetStackFrameEntries works. + vector entries; + m.GetStackFrameEntries(&entries); + ASSERT_EQ(3U, entries.size()); + // Check first entry. + EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); + EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); + ASSERT_EQ(0U, entries[0]->initial_rules.size()); + ASSERT_EQ(0U, entries[0]->rule_changes.size()); + // Check second entry. + EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); + EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); + ASSERT_EQ(3U, entries[1]->initial_rules.size()); + Module::RuleMap entry2_initial; + entry2_initial[".cfa"] = "I think that I shall never see"; + entry2_initial["stromboli"] = "a poem lovely as a tree"; + entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; + EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); + ASSERT_EQ(0U, entries[1]->rule_changes.size()); + // Check third entry. + EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); + EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); + Module::RuleMap entry3_initial; + entry3_initial[".cfa"] = "Whose woods are these"; + EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); + Module::RuleChangeMap entry3_changes; + entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; + entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; + entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; + entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + "he will not see me stopping here"; + EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); +} + +TEST(Construct, UniqueFiles) { + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + Module::File *file1 = m.FindFile("foo"); + Module::File *file2 = m.FindFile(string("bar")); + Module::File *file3 = m.FindFile(string("foo")); + Module::File *file4 = m.FindFile("bar"); + EXPECT_NE(file1, file2); + EXPECT_EQ(file1, file3); + EXPECT_EQ(file2, file4); + EXPECT_EQ(file1, m.FindExistingFile("foo")); + EXPECT_TRUE(m.FindExistingFile("baz") == NULL); +} + +TEST(Construct, DuplicateFunctions) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two functions. + Module::Function *function1 = generate_duplicate_function("_without_form"); + Module::Function *function2 = generate_duplicate_function("_without_form"); + + m.AddFunction(function1); + m.AddFunction(function2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); +} + +TEST(Construct, FunctionsWithSameAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two functions. + Module::Function *function1 = generate_duplicate_function("_without_form"); + Module::Function *function2 = generate_duplicate_function("_and_void"); + + m.AddFunction(function1); + m.AddFunction(function2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _and_void\n" + "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); +} + +// Externs should be written out as PUBLIC records, sorted by +// address. +TEST(Construct, Externs) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two externs. + Module::Extern *extern1 = new(Module::Extern); + extern1->address = 0xffff; + extern1->name = "_abc"; + Module::Extern *extern2 = new(Module::Extern); + extern2->address = 0xaaaa; + extern2->name = "_xyz"; + + m.AddExtern(extern1); + m.AddExtern(extern2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " + MODULE_ID " " MODULE_NAME "\n" + "PUBLIC aaaa 0 _xyz\n" + "PUBLIC ffff 0 _abc\n", + contents.c_str()); +} + +// Externs with the same address should only keep the first entry +// added. +TEST(Construct, DuplicateExterns) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two externs. + Module::Extern *extern1 = new(Module::Extern); + extern1->address = 0xffff; + extern1->name = "_xyz"; + Module::Extern *extern2 = new(Module::Extern); + extern2->address = 0xffff; + extern2->name = "_abc"; + + m.AddExtern(extern1); + m.AddExtern(extern2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " + MODULE_ID " " MODULE_NAME "\n" + "PUBLIC ffff 0 _xyz\n", + contents.c_str()); +} diff --git a/breakpad/common/scoped_ptr.h b/breakpad/common/scoped_ptr.h new file mode 100644 index 0000000000..2dbc40df3b --- /dev/null +++ b/breakpad/common/scoped_ptr.h @@ -0,0 +1,335 @@ +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::auto_ptr if your needs are more complex. + +// *** NOTE *** +// If your scoped_ptr is a class member of class FOO pointing to a +// forward declared type BAR (as shown below), then you MUST use a non-inlined +// version of the destructor. The destructor of a scoped_ptr (called from +// FOO's destructor) must have a complete definition of BAR in order to +// destroy it. Example: +// +// -- foo.h -- +// class BAR; +// +// class FOO { +// public: +// FOO(); +// ~FOO(); // Required for sources that instantiate class FOO to compile! +// +// private: +// scoped_ptr bar_; +// }; +// +// -- foo.cc -- +// #include "foo.h" +// FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition. + +// scoped_ptr_malloc added by Google +// When one of these goes out of scope, instead of doing a delete or +// delete[], it calls free(). scoped_ptr_malloc is likely to see +// much more use than any other specializations. + +// release() added by Google +// Use this to conditionally transfer ownership of a heap-allocated object +// to the caller, usually on method success. + +#ifndef COMMON_SCOPED_PTR_H_ +#define COMMON_SCOPED_PTR_H_ + +#include // for std::ptrdiff_t +#include // for assert +#include // for free() decl + +namespace google_breakpad { + +template +class scoped_ptr { + private: + + T* ptr; + + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + public: + + typedef T element_type; + + explicit scoped_ptr(T* p = 0): ptr(p) {} + + ~scoped_ptr() { + typedef char type_must_be_complete[sizeof(T)]; + delete ptr; + } + + void reset(T* p = 0) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + delete ptr; + ptr = p; + } + } + + T& operator*() const { + assert(ptr != 0); + return *ptr; + } + + T* operator->() const { + assert(ptr != 0); + return ptr; + } + + bool operator==(T* p) const { + return ptr == p; + } + + bool operator!=(T* p) const { + return ptr != p; + } + + T* get() const { + return ptr; + } + + void swap(scoped_ptr & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + private: + + // no reason to use these: each scoped_ptr should have its own object + template bool operator==(scoped_ptr const& p) const; + template bool operator!=(scoped_ptr const& p) const; +}; + +template inline +void swap(scoped_ptr& a, scoped_ptr& b) { + a.swap(b); +} + +template inline +bool operator==(T* p, const scoped_ptr& b) { + return p == b.get(); +} + +template inline +bool operator!=(T* p, const scoped_ptr& b) { + return p != b.get(); +} + +// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to +// is guaranteed, either on destruction of the scoped_array or via an explicit +// reset(). Use shared_array or std::vector if your needs are more complex. + +template +class scoped_array { + private: + + T* ptr; + + scoped_array(scoped_array const &); + scoped_array & operator=(scoped_array const &); + + public: + + typedef T element_type; + + explicit scoped_array(T* p = 0) : ptr(p) {} + + ~scoped_array() { + typedef char type_must_be_complete[sizeof(T)]; + delete[] ptr; + } + + void reset(T* p = 0) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + delete [] ptr; + ptr = p; + } + } + + T& operator[](std::ptrdiff_t i) const { + assert(ptr != 0); + assert(i >= 0); + return ptr[i]; + } + + bool operator==(T* p) const { + return ptr == p; + } + + bool operator!=(T* p) const { + return ptr != p; + } + + T* get() const { + return ptr; + } + + void swap(scoped_array & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + private: + + // no reason to use these: each scoped_array should have its own object + template bool operator==(scoped_array const& p) const; + template bool operator!=(scoped_array const& p) const; +}; + +template inline +void swap(scoped_array& a, scoped_array& b) { + a.swap(b); +} + +template inline +bool operator==(T* p, const scoped_array& b) { + return p == b.get(); +} + +template inline +bool operator!=(T* p, const scoped_array& b) { + return p != b.get(); +} + + +// This class wraps the c library function free() in a class that can be +// passed as a template argument to scoped_ptr_malloc below. +class ScopedPtrMallocFree { + public: + inline void operator()(void* x) const { + free(x); + } +}; + +// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a +// second template argument, the functor used to free the object. + +template +class scoped_ptr_malloc { + private: + + T* ptr; + + scoped_ptr_malloc(scoped_ptr_malloc const &); + scoped_ptr_malloc & operator=(scoped_ptr_malloc const &); + + public: + + typedef T element_type; + + explicit scoped_ptr_malloc(T* p = 0): ptr(p) {} + + ~scoped_ptr_malloc() { + typedef char type_must_be_complete[sizeof(T)]; + free_((void*) ptr); + } + + void reset(T* p = 0) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + free_((void*) ptr); + ptr = p; + } + } + + T& operator*() const { + assert(ptr != 0); + return *ptr; + } + + T* operator->() const { + assert(ptr != 0); + return ptr; + } + + bool operator==(T* p) const { + return ptr == p; + } + + bool operator!=(T* p) const { + return ptr != p; + } + + T* get() const { + return ptr; + } + + void swap(scoped_ptr_malloc & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + private: + + // no reason to use these: each scoped_ptr_malloc should have its own object + template + bool operator==(scoped_ptr_malloc const& p) const; + template + bool operator!=(scoped_ptr_malloc const& p) const; + + static FreeProc const free_; +}; + +template +FP const scoped_ptr_malloc::free_ = FP(); + +template inline +void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { + a.swap(b); +} + +template inline +bool operator==(T* p, const scoped_ptr_malloc& b) { + return p == b.get(); +} + +template inline +bool operator!=(T* p, const scoped_ptr_malloc& b) { + return p != b.get(); +} + +} // namespace google_breakpad + +#endif // COMMON_SCOPED_PTR_H_ diff --git a/breakpad/common/simple_string_dictionary.cc b/breakpad/common/simple_string_dictionary.cc new file mode 100644 index 0000000000..e0a74ceeb4 --- /dev/null +++ b/breakpad/common/simple_string_dictionary.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { + +namespace { + +// In C++98 (ISO 14882), section 9.5.1 says that a union cannot have a member +// with a non-trivial ctor, copy ctor, dtor, or assignment operator. Use this +// property to ensure that Entry remains POD. +union Compile_Assert { + NonAllocatingMap<1, 1, 1>::Entry Compile_Assert__entry_must_be_pod; +}; + +} + +} // namespace google_breakpad diff --git a/breakpad/common/simple_string_dictionary.h b/breakpad/common/simple_string_dictionary.h new file mode 100644 index 0000000000..e241aff54a --- /dev/null +++ b/breakpad/common/simple_string_dictionary.h @@ -0,0 +1,263 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_SIMPLE_STRING_DICTIONARY_H_ +#define COMMON_SIMPLE_STRING_DICTIONARY_H_ + +#include +#include + +#include "common/basictypes.h" + +namespace google_breakpad { + +// Opaque type for the serialized representation of a NonAllocatingMap. One is +// created in NonAllocatingMap::Serialize and can be deserialized using one of +// the constructors. +struct SerializedNonAllocatingMap; + +// NonAllocatingMap is an implementation of a map/dictionary collection that +// uses a fixed amount of storage, so that it does not perform any dynamic +// allocations for its operations. +// +// The actual map storage (the Entry) is guaranteed to be POD, so that it can +// be transmitted over various IPC mechanisms. +// +// The template parameters control the amount of storage used for the key, +// value, and map. The KeySize and ValueSize are measured in bytes, not glyphs, +// and includes space for a \0 byte. This gives space for KeySize-1 and +// ValueSize-1 characters in an entry. NumEntries is the total number of +// entries that will fit in the map. +template +class NonAllocatingMap { + public: + // Constant and publicly accessible versions of the template parameters. + static const size_t key_size = KeySize; + static const size_t value_size = ValueSize; + static const size_t num_entries = NumEntries; + + // An Entry object is a single entry in the map. If the key is a 0-length + // NUL-terminated string, the entry is empty. + struct Entry { + char key[KeySize]; + char value[ValueSize]; + + bool is_active() const { + return key[0] != '\0'; + } + }; + + // An Iterator can be used to iterate over all the active entries in a + // NonAllocatingMap. + class Iterator { + public: + explicit Iterator(const NonAllocatingMap& map) + : map_(map), + current_(0) { + } + + // Returns the next entry in the map, or NULL if at the end of the + // collection. + const Entry* Next() { + while (current_ < map_.num_entries) { + const Entry* entry = &map_.entries_[current_++]; + if (entry->is_active()) { + return entry; + } + } + return NULL; + } + + private: + const NonAllocatingMap& map_; + size_t current_; + + DISALLOW_COPY_AND_ASSIGN(Iterator); + }; + + NonAllocatingMap() : entries_() { + } + + NonAllocatingMap(const NonAllocatingMap& other) { + *this = other; + } + + NonAllocatingMap& operator=(const NonAllocatingMap& other) { + assert(other.key_size == key_size); + assert(other.value_size == value_size); + assert(other.num_entries == num_entries); + if (other.key_size == key_size && other.value_size == value_size && + other.num_entries == num_entries) { + memcpy(entries_, other.entries_, sizeof(entries_)); + } + return *this; + } + + // Constructs a map from its serialized form. |map| should be the out + // parameter from Serialize() and |size| should be its return value. + NonAllocatingMap(const SerializedNonAllocatingMap* map, size_t size) { + assert(size == sizeof(entries_)); + if (size == sizeof(entries_)) { + memcpy(entries_, map, size); + } + } + + // Returns the number of active key/value pairs. The upper limit for this + // is NumEntries. + size_t GetCount() const { + size_t count = 0; + for (size_t i = 0; i < num_entries; ++i) { + if (entries_[i].is_active()) { + ++count; + } + } + return count; + } + + // Given |key|, returns its corresponding |value|. |key| must not be NULL. If + // the key is not found, NULL is returned. + const char* GetValueForKey(const char* key) const { + assert(key); + if (!key) + return NULL; + + const Entry* entry = GetConstEntryForKey(key); + if (!entry) + return NULL; + + return entry->value; + } + + // Stores |value| into |key|, replacing the existing value if |key| is + // already present. |key| must not be NULL. If |value| is NULL, the key is + // removed from the map. If there is no more space in the map, then the + // operation silently fails. + void SetKeyValue(const char* key, const char* value) { + if (!value) { + RemoveKey(key); + return; + } + + assert(key); + if (!key) + return; + + // Key must not be an empty string. + assert(key[0] != '\0'); + if (key[0] == '\0') + return; + + Entry* entry = GetEntryForKey(key); + + // If it does not yet exist, attempt to insert it. + if (!entry) { + for (size_t i = 0; i < num_entries; ++i) { + if (!entries_[i].is_active()) { + entry = &entries_[i]; + + assert(strlen(key) < key_size); + + strncpy(entry->key, key, key_size); + entry->key[key_size - 1] = '\0'; + + break; + } + } + } + + // If the map is out of space, entry will be NULL. + if (!entry) + return; + +#ifndef NDEBUG + // Sanity check that the key only appears once. + int count = 0; + for (size_t i = 0; i < num_entries; ++i) { + if (strncmp(entries_[i].key, key, key_size) == 0) + ++count; + } + assert(count == 1); +#endif + + assert(strlen(value) < value_size); + strncpy(entry->value, value, value_size); + entry->value[value_size - 1] = '\0'; + } + + // Given |key|, removes any associated value. |key| must not be NULL. If + // the key is not found, this is a noop. + void RemoveKey(const char* key) { + assert(key); + if (!key) + return; + + Entry* entry = GetEntryForKey(key); + if (entry) { + entry->key[0] = '\0'; + entry->value[0] = '\0'; + } + +#ifndef NDEBUG + assert(GetEntryForKey(key) == NULL); +#endif + } + + // Places a serialized version of the map into |map| and returns the size. + // Both of these should be passed to the deserializing constructor. Note that + // the serialized |map| is scoped to the lifetime of the non-serialized + // instance of this class. The |map| can be copied across IPC boundaries. + size_t Serialize(const SerializedNonAllocatingMap** map) const { + *map = reinterpret_cast(entries_); + return sizeof(entries_); + } + + private: + const Entry* GetConstEntryForKey(const char* key) const { + for (size_t i = 0; i < num_entries; ++i) { + if (strncmp(key, entries_[i].key, key_size) == 0) { + return &entries_[i]; + } + } + return NULL; + } + + Entry* GetEntryForKey(const char* key) { + return const_cast(GetConstEntryForKey(key)); + } + + Entry entries_[NumEntries]; +}; + +// For historical reasons this specialized version is available with the same +// size factors as a previous implementation. +typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary; + +} // namespace google_breakpad + +#endif // COMMON_SIMPLE_STRING_DICTIONARY_H_ diff --git a/breakpad/common/simple_string_dictionary_unittest.cc b/breakpad/common/simple_string_dictionary_unittest.cc new file mode 100644 index 0000000000..5fbc481c54 --- /dev/null +++ b/breakpad/common/simple_string_dictionary_unittest.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "breakpad_googletest_includes.h" +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { + +TEST(NonAllocatingMapTest, Entry) { + typedef NonAllocatingMap<5, 9, 15> TestMap; + TestMap map; + + const TestMap::Entry* entry = TestMap::Iterator(map).Next(); + EXPECT_FALSE(entry); + + // Try setting a key/value and then verify. + map.SetKeyValue("key1", "value1"); + entry = TestMap::Iterator(map).Next(); + ASSERT_TRUE(entry); + EXPECT_STREQ(entry->key, "key1"); + EXPECT_STREQ(entry->value, "value1"); + + // Try setting a new value. + map.SetKeyValue("key1", "value3"); + EXPECT_STREQ(entry->value, "value3"); + + // Make sure the key didn't change. + EXPECT_STREQ(entry->key, "key1"); + + // Clear the entry and verify the key and value are empty strings. + map.RemoveKey("key1"); + EXPECT_FALSE(entry->is_active()); + EXPECT_EQ(strlen(entry->key), 0u); + EXPECT_EQ(strlen(entry->value), 0u); +} + +TEST(NonAllocatingMapTest, SimpleStringDictionary) { + // Make a new dictionary + SimpleStringDictionary dict; + + // Set three distinct values on three keys + dict.SetKeyValue("key1", "value1"); + dict.SetKeyValue("key2", "value2"); + dict.SetKeyValue("key3", "value3"); + + EXPECT_NE(dict.GetValueForKey("key1"), "value1"); + EXPECT_NE(dict.GetValueForKey("key2"), "value2"); + EXPECT_NE(dict.GetValueForKey("key3"), "value3"); + EXPECT_EQ(dict.GetCount(), 3u); + // try an unknown key + EXPECT_FALSE(dict.GetValueForKey("key4")); + + // Remove a key + dict.RemoveKey("key3"); + + // Now make sure it's not there anymore + EXPECT_FALSE(dict.GetValueForKey("key3")); + + // Remove by setting value to NULL + dict.SetKeyValue("key2", NULL); + + // Now make sure it's not there anymore + EXPECT_FALSE(dict.GetValueForKey("key2")); +} + +TEST(NonAllocatingMapTest, CopyAndAssign) { + NonAllocatingMap<10, 10, 10> map; + map.SetKeyValue("one", "a"); + map.SetKeyValue("two", "b"); + map.SetKeyValue("three", "c"); + map.RemoveKey("two"); + EXPECT_EQ(2u, map.GetCount()); + + // Test copy. + NonAllocatingMap<10, 10, 10> map_copy(map); + EXPECT_EQ(2u, map_copy.GetCount()); + EXPECT_STREQ("a", map_copy.GetValueForKey("one")); + EXPECT_STREQ("c", map_copy.GetValueForKey("three")); + map_copy.SetKeyValue("four", "d"); + EXPECT_STREQ("d", map_copy.GetValueForKey("four")); + EXPECT_FALSE(map.GetValueForKey("four")); + + // Test assign. + NonAllocatingMap<10, 10, 10> map_assign; + map_assign = map; + EXPECT_EQ(2u, map_assign.GetCount()); + EXPECT_STREQ("a", map_assign.GetValueForKey("one")); + EXPECT_STREQ("c", map_assign.GetValueForKey("three")); + map_assign.SetKeyValue("four", "d"); + EXPECT_STREQ("d", map_assign.GetValueForKey("four")); + EXPECT_FALSE(map.GetValueForKey("four")); + + map.RemoveKey("one"); + EXPECT_FALSE(map.GetValueForKey("one")); + EXPECT_STREQ("a", map_copy.GetValueForKey("one")); + EXPECT_STREQ("a", map_assign.GetValueForKey("one")); +} + +// Add a bunch of values to the dictionary, remove some entries in the middle, +// and then add more. +TEST(NonAllocatingMapTest, Iterator) { + SimpleStringDictionary* dict = new SimpleStringDictionary(); + ASSERT_TRUE(dict); + + char key[SimpleStringDictionary::key_size]; + char value[SimpleStringDictionary::value_size]; + + const int kDictionaryCapacity = SimpleStringDictionary::num_entries; + const int kPartitionIndex = kDictionaryCapacity - 5; + + // We assume at least this size in the tests below + ASSERT_GE(kDictionaryCapacity, 64); + + // We'll keep track of the number of key/value pairs we think should + // be in the dictionary + int expectedDictionarySize = 0; + + // Set a bunch of key/value pairs like key0/value0, key1/value1, ... + for (int i = 0; i < kPartitionIndex; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize = kPartitionIndex; + + // set a couple of the keys twice (with the same value) - should be nop + dict->SetKeyValue("key2", "value2"); + dict->SetKeyValue("key4", "value4"); + dict->SetKeyValue("key15", "value15"); + + // Remove some random elements in the middle + dict->RemoveKey("key7"); + dict->RemoveKey("key18"); + dict->RemoveKey("key23"); + dict->RemoveKey("key31"); + expectedDictionarySize -= 4; // we just removed four key/value pairs + + // Set some more key/value pairs like key59/value59, key60/value60, ... + for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize += kDictionaryCapacity - kPartitionIndex; + + // Now create an iterator on the dictionary + SimpleStringDictionary::Iterator iter(*dict); + + // We then verify that it iterates through exactly the number of + // key/value pairs we expect, and that they match one-for-one with what we + // would expect. The ordering of the iteration does not matter... + + // used to keep track of number of occurrences found for key/value pairs + int count[kDictionaryCapacity]; + memset(count, 0, sizeof(count)); + + int totalCount = 0; + + const SimpleStringDictionary::Entry* entry; + while ((entry = iter.Next())) { + totalCount++; + + // Extract keyNumber from a string of the form key + int keyNumber; + sscanf(entry->key, "key%d", &keyNumber); + + // Extract valueNumber from a string of the form value + int valueNumber; + sscanf(entry->value, "value%d", &valueNumber); + + // The value number should equal the key number since that's how we set them + EXPECT_EQ(keyNumber, valueNumber); + + // Key and value numbers should be in proper range: + // 0 <= keyNumber < kDictionaryCapacity + bool isKeyInGoodRange = + (keyNumber >= 0 && keyNumber < kDictionaryCapacity); + bool isValueInGoodRange = + (valueNumber >= 0 && valueNumber < kDictionaryCapacity); + EXPECT_TRUE(isKeyInGoodRange); + EXPECT_TRUE(isValueInGoodRange); + + if (isKeyInGoodRange && isValueInGoodRange) { + ++count[keyNumber]; + } + } + + // Make sure each of the key/value pairs showed up exactly one time, except + // for the ones which we removed. + for (size_t i = 0; i < kDictionaryCapacity; ++i) { + // Skip over key7, key18, key23, and key31, since we removed them + if (!(i == 7 || i == 18 || i == 23 || i == 31)) { + EXPECT_EQ(count[i], 1); + } + } + + // Make sure the number of iterations matches the expected dictionary size. + EXPECT_EQ(totalCount, expectedDictionarySize); +} + + +TEST(NonAllocatingMapTest, AddRemove) { + NonAllocatingMap<5, 7, 6> map; + map.SetKeyValue("rob", "ert"); + map.SetKeyValue("mike", "pink"); + map.SetKeyValue("mark", "allays"); + + EXPECT_EQ(3u, map.GetCount()); + EXPECT_STREQ("ert", map.GetValueForKey("rob")); + EXPECT_STREQ("pink", map.GetValueForKey("mike")); + EXPECT_STREQ("allays", map.GetValueForKey("mark")); + + map.RemoveKey("mike"); + + EXPECT_EQ(2u, map.GetCount()); + EXPECT_FALSE(map.GetValueForKey("mike")); + + map.SetKeyValue("mark", "mal"); + EXPECT_EQ(2u, map.GetCount()); + EXPECT_STREQ("mal", map.GetValueForKey("mark")); + + map.RemoveKey("mark"); + EXPECT_EQ(1u, map.GetCount()); + EXPECT_FALSE(map.GetValueForKey("mark")); +} + +TEST(NonAllocatingMapTest, Serialize) { + typedef NonAllocatingMap<4, 5, 7> TestMap; + TestMap map; + map.SetKeyValue("one", "abc"); + map.SetKeyValue("two", "def"); + map.SetKeyValue("tre", "hig"); + + EXPECT_STREQ("abc", map.GetValueForKey("one")); + EXPECT_STREQ("def", map.GetValueForKey("two")); + EXPECT_STREQ("hig", map.GetValueForKey("tre")); + + const SerializedNonAllocatingMap* serialized; + size_t size = map.Serialize(&serialized); + + SerializedNonAllocatingMap* serialized_copy = + reinterpret_cast(malloc(size)); + ASSERT_TRUE(serialized_copy); + memcpy(serialized_copy, serialized, size); + + TestMap deserialized(serialized_copy, size); + free(serialized_copy); + + EXPECT_EQ(3u, deserialized.GetCount()); + EXPECT_STREQ("abc", deserialized.GetValueForKey("one")); + EXPECT_STREQ("def", deserialized.GetValueForKey("two")); + EXPECT_STREQ("hig", deserialized.GetValueForKey("tre")); +} + +// Running out of space shouldn't crash. +TEST(NonAllocatingMapTest, OutOfSpace) { + NonAllocatingMap<3, 2, 2> map; + map.SetKeyValue("a", "1"); + map.SetKeyValue("b", "2"); + map.SetKeyValue("c", "3"); + EXPECT_EQ(2u, map.GetCount()); + EXPECT_FALSE(map.GetValueForKey("c")); +} + +#ifndef NDEBUG + +TEST(NonAllocatingMapTest, KeyTooLong) { + NonAllocatingMap<3, 10, 12> map; + map.SetKeyValue("ab", "cdefghi"); + ASSERT_DEATH(map.SetKeyValue("abcdef", "1"), ""); +} + +TEST(NonAllocatingMapTest, ValueTooLong) { + NonAllocatingMap<9, 3, 8> map; + map.SetKeyValue("abcd", "ab"); + ASSERT_DEATH(map.SetKeyValue("abcd", "abc"), ""); +} + +TEST(NonAllocatingMapTest, NullKey) { + NonAllocatingMap<4, 6, 6> map; + ASSERT_DEATH(map.SetKeyValue(NULL, "hello"), ""); + + map.SetKeyValue("hi", "there"); + ASSERT_DEATH(map.GetValueForKey(NULL), ""); + EXPECT_STREQ("there", map.GetValueForKey("hi")); + + ASSERT_DEATH(map.GetValueForKey(NULL), ""); + map.RemoveKey("hi"); + EXPECT_EQ(0u, map.GetCount()); +} + +#endif // !NDEBUG + +} // namespace google_breakpad diff --git a/breakpad/common/stabs_reader.cc b/breakpad/common/stabs_reader.cc new file mode 100644 index 0000000000..6019fc7ee2 --- /dev/null +++ b/breakpad/common/stabs_reader.cc @@ -0,0 +1,315 @@ +// Copyright (c) 2010 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// This file implements the google_breakpad::StabsReader class. +// See stabs_reader.h. + +#include "common/stabs_reader.h" + +#include +#include +#include + +#include + +#include "common/using_std_string.h" + +using std::vector; + +namespace google_breakpad { + +StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer, + bool big_endian, size_t value_size) + : value_size_(value_size), cursor_(buffer, big_endian) { + // Actually, we could handle weird sizes just fine, but they're + // probably mistakes --- expressed in bits, say. + assert(value_size == 4 || value_size == 8); + entry_.index = 0; + Fetch(); +} + +void StabsReader::EntryIterator::Fetch() { + cursor_ + .Read(4, false, &entry_.name_offset) + .Read(1, false, &entry_.type) + .Read(1, false, &entry_.other) + .Read(2, false, &entry_.descriptor) + .Read(value_size_, false, &entry_.value); + entry_.at_end = !cursor_; +} + +StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, + const uint8_t *stabstr, size_t stabstr_size, + bool big_endian, size_t value_size, bool unitized, + StabsHandler *handler) + : entries_(stab, stab_size), + strings_(stabstr, stabstr_size), + iterator_(&entries_, big_endian, value_size), + unitized_(unitized), + handler_(handler), + string_offset_(0), + next_cu_string_offset_(0), + current_source_file_(NULL) { } + +const char *StabsReader::SymbolString() { + ptrdiff_t offset = string_offset_ + iterator_->name_offset; + if (offset < 0 || (size_t) offset >= strings_.Size()) { + handler_->Warning("symbol %d: name offset outside the string section\n", + iterator_->index); + // Return our null string, to keep our promise about all names being + // taken from the string section. + offset = 0; + } + return reinterpret_cast(strings_.start + offset); +} + +bool StabsReader::Process() { + while (!iterator_->at_end) { + if (iterator_->type == N_SO) { + if (! ProcessCompilationUnit()) + return false; + } else if (iterator_->type == N_UNDF && unitized_) { + // In unitized STABS (including Linux STABS, and pretty much anything + // else that puts STABS data in sections), at the head of each + // compilation unit's entries there is an N_UNDF stab giving the + // number of symbols in the compilation unit, and the number of bytes + // that compilation unit's strings take up in the .stabstr section. + // Each CU's strings are separate; the n_strx values are offsets + // within the current CU's portion of the .stabstr section. + // + // As an optimization, the GNU linker combines all the + // compilation units into one, with a single N_UNDF at the + // beginning. However, other linkers, like Gold, do not perform + // this optimization. + string_offset_ = next_cu_string_offset_; + next_cu_string_offset_ = iterator_->value; + ++iterator_; + } +#if defined(HAVE_MACH_O_NLIST_H) + // Export symbols in Mach-O binaries look like this. + // This is necessary in order to be able to dump symbols + // from OS X system libraries. + else if ((iterator_->type & N_STAB) == 0 && + (iterator_->type & N_TYPE) == N_SECT) { + ProcessExtern(); + } +#endif + else { + ++iterator_; + } + } + return true; +} + +bool StabsReader::ProcessCompilationUnit() { + assert(!iterator_->at_end && iterator_->type == N_SO); + + // There may be an N_SO entry whose name ends with a slash, + // indicating the directory in which the compilation occurred. + // The build directory defaults to NULL. + const char *build_directory = NULL; + { + const char *name = SymbolString(); + if (name[0] && name[strlen(name) - 1] == '/') { + build_directory = name; + ++iterator_; + } + } + + // We expect to see an N_SO entry with a filename next, indicating + // the start of the compilation unit. + { + if (iterator_->at_end || iterator_->type != N_SO) + return true; + const char *name = SymbolString(); + if (name[0] == '\0') { + // This seems to be a stray end-of-compilation-unit marker; + // consume it, but don't report the end, since we didn't see a + // beginning. + ++iterator_; + return true; + } + current_source_file_ = name; + } + + if (! handler_->StartCompilationUnit(current_source_file_, + iterator_->value, + build_directory)) + return false; + + ++iterator_; + + // The STABS documentation says that some compilers may emit + // additional N_SO entries with names immediately following the + // first, and that they should be ignored. However, the original + // Breakpad STABS reader doesn't ignore them, so we won't either. + + // Process the body of the compilation unit, up to the next N_SO. + while (!iterator_->at_end && iterator_->type != N_SO) { + if (iterator_->type == N_FUN) { + if (! ProcessFunction()) + return false; + } else if (iterator_->type == N_SLINE) { + // Mac OS X STABS place SLINE records before functions. + Line line; + // The value of an N_SLINE entry that appears outside a function is + // the absolute address of the line. + line.address = iterator_->value; + line.filename = current_source_file_; + // The n_desc of a N_SLINE entry is the line number. It's a + // signed 16-bit field; line numbers from 32768 to 65535 are + // stored as n-65536. + line.number = (uint16_t) iterator_->descriptor; + queued_lines_.push_back(line); + ++iterator_; + } else if (iterator_->type == N_SOL) { + current_source_file_ = SymbolString(); + ++iterator_; + } else { + // Ignore anything else. + ++iterator_; + } + } + + // An N_SO with an empty name indicates the end of the compilation + // unit. Default to zero. + uint64_t ending_address = 0; + if (!iterator_->at_end) { + assert(iterator_->type == N_SO); + const char *name = SymbolString(); + if (name[0] == '\0') { + ending_address = iterator_->value; + ++iterator_; + } + } + + if (! handler_->EndCompilationUnit(ending_address)) + return false; + + queued_lines_.clear(); + + return true; +} + +bool StabsReader::ProcessFunction() { + assert(!iterator_->at_end && iterator_->type == N_FUN); + + uint64_t function_address = iterator_->value; + // The STABS string for an N_FUN entry is the name of the function, + // followed by a colon, followed by type information for the + // function. We want to pass the name alone to StartFunction. + const char *stab_string = SymbolString(); + const char *name_end = strchr(stab_string, ':'); + if (! name_end) + name_end = stab_string + strlen(stab_string); + string name(stab_string, name_end - stab_string); + if (! handler_->StartFunction(name, function_address)) + return false; + ++iterator_; + + // If there were any SLINE records given before the function, report them now. + for (vector::const_iterator it = queued_lines_.begin(); + it != queued_lines_.end(); it++) { + if (!handler_->Line(it->address, it->filename, it->number)) + return false; + } + queued_lines_.clear(); + + while (!iterator_->at_end) { + if (iterator_->type == N_SO || iterator_->type == N_FUN) + break; + else if (iterator_->type == N_SLINE) { + // The value of an N_SLINE entry is the offset of the line from + // the function's start address. + uint64_t line_address = function_address + iterator_->value; + // The n_desc of a N_SLINE entry is the line number. It's a + // signed 16-bit field; line numbers from 32768 to 65535 are + // stored as n-65536. + uint16_t line_number = iterator_->descriptor; + if (! handler_->Line(line_address, current_source_file_, line_number)) + return false; + ++iterator_; + } else if (iterator_->type == N_SOL) { + current_source_file_ = SymbolString(); + ++iterator_; + } else + // Ignore anything else. + ++iterator_; + } + + // We've reached the end of the function. See if we can figure out its + // ending address. + uint64_t ending_address = 0; + if (!iterator_->at_end) { + assert(iterator_->type == N_SO || iterator_->type == N_FUN); + if (iterator_->type == N_FUN) { + const char *symbol_name = SymbolString(); + if (symbol_name[0] == '\0') { + // An N_FUN entry with no name is a terminator for this function; + // its value is the function's size. + ending_address = function_address + iterator_->value; + ++iterator_; + } else { + // An N_FUN entry with a name is the next function, and we can take + // its value as our ending address. Don't advance the iterator, as + // we'll use this symbol to start the next function as well. + ending_address = iterator_->value; + } + } else { + // An N_SO entry could be an end-of-compilation-unit marker, or the + // start of the next compilation unit, but in either case, its value + // is our ending address. We don't advance the iterator; + // ProcessCompilationUnit will decide what to do with this symbol. + ending_address = iterator_->value; + } + } + + if (! handler_->EndFunction(ending_address)) + return false; + + return true; +} + +bool StabsReader::ProcessExtern() { +#if defined(HAVE_MACH_O_NLIST_H) + assert(!iterator_->at_end && + (iterator_->type & N_STAB) == 0 && + (iterator_->type & N_TYPE) == N_SECT); +#endif + + // TODO(mark): only do symbols in the text section? + if (!handler_->Extern(SymbolString(), iterator_->value)) + return false; + + ++iterator_; + return true; +} + +} // namespace google_breakpad diff --git a/breakpad/common/stabs_reader.h b/breakpad/common/stabs_reader.h new file mode 100644 index 0000000000..d89afc0013 --- /dev/null +++ b/breakpad/common/stabs_reader.h @@ -0,0 +1,326 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// stabs_reader.h: Define StabsReader, a parser for STABS debugging +// information. A description of the STABS debugging format can be +// found at: +// +// http://sourceware.org/gdb/current/onlinedocs/stabs_toc.html +// +// The comments here assume you understand the format. +// +// This parser can handle big-endian and little-endian data, and the symbol +// values may be either 32 or 64 bits long. It handles both STABS in +// sections (as used on Linux) and STABS appearing directly in an +// a.out-like symbol table (as used in Darwin OS X Mach-O files). + +#ifndef COMMON_STABS_READER_H__ +#define COMMON_STABS_READER_H__ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_A_OUT_H +#include +#endif +#ifdef HAVE_MACH_O_NLIST_H +#include +#endif + +#include +#include + +#include "common/byte_cursor.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +class StabsHandler; + +class StabsReader { + public: + // Create a reader for the STABS debug information whose .stab section is + // being traversed by ITERATOR, and whose .stabstr section is referred to + // by STRINGS. The reader will call the member functions of HANDLER to + // report the information it finds, when the reader's 'Process' member + // function is called. + // + // BIG_ENDIAN should be true if the entries in the .stab section are in + // big-endian form, or false if they are in little-endian form. + // + // VALUE_SIZE should be either 4 or 8, indicating the size of the 'value' + // field in each entry in bytes. + // + // UNITIZED should be true if the STABS data is stored in units with + // N_UNDF headers. This is usually the case for STABS stored in sections, + // like .stab/.stabstr, and usually not the case for STABS stored in the + // actual symbol table; UNITIZED should be true when parsing Linux stabs, + // false when parsing Mac OS X STABS. For details, see: + // http://sourceware.org/gdb/current/onlinedocs/stabs/Stab-Section-Basics.html + // + // Note that, in ELF, the .stabstr section should be found using the + // 'sh_link' field of the .stab section header, not by name. + StabsReader(const uint8_t *stab, size_t stab_size, + const uint8_t *stabstr, size_t stabstr_size, + bool big_endian, size_t value_size, bool unitized, + StabsHandler *handler); + + // Process the STABS data, calling the handler's member functions to + // report what we find. While the handler functions return true, + // continue to process until we reach the end of the section. If we + // processed the entire section and all handlers returned true, + // return true. If any handler returned false, return false. + // + // This is only meant to be called once per StabsReader instance; + // resuming a prior processing pass that stopped abruptly isn't supported. + bool Process(); + + private: + + // An class for walking arrays of STABS entries. This isolates the main + // STABS reader from the exact format (size; endianness) of the entries + // themselves. + class EntryIterator { + public: + // The contents of a STABS entry, adjusted for the host's endianness, + // word size, 'struct nlist' layout, and so on. + struct Entry { + // True if this iterator has reached the end of the entry array. When + // this is set, the other members of this structure are not valid. + bool at_end; + + // The number of this entry within the list. + size_t index; + + // The current entry's name offset. This is the offset within the + // current compilation unit's strings, as establish by the N_UNDF entries. + size_t name_offset; + + // The current entry's type, 'other' field, descriptor, and value. + unsigned char type; + unsigned char other; + short descriptor; + uint64_t value; + }; + + // Create a EntryIterator walking the entries in BUFFER. Treat the + // entries as big-endian if BIG_ENDIAN is true, as little-endian + // otherwise. Assume each entry has a 'value' field whose size is + // VALUE_SIZE. + // + // This would not be terribly clean to extend to other format variations, + // but it's enough to handle Linux and Mac, and we'd like STABS to die + // anyway. + // + // For the record: on Linux, STABS entry values are always 32 bits, + // regardless of the architecture address size (don't ask me why); on + // Mac, they are 32 or 64 bits long. Oddly, the section header's entry + // size for a Linux ELF .stab section varies according to the ELF class + // from 12 to 20 even as the actual entries remain unchanged. + EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size); + + // Move to the next entry. This function's behavior is undefined if + // at_end() is true when it is called. + EntryIterator &operator++() { Fetch(); entry_.index++; return *this; } + + // Dereferencing this iterator produces a reference to an Entry structure + // that holds the current entry's values. The entry is owned by this + // EntryIterator, and will be invalidated at the next call to operator++. + const Entry &operator*() const { return entry_; } + const Entry *operator->() const { return &entry_; } + + private: + // Read the STABS entry at cursor_, and set entry_ appropriately. + void Fetch(); + + // The size of entries' value field, in bytes. + size_t value_size_; + + // A byte cursor traversing buffer_. + ByteCursor cursor_; + + // Values for the entry this iterator refers to. + Entry entry_; + }; + + // A source line, saved to be reported later. + struct Line { + uint64_t address; + const char *filename; + int number; + }; + + // Return the name of the current symbol. + const char *SymbolString(); + + // Process a compilation unit starting at symbol_. Return true + // to continue processing, or false to abort. + bool ProcessCompilationUnit(); + + // Process a function in current_source_file_ starting at symbol_. + // Return true to continue processing, or false to abort. + bool ProcessFunction(); + + // Process an exported function symbol. + // Return true to continue processing, or false to abort. + bool ProcessExtern(); + + // The STABS entries being parsed. + ByteBuffer entries_; + + // The string section to which the entries refer. + ByteBuffer strings_; + + // The iterator walking the STABS entries. + EntryIterator iterator_; + + // True if the data is "unitized"; see the explanation in the comment for + // StabsReader::StabsReader. + bool unitized_; + + StabsHandler *handler_; + + // The offset of the current compilation unit's strings within stabstr_. + size_t string_offset_; + + // The value string_offset_ should have for the next compilation unit, + // as established by N_UNDF entries. + size_t next_cu_string_offset_; + + // The current source file name. + const char *current_source_file_; + + // Mac OS X STABS place SLINE records before functions; we accumulate a + // vector of these until we see the FUN record, and then report them + // after the StartFunction call. + std::vector queued_lines_; +}; + +// Consumer-provided callback structure for the STABS reader. Clients +// of the STABS reader provide an instance of this structure. The +// reader then invokes the member functions of that instance to report +// the information it finds. +// +// The default definitions of the member functions do nothing, and return +// true so processing will continue. +class StabsHandler { + public: + StabsHandler() { } + virtual ~StabsHandler() { } + + // Some general notes about the handler callback functions: + + // Processing proceeds until the end of the .stabs section, or until + // one of these functions returns false. + + // The addresses given are as reported in the STABS info, without + // regard for whether the module may be loaded at different + // addresses at different times (a shared library, say). When + // processing STABS from an ELF shared library, the addresses given + // all assume the library is loaded at its nominal load address. + // They are *not* offsets from the nominal load address. If you + // want offsets, you must subtract off the library's nominal load + // address. + + // The arguments to these functions named FILENAME are all + // references to strings stored in the .stabstr section. Because + // both the Linux and Solaris linkers factor out duplicate strings + // from the .stabstr section, the consumer can assume that if two + // FILENAME values are different addresses, they represent different + // file names. + // + // Thus, it's safe to use (say) std::map, which does + // string address comparisons, not string content comparisons. + // Since all the strings are in same array of characters --- the + // .stabstr section --- comparing their addresses produces + // predictable, if not lexicographically meaningful, results. + + // Begin processing a compilation unit whose main source file is + // named FILENAME, and whose base address is ADDRESS. If + // BUILD_DIRECTORY is non-NULL, it is the name of the build + // directory in which the compilation occurred. + virtual bool StartCompilationUnit(const char *filename, uint64_t address, + const char *build_directory) { + return true; + } + + // Finish processing the compilation unit. If ADDRESS is non-zero, + // it is the ending address of the compilation unit. If ADDRESS is + // zero, then the compilation unit's ending address is not + // available, and the consumer must infer it by other means. + virtual bool EndCompilationUnit(uint64_t address) { return true; } + + // Begin processing a function named NAME, whose starting address is + // ADDRESS. This function belongs to the compilation unit that was + // most recently started but not ended. + // + // Note that, unlike filenames, NAME is not a pointer into the + // .stabstr section; this is because the name as it appears in the + // STABS data is followed by type information. The value passed to + // StartFunction is the function name alone. + // + // In languages that use name mangling, like C++, NAME is mangled. + virtual bool StartFunction(const string &name, uint64_t address) { + return true; + } + + // Finish processing the function. If ADDRESS is non-zero, it is + // the ending address for the function. If ADDRESS is zero, then + // the function's ending address is not available, and the consumer + // must infer it by other means. + virtual bool EndFunction(uint64_t address) { return true; } + + // Report that the code at ADDRESS is attributable to line NUMBER of + // the source file named FILENAME. The caller must infer the ending + // address of the line. + virtual bool Line(uint64_t address, const char *filename, int number) { + return true; + } + + // Report that an exported function NAME is present at ADDRESS. + // The size of the function is unknown. + virtual bool Extern(const string &name, uint64_t address) { + return true; + } + + // Report a warning. FORMAT is a printf-like format string, + // specifying how to format the subsequent arguments. + virtual void Warning(const char *format, ...) = 0; +}; + +} // namespace google_breakpad + +#endif // COMMON_STABS_READER_H__ diff --git a/breakpad/common/stabs_reader_unittest.cc b/breakpad/common/stabs_reader_unittest.cc new file mode 100644 index 0000000000..a84da1c4ca --- /dev/null +++ b/breakpad/common/stabs_reader_unittest.cc @@ -0,0 +1,611 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/stabs_reader.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" + +using ::testing::Eq; +using ::testing::InSequence; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::Test; +using ::testing::_; +using google_breakpad::StabsHandler; +using google_breakpad::StabsReader; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using std::map; + +namespace { + +// A StringAssembler is a class for generating .stabstr sections to present +// as input to the STABS parser. +class StringAssembler: public Section { + public: + StringAssembler() : in_cu_(false) { StartCU(); } + + // Add the string S to this StringAssembler, and return the string's + // offset within this compilation unit's strings. If S has been added + // already, this returns the offset of its first instance. + size_t Add(const string &s) { + map::iterator it = added_.find(s); + if (it != added_.end()) + return it->second; + size_t offset = Size() - cu_start_; + AppendCString(s); + added_[s] = offset; + return offset; + } + + // Start a fresh compilation unit string collection. + void StartCU() { + // Ignore duplicate calls to StartCU. Our test data don't always call + // StartCU at all, meaning that our constructor has to take care of it, + // meaning that tests that *do* call StartCU call it twice at the + // beginning. This is not worth smoothing out. + if (in_cu_) return; + + added_.clear(); + cu_start_ = Size(); + + // Each compilation unit's strings start with an empty string. + AppendCString(""); + added_[""] = 0; + + in_cu_ = true; + } + + // Finish off the current CU's strings. + size_t EndCU() { + assert(in_cu_); + in_cu_ = false; + return Size() - cu_start_; + } + + private: + // The offset of the start of this compilation unit's strings. + size_t cu_start_; + + // True if we're in a CU. + bool in_cu_; + + // A map from the strings that have been added to this section to + // their starting indices within their compilation unit. + map added_; +}; + +// A StabsAssembler is a class for generating .stab sections to present as +// test input for the STABS parser. +class StabsAssembler: public Section { + public: + // Create a StabsAssembler that uses StringAssembler for its strings. + StabsAssembler(StringAssembler *string_assembler) + : Section(string_assembler->endianness()), + string_assembler_(string_assembler), + value_size_(0), + entry_count_(0), + cu_header_(NULL) { } + ~StabsAssembler() { assert(!cu_header_); } + + // Accessor and setter for value_size_. + size_t value_size() const { return value_size_; } + StabsAssembler &set_value_size(size_t value_size) { + value_size_ = value_size; + return *this; + } + + // Append a STAB entry to the end of this section with the given + // characteristics. NAME is the offset of this entry's name string within + // its compilation unit's portion of the .stabstr section; this can be a + // value generated by a StringAssembler. Return a reference to this + // StabsAssembler. + StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, + Label value, Label name) { + D32(name); + D8(type); + D8(other); + D16(descriptor); + Append(endianness(), value_size_, value); + entry_count_++; + return *this; + } + + // As above, but automatically add NAME to our StringAssembler. + StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, + Label value, const string &name) { + return Stab(type, other, descriptor, value, string_assembler_->Add(name)); + } + + // Start a compilation unit named NAME, with an N_UNDF symbol to start + // it, and its own portion of the string section. Return a reference to + // this StabsAssembler. + StabsAssembler &StartCU(const string &name) { + assert(!cu_header_); + cu_header_ = new CUHeader; + string_assembler_->StartCU(); + entry_count_ = 0; + return Stab(N_UNDF, 0, + cu_header_->final_entry_count, + cu_header_->final_string_size, + string_assembler_->Add(name)); + } + + // Close off the current compilation unit. Return a reference to this + // StabsAssembler. + StabsAssembler &EndCU() { + assert(cu_header_); + cu_header_->final_entry_count = entry_count_; + cu_header_->final_string_size = string_assembler_->EndCU(); + delete cu_header_; + cu_header_ = NULL; + return *this; + } + + private: + // Data used in a compilation unit header STAB that we won't know until + // we've finished the compilation unit. + struct CUHeader { + // The final number of entries this compilation unit will hold. + Label final_entry_count; + + // The final size of this compilation unit's strings. + Label final_string_size; + }; + + // The strings for our STABS entries. + StringAssembler *string_assembler_; + + // The size of the 'value' field of stabs entries in this section. + size_t value_size_; + + // The number of entries in this compilation unit so far. + size_t entry_count_; + + // Header labels for this compilation unit, if we've started one but not + // finished it. + CUHeader *cu_header_; +}; + +class MockStabsReaderHandler: public StabsHandler { + public: + MOCK_METHOD3(StartCompilationUnit, + bool(const char *, uint64_t, const char *)); + MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); + MOCK_METHOD2(StartFunction, bool(const string &, uint64_t)); + MOCK_METHOD1(EndFunction, bool(uint64_t)); + MOCK_METHOD3(Line, bool(uint64_t, const char *, int)); + MOCK_METHOD2(Extern, bool(const string &, uint64_t)); + void Warning(const char *format, ...) { MockWarning(format); } + MOCK_METHOD1(MockWarning, void(const char *)); +}; + +struct StabsFixture { + StabsFixture() : stabs(&strings), unitized(true) { } + + // Create a StabsReader to parse the mock stabs data in stabs and + // strings, and pass the parsed information to mock_handler. Use the + // endianness and value size of stabs to parse the data. If all goes + // well, return the result of calling the reader's Process member + // function. Otherwise, return false. + bool ApplyHandlerToMockStabsData() { + string stabs_contents, stabstr_contents; + if (!stabs.GetContents(&stabs_contents) || + !strings.GetContents(&stabstr_contents)) + return false; + + // Run the parser on the test input, passing whatever we find to HANDLER. + StabsReader reader( + reinterpret_cast(stabs_contents.data()), + stabs_contents.size(), + reinterpret_cast(stabstr_contents.data()), + stabstr_contents.size(), + stabs.endianness() == kBigEndian, stabs.value_size(), unitized, + &mock_handler); + return reader.Process(); + } + + StringAssembler strings; + StabsAssembler stabs; + bool unitized; + MockStabsReaderHandler mock_handler; +}; + +class Stabs: public StabsFixture, public Test { }; + +TEST_F(Stabs, MockStabsInput) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + stabs + .Stab(N_SO, 149, 40232, 0x18a2a72bU, "builddir/") + .Stab(N_FUN, 83, 50010, 0x91a5353fU, + "not the SO with source file name we expected ") + .Stab(N_SO, 165, 24791, 0xfe69d23cU, "") + .Stab(N_SO, 184, 34178, 0xca4d883aU, "builddir1/") + .Stab(N_SO, 83, 40859, 0xd2fe5df3U, "file1.c") + .Stab(N_LSYM, 147, 39565, 0x60d4bb8aU, "not the FUN we're looking for") + .Stab(N_FUN, 120, 50271, 0xa049f4b1U, "fun1") + .Stab(N_BINCL, 150, 15694, 0xef65c659U, + "something to ignore in a FUN body") + .Stab(N_SLINE, 147, 4967, 0xd904b3f, "") + .Stab(N_SOL, 177, 56135, 0xbd97b1dcU, "header.h") + .Stab(N_SLINE, 130, 24610, 0x90f145b, "") + .Stab(N_FUN, 45, 32441, 0xbf27cf93U, + "fun2:some stabs type info here:to trim from the name") + .Stab(N_SLINE, 138, 39002, 0x8148b87, "") + .Stab(N_SOL, 60, 49318, 0x1d06e025U, "file1.c") + .Stab(N_SLINE, 29, 52163, 0x6eebbb7, "") + .Stab(N_SO, 167, 4647, 0xd04b7448U, "") + .Stab(N_LSYM, 58, 37837, 0xe6b14d37U, "") + .Stab(N_SO, 152, 7810, 0x11759f10U, "file3.c") + .Stab(N_SO, 218, 12447, 0x11cfe4b5U, ""); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U, + StrEq("builddir1/"))) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), + 0x11759f10U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, AbruptCU) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(4); + stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c"); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, AbruptFunction) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(8); + stabs + .Stab(N_SO, 218, 26631, 0xb83ddf10U, "file3-1.c") + .Stab(N_FUN, 113, 24765, 0xbbd4a145U, "fun3_1"); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, NoCU) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(8); + stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/"); + + EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _)) + .Times(0); + EXPECT_CALL(mock_handler, StartFunction(_, _)) + .Times(0); + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, NoCUEnd) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(8); + stabs + .Stab(N_SO, 116, 58280, 0x2f7493c9U, "file5-1.c") + .Stab(N_SO, 224, 23057, 0xf9f1d50fU, "file5-2.c"); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +// On systems that store STABS in sections, string offsets are relative to +// the beginning of that compilation unit's strings, marked with N_UNDF +// symbols; see the comments for StabsReader::StabsReader. +TEST_F(Stabs, Unitized) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(4); + stabs + .StartCU("antimony") + .Stab(N_SO, 49, 26043, 0x7e259f1aU, "antimony") + .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic") + .Stab(N_SO, 124, 37175, 0x80b0014cU, "") + .EndCU() + .StartCU("aluminum") + .Stab(N_SO, 72, 23084, 0x86756839U, "aluminum") + .Stab(N_FUN, 59, 3305, 0xa8e120b0U, "selenium") + .Stab(N_SO, 178, 56949, 0xbffff983U, "") + .EndCU(); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xbffff983U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +// On systems that store STABS entries in the real symbol table, the N_UNDF +// entries have no special meaning, and shouldn't mess up the string +// indices. +TEST_F(Stabs, NonUnitized) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + unitized = false; + stabs + .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") + .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") + .Stab(N_SO, 71, 45139, 0x11a97352, "Tanzania") + .Stab(N_SO, 221, 41976, 0x21a97352, ""); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("Tanzania"), + 0x11a97352, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, FunctionEnd) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(8); + stabs + .Stab(N_SO, 102, 62362, 0x52a830d644cd6942ULL, "compilation unit") + // This function is terminated by the start of the next function. + .Stab(N_FUN, 216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1") + // This function is terminated by an explicit end-of-function stab, + // whose value is a size in bytes. + .Stab(N_FUN, 240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2") + .Stab(N_FUN, 14, 36749, 0xc1ab, "") + // This function is terminated by the end of the compilation unit. + .Stab(N_FUN, 143, 64514, 0xdff98c9a35386e1fULL, "function 3") + .Stab(N_SO, 164, 60142, 0xfdacb856e78bbf57ULL, ""); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("compilation unit"), + 0x52a830d644cd6942ULL, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +// On Mac OS X, SLINE records can appear before the FUN stab to which they +// belong, and their values are absolute addresses, not offsets. +TEST_F(Stabs, LeadingLine) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(4); + stabs + .Stab(N_SO, 179, 27357, 0x8adabc15, "build directory/") + .Stab(N_SO, 52, 53058, 0x4c7e3bf4, "compilation unit") + .Stab(N_SOL, 165, 12086, 0x6a797ca3, "source file name") + .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "") + .Stab(N_SLINE, 89, 43802, 0x4cba8b88, "") + .Stab(N_FUN, 251, 51639, 0xce1b98fa, "rutabaga") + .Stab(N_FUN, 218, 16113, 0x5798, "") + .Stab(N_SO, 52, 53058, 0xd4af4415, ""); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("compilation unit"), + 0x4c7e3bf4, StrEq("build directory/"))) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("rutabaga"), 0xce1b98fa)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0x4cb3d7e0, StrEq("source file name"), 20015)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0x4cba8b88, StrEq("source file name"), 43802)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + + +#if defined(HAVE_MACH_O_NLIST_H) +// These tests have no meaning on non-Mach-O-based systems, as +// only Mach-O uses N_SECT to represent public symbols. +TEST_F(Stabs, OnePublicSymbol) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + + const uint32_t kExpectedAddress = 0x9000; + const string kExpectedFunctionName("public_function"); + stabs + .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName); + + { + InSequence s; + EXPECT_CALL(mock_handler, + Extern(StrEq(kExpectedFunctionName), + kExpectedAddress)) + .WillOnce(Return(true)); + } + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, TwoPublicSymbols) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + + const uint32_t kExpectedAddress1 = 0xB0B0B0B0; + const string kExpectedFunctionName1("public_function"); + const uint32_t kExpectedAddress2 = 0xF0F0F0F0; + const string kExpectedFunctionName2("something else"); + stabs + .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1) + .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2); + + { + InSequence s; + EXPECT_CALL(mock_handler, + Extern(StrEq(kExpectedFunctionName1), + kExpectedAddress1)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Extern(StrEq(kExpectedFunctionName2), + kExpectedAddress2)) + .WillOnce(Return(true)); + } + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +#endif + +} // anonymous namespace diff --git a/breakpad/common/stabs_to_module.cc b/breakpad/common/stabs_to_module.cc new file mode 100644 index 0000000000..e59aebdba7 --- /dev/null +++ b/breakpad/common/stabs_to_module.cc @@ -0,0 +1,200 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dump_stabs.cc --- implement the StabsToModule class. + +#include +#include +#include +#include + +#include + +#include "common/stabs_to_module.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +// Demangle using abi call. +// Older GCC may not support it. +static string Demangle(const string &mangled) { + int status = 0; + char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); + if (status == 0 && demangled != NULL) { + string str(demangled); + free(demangled); + return str; + } + return string(mangled); +} + +StabsToModule::~StabsToModule() { + // Free any functions we've accumulated but not added to the module. + for (vector::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); func_it++) + delete *func_it; + // Free any function that we're currently within. + delete current_function_; +} + +bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address, + const char *build_directory) { + assert(!in_compilation_unit_); + in_compilation_unit_ = true; + current_source_file_name_ = name; + current_source_file_ = module_->FindFile(name); + comp_unit_base_address_ = address; + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::EndCompilationUnit(uint64_t address) { + assert(in_compilation_unit_); + in_compilation_unit_ = false; + comp_unit_base_address_ = 0; + current_source_file_ = NULL; + current_source_file_name_ = NULL; + if (address) + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::StartFunction(const string &name, + uint64_t address) { + assert(!current_function_); + Module::Function *f = new Module::Function; + f->name = Demangle(name); + f->address = address; + f->size = 0; // We compute this in StabsToModule::Finalize(). + f->parameter_size = 0; // We don't provide this information. + current_function_ = f; + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::EndFunction(uint64_t address) { + assert(current_function_); + // Functions in this compilation unit should have address bigger + // than the compilation unit's starting address. There may be a lot + // of duplicated entries for functions in the STABS data. We will + // count on the Module to remove the duplicates. + if (current_function_->address >= comp_unit_base_address_) + functions_.push_back(current_function_); + else + delete current_function_; + current_function_ = NULL; + if (address) + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::Line(uint64_t address, const char *name, int number) { + assert(current_function_); + assert(current_source_file_); + if (name != current_source_file_name_) { + current_source_file_ = module_->FindFile(name); + current_source_file_name_ = name; + } + Module::Line line; + line.address = address; + line.size = 0; // We compute this in StabsToModule::Finalize(). + line.file = current_source_file_; + line.number = number; + current_function_->lines.push_back(line); + return true; +} + +bool StabsToModule::Extern(const string &name, uint64_t address) { + Module::Extern *ext = new Module::Extern; + // Older libstdc++ demangle implementations can crash on unexpected + // input, so be careful about what gets passed in. + if (name.compare(0, 3, "__Z") == 0) { + ext->name = Demangle(name.substr(1)); + } else if (name[0] == '_') { + ext->name = name.substr(1); + } else { + ext->name = name; + } + ext->address = address; + module_->AddExtern(ext); + return true; +} + +void StabsToModule::Warning(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + +void StabsToModule::Finalize() { + // Sort our boundary list, so we can search it quickly. + sort(boundaries_.begin(), boundaries_.end()); + // Sort all functions by address, just for neatness. + sort(functions_.begin(), functions_.end(), + Module::Function::CompareByAddress); + + for (vector::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); + func_it++) { + Module::Function *f = *func_it; + // Compute the function f's size. + vector::const_iterator boundary + = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); + if (boundary != boundaries_.end()) + f->size = *boundary - f->address; + else + // If this is the last function in the module, and the STABS + // reader was unable to give us its ending address, then assign + // it a bogus, very large value. This will happen at most once + // per module: since we've added all functions' addresses to the + // boundary table, only one can be the last. + f->size = kFallbackSize; + + // Compute sizes for each of the function f's lines --- if it has any. + if (!f->lines.empty()) { + stable_sort(f->lines.begin(), f->lines.end(), + Module::Line::CompareByAddress); + vector::iterator last_line = f->lines.end() - 1; + for (vector::iterator line_it = f->lines.begin(); + line_it != last_line; line_it++) + line_it[0].size = line_it[1].address - line_it[0].address; + // Compute the size of the last line from f's end address. + last_line->size = (f->address + f->size) - last_line->address; + } + } + // Now that everything has a size, add our functions to the module, and + // dispose of our private list. + module_->AddFunctions(functions_.begin(), functions_.end()); + functions_.clear(); +} + +} // namespace google_breakpad diff --git a/breakpad/common/stabs_to_module.h b/breakpad/common/stabs_to_module.h new file mode 100644 index 0000000000..5e04fa7927 --- /dev/null +++ b/breakpad/common/stabs_to_module.h @@ -0,0 +1,143 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dump_stabs.h: Define the StabsToModule class, which receives +// STABS debugging information from a parser and adds it to a Breakpad +// symbol file. + +#ifndef BREAKPAD_COMMON_STABS_TO_MODULE_H_ +#define BREAKPAD_COMMON_STABS_TO_MODULE_H_ + +#include + +#include +#include + +#include "common/module.h" +#include "common/stabs_reader.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::vector; + +// A StabsToModule is a handler that receives parsed STABS debugging +// information from a StabsReader, and uses that to populate +// a Module. (All classes are in the google_breakpad namespace.) A +// Module represents the contents of a Breakpad symbol file, and knows +// how to write itself out as such. A StabsToModule thus acts as +// the bridge between STABS and Breakpad data. +// When processing Darwin Mach-O files, this also receives public linker +// symbols, like those found in system libraries. +class StabsToModule: public google_breakpad::StabsHandler { + public: + // Receive parsed debugging information from a StabsReader, and + // store it all in MODULE. + StabsToModule(Module *module) : + module_(module), + in_compilation_unit_(false), + comp_unit_base_address_(0), + current_function_(NULL), + current_source_file_(NULL), + current_source_file_name_(NULL) { } + ~StabsToModule(); + + // The standard StabsHandler virtual member functions. + bool StartCompilationUnit(const char *name, uint64_t address, + const char *build_directory); + bool EndCompilationUnit(uint64_t address); + bool StartFunction(const string &name, uint64_t address); + bool EndFunction(uint64_t address); + bool Line(uint64_t address, const char *name, int number); + bool Extern(const string &name, uint64_t address); + void Warning(const char *format, ...); + + // Do any final processing necessary to make module_ contain all the + // data provided by the STABS reader. + // + // Because STABS does not provide reliable size information for + // functions and lines, we need to make a pass over the data after + // processing all the STABS to compute those sizes. We take care of + // that here. + void Finalize(); + + private: + + // An arbitrary, but very large, size to use for functions whose + // size we can't compute properly. + static const uint64_t kFallbackSize = 0x10000000; + + // The module we're contributing debugging info to. + Module *module_; + + // The functions we've generated so far. We don't add these to + // module_ as we parse them. Instead, we wait until we've computed + // their ending address, and their lines' ending addresses. + // + // We could just stick them in module_ from the outset, but if + // module_ already contains data gathered from other debugging + // formats, that would complicate the size computation. + vector functions_; + + // Boundary addresses. STABS doesn't necessarily supply sizes for + // functions and lines, so we need to compute them ourselves by + // finding the next object. + vector boundaries_; + + // True if we are currently within a compilation unit: we have gotten a + // StartCompilationUnit call, but no matching EndCompilationUnit call + // yet. We use this for sanity checks. + bool in_compilation_unit_; + + // The base address of the current compilation unit. We use this to + // recognize functions we should omit from the symbol file. (If you + // know the details of why we omit these, please patch this + // comment.) + Module::Address comp_unit_base_address_; + + // The function we're currently contributing lines to. + Module::Function *current_function_; + + // The last Module::File we got a line number in. + Module::File *current_source_file_; + + // The pointer in the .stabstr section of the name that + // current_source_file_ is built from. This allows us to quickly + // recognize when the current line is in the same file as the + // previous one (which it usually is). + const char *current_source_file_name_; +}; + +} // namespace google_breakpad + +#endif // BREAKPAD_COMMON_STABS_TO_MODULE_H_ diff --git a/breakpad/common/stabs_to_module_unittest.cc b/breakpad/common/stabs_to_module_unittest.cc new file mode 100644 index 0000000000..d445d1d64b --- /dev/null +++ b/breakpad/common/stabs_to_module_unittest.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// dump_stabs_unittest.cc: Unit tests for StabsToModule. + +#include + +#include "breakpad_googletest_includes.h" +#include "common/stabs_to_module.h" + +using google_breakpad::Module; +using google_breakpad::StabsToModule; +using std::vector; + +TEST(StabsToModule, SimpleCU) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Feed in a simple compilation unit that defines a function with + // one line. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0x9f4d1271e50db93bLL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("function", 0xfde4abbed390c394LL)); + EXPECT_TRUE(h.Line(0xfde4abbed390c394LL, "source-file-name", 174823314)); + EXPECT_TRUE(h.EndFunction(0xfde4abbed390c3a4LL)); + EXPECT_TRUE(h.EndCompilationUnit(0xfee4abbed390c3a4LL)); + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file = m.FindExistingFile("source-file-name"); + ASSERT_TRUE(file != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ((size_t) 1, functions.size()); + Module::Function *function = functions[0]; + EXPECT_STREQ("function", function->name.c_str()); + EXPECT_EQ(0xfde4abbed390c394LL, function->address); + EXPECT_EQ(0x10U, function->size); + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ((size_t) 1, function->lines.size()); + Module::Line *line = &function->lines[0]; + EXPECT_EQ(0xfde4abbed390c394LL, line->address); + EXPECT_EQ(0x10U, line->size); // derived from EndFunction + EXPECT_TRUE(line->file == file); + EXPECT_EQ(174823314, line->number); +} + +#ifdef __GNUC__ +// Function name mangling can vary by compiler, so only run mangled-name +// tests on GCC for simplicity's sake. +TEST(StabsToModule, Externs) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Feed in a few Extern symbols. + EXPECT_TRUE(h.Extern("_foo", 0xffff)); + EXPECT_TRUE(h.Extern("__Z21dyldGlobalLockAcquirev", 0xaaaa)); + EXPECT_TRUE(h.Extern("_MorphTableGetNextMorphChain", 0x1111)); + h.Finalize(); + + // Now check to see what has been added to the Module. + vector externs; + m.GetExterns(&externs, externs.end()); + ASSERT_EQ((size_t) 3, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_STREQ("MorphTableGetNextMorphChain", extern1->name.c_str()); + EXPECT_EQ((Module::Address)0x1111, extern1->address); + Module::Extern *extern2 = externs[1]; + EXPECT_STREQ("dyldGlobalLockAcquire()", extern2->name.c_str()); + EXPECT_EQ((Module::Address)0xaaaa, extern2->address); + Module::Extern *extern3 = externs[2]; + EXPECT_STREQ("foo", extern3->name.c_str()); + EXPECT_EQ((Module::Address)0xffff, extern3->address); +} +#endif // __GNUC__ + +TEST(StabsToModule, DuplicateFunctionNames) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Compilation unit with one function, mangled name. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda36ecf7f46cLL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("funcfoo", + 0xf2cfda36ecf7f46dLL)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.StartFunction("funcfoo", + 0xf2cfda36ecf7f46dLL)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.EndCompilationUnit(0)); + + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file = m.FindExistingFile("compilation-unit"); + ASSERT_TRUE(file != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ(1U, functions.size()); + + Module::Function *function = functions[0]; + EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address); + EXPECT_LT(0U, function->size); // should have used dummy size + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ(0U, function->lines.size()); +} + +TEST(InferSizes, LineSize) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Feed in a simple compilation unit that defines a function with + // one line. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xb4513962eff94e92LL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("function", 0xb4513962eff94e92LL)); + EXPECT_TRUE(h.Line(0xb4513962eff94e92LL, "source-file-name-1", 77396614)); + EXPECT_TRUE(h.Line(0xb4513963eff94e92LL, "source-file-name-2", 87660088)); + EXPECT_TRUE(h.EndFunction(0)); // unknown function end address + EXPECT_TRUE(h.EndCompilationUnit(0)); // unknown CU end address + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit-2", 0xb4523963eff94e92LL, + "build-directory-2")); // next boundary + EXPECT_TRUE(h.EndCompilationUnit(0)); + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file1 = m.FindExistingFile("source-file-name-1"); + ASSERT_TRUE(file1 != NULL); + Module::File *file2 = m.FindExistingFile("source-file-name-2"); + ASSERT_TRUE(file2 != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ((size_t) 1, functions.size()); + + Module::Function *function = functions[0]; + EXPECT_STREQ("function", function->name.c_str()); + EXPECT_EQ(0xb4513962eff94e92LL, function->address); + EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ((size_t) 2, function->lines.size()); + + Module::Line *line1 = &function->lines[0]; + EXPECT_EQ(0xb4513962eff94e92LL, line1->address); + EXPECT_EQ(0x100000000ULL, line1->size); // derived from EndFunction + EXPECT_TRUE(line1->file == file1); + EXPECT_EQ(77396614, line1->number); + + Module::Line *line2 = &function->lines[1]; + EXPECT_EQ(0xb4513963eff94e92LL, line2->address); + EXPECT_EQ(0x1000000000000ULL, line2->size); // derived from EndFunction + EXPECT_TRUE(line2->file == file2); + EXPECT_EQ(87660088, line2->number); +} + +#ifdef __GNUC__ +// Function name mangling can vary by compiler, so only run mangled-name +// tests on GCC for simplicity's sake. +TEST(FunctionNames, Mangled) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Compilation unit with one function, mangled name. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda63cef7f46cLL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("_ZNSt6vectorIySaIyEE9push_backERKy", + 0xf2cfda63cef7f46dLL)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.EndCompilationUnit(0)); + + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file = m.FindExistingFile("compilation-unit"); + ASSERT_TRUE(file != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ(1U, functions.size()); + + Module::Function *function = functions[0]; + // This is GCC-specific, but we shouldn't be seeing STABS data anywhere + // but Linux. + EXPECT_STREQ("std::vector >::" + "push_back(unsigned long long const&)", + function->name.c_str()); + EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address); + EXPECT_LT(0U, function->size); // should have used dummy size + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ(0U, function->lines.size()); +} +#endif // __GNUC__ + +// The GNU toolchain can omit functions that are not used; however, +// when it does so, it doesn't clean up the debugging information that +// refers to them. In STABS, this results in compilation units whose +// SO addresses are zero. +TEST(Omitted, Function) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // The StartCompilationUnit and EndCompilationUnit calls may both have an + // address of zero if the compilation unit has had sections removed. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0, "build-directory")); + EXPECT_TRUE(h.StartFunction("function", 0x2a133596)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.EndCompilationUnit(0)); +} + +// TODO --- if we actually cared about STABS. Even without these we've +// got full coverage of non-failure source lines in dump_stabs.cc. + +// Line size from next line +// Line size from function end +// Line size from next function start +// line size from cu end +// line size from next cu start +// fallback size is something plausible + +// function size from function end +// function size from next function start +// function size from cu end +// function size from next cu start +// fallback size is something plausible + +// omitting functions outside the compilation unit's address range +// zero-line, one-line, many-line functions diff --git a/breakpad/common/string_conversion.cc b/breakpad/common/string_conversion.cc new file mode 100644 index 0000000000..9b06e86b4d --- /dev/null +++ b/breakpad/common/string_conversion.cc @@ -0,0 +1,155 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "common/convert_UTF.h" +#include "common/scoped_ptr.h" +#include "common/string_conversion.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::vector; + +void UTF8ToUTF16(const char *in, vector *out) { + size_t source_length = strlen(in); + const UTF8 *source_ptr = reinterpret_cast(in); + const UTF8 *source_end_ptr = source_ptr + source_length; + // Erase the contents and zero fill to the expected size + out->clear(); + out->insert(out->begin(), source_length, 0); + uint16_t *target_ptr = &(*out)[0]; + uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t); + ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + // Resize to be the size of the # of converted characters + NULL + out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); +} + +int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) { + const UTF8 *source_ptr = reinterpret_cast(in); + const UTF8 *source_end_ptr = source_ptr + sizeof(char); + uint16_t *target_ptr = out; + uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t); + out[0] = out[1] = 0; + + // Process one character at a time + while (1) { + ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result == conversionOK) + return static_cast(source_ptr - reinterpret_cast(in)); + + // Add another character to the input stream and try again + source_ptr = reinterpret_cast(in); + ++source_end_ptr; + + if (source_end_ptr > reinterpret_cast(in) + in_length) + break; + } + + return 0; +} + +void UTF32ToUTF16(const wchar_t *in, vector *out) { + size_t source_length = wcslen(in); + const UTF32 *source_ptr = reinterpret_cast(in); + const UTF32 *source_end_ptr = source_ptr + source_length; + // Erase the contents and zero fill to the expected size + out->clear(); + out->insert(out->begin(), source_length, 0); + uint16_t *target_ptr = &(*out)[0]; + uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t); + ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + // Resize to be the size of the # of converted characters + NULL + out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); +} + +void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) { + const UTF32 *source_ptr = reinterpret_cast(&in); + const UTF32 *source_end_ptr = source_ptr + 1; + uint16_t *target_ptr = out; + uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t); + out[0] = out[1] = 0; + ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result != conversionOK) { + out[0] = out[1] = 0; + } +} + +static inline uint16_t Swap(uint16_t value) { + return (value >> 8) | static_cast(value << 8); +} + +string UTF16ToUTF8(const vector &in, bool swap) { + const UTF16 *source_ptr = &in[0]; + scoped_ptr source_buffer; + + // If we're to swap, we need to make a local copy and swap each byte pair + if (swap) { + int idx = 0; + source_buffer.reset(new uint16_t[in.size()]); + UTF16 *source_buffer_ptr = source_buffer.get(); + for (vector::const_iterator it = in.begin(); + it != in.end(); ++it, ++idx) + source_buffer_ptr[idx] = Swap(*it); + + source_ptr = source_buffer.get(); + } + + // The maximum expansion would be 4x the size of the input string. + const UTF16 *source_end_ptr = source_ptr + in.size(); + size_t target_capacity = in.size() * 4; + scoped_array target_buffer(new UTF8[target_capacity]); + UTF8 *target_ptr = target_buffer.get(); + UTF8 *target_end_ptr = target_ptr + target_capacity; + ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result == conversionOK) { + const char *targetPtr = reinterpret_cast(target_buffer.get()); + return targetPtr; + } + + return ""; +} + +} // namespace google_breakpad diff --git a/breakpad/common/string_conversion.h b/breakpad/common/string_conversion.h new file mode 100644 index 0000000000..b9ba96a2e1 --- /dev/null +++ b/breakpad/common/string_conversion.h @@ -0,0 +1,68 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// string_conversion.h: Conversion between different UTF-8/16/32 encodings. + +#ifndef COMMON_STRING_CONVERSION_H__ +#define COMMON_STRING_CONVERSION_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::vector; + +// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the +// conversion failed, |out| will be zero length. +void UTF8ToUTF16(const char *in, vector *out); + +// Convert at least one character (up to a maximum of |in_length|) from |in| +// to UTF-16 into |out|. Return the number of characters consumed from |in|. +// Any unused characters in |out| will be initialized to 0. No memory will +// be allocated by this routine. +int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]); + +// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the +// conversion failed, |out| will be zero length. +void UTF32ToUTF16(const wchar_t *in, vector *out); + +// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be +// initialized to 0. No memory will be allocated by this routine. +void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]); + +// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting. +string UTF16ToUTF8(const vector &in, bool swap); + +} // namespace google_breakpad + +#endif // COMMON_STRING_CONVERSION_H__ diff --git a/breakpad/common/symbol_data.h b/breakpad/common/symbol_data.h new file mode 100644 index 0000000000..2cf15a855d --- /dev/null +++ b/breakpad/common/symbol_data.h @@ -0,0 +1,42 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2013 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_SYMBOL_DATA_H_ +#define COMMON_SYMBOL_DATA_H_ + +// Control what data is used from the symbol file. +enum SymbolData { + ALL_SYMBOL_DATA, + NO_CFI, + ONLY_CFI +}; + +#endif // COMMON_SYMBOL_DATA_H_ diff --git a/breakpad/common/test_assembler.cc b/breakpad/common/test_assembler.cc new file mode 100644 index 0000000000..1e783b45c5 --- /dev/null +++ b/breakpad/common/test_assembler.cc @@ -0,0 +1,359 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// test_assembler.cc: Implementation of google_breakpad::TestAssembler. +// See test_assembler.h for details. + +#include "common/test_assembler.h" + +#include +#include + +#include + +namespace google_breakpad { +namespace test_assembler { + +using std::back_insert_iterator; + +Label::Label() : value_(new Binding()) { } +Label::Label(uint64_t value) : value_(new Binding(value)) { } +Label::Label(const Label &label) { + value_ = label.value_; + value_->Acquire(); +} +Label::~Label() { + if (value_->Release()) delete value_; +} + +Label &Label::operator=(uint64_t value) { + value_->Set(NULL, value); + return *this; +} + +Label &Label::operator=(const Label &label) { + value_->Set(label.value_, 0); + return *this; +} + +Label Label::operator+(uint64_t addend) const { + Label l; + l.value_->Set(this->value_, addend); + return l; +} + +Label Label::operator-(uint64_t subtrahend) const { + Label l; + l.value_->Set(this->value_, -subtrahend); + return l; +} + +// When NDEBUG is #defined, assert doesn't evaluate its argument. This +// means you can't simply use assert to check the return value of a +// function with necessary side effects. +// +// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether +// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts +// that x is true. +#ifdef NDEBUG +#define ALWAYS_EVALUATE_AND_ASSERT(x) x +#else +#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) +#endif + +uint64_t Label::operator-(const Label &label) const { + uint64_t offset; + ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); + return offset; +} + +uint64_t Label::Value() const { + uint64_t v = 0; + ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v)); + return v; +}; + +bool Label::IsKnownConstant(uint64_t *value_p) const { + Binding *base; + uint64_t addend; + value_->Get(&base, &addend); + if (base != NULL) return false; + if (value_p) *value_p = addend; + return true; +} + +bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const +{ + Binding *label_base, *this_base; + uint64_t label_addend, this_addend; + label.value_->Get(&label_base, &label_addend); + value_->Get(&this_base, &this_addend); + // If this and label are related, Get will find their final + // common ancestor, regardless of how indirect the relation is. This + // comparison also handles the constant vs. constant case. + if (this_base != label_base) return false; + if (offset_p) *offset_p = this_addend - label_addend; + return true; +} + +Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } + +Label::Binding::Binding(uint64_t addend) + : base_(NULL), addend_(addend), reference_count_(1) { } + +Label::Binding::~Binding() { + assert(reference_count_ == 0); + if (base_ && base_ != this && base_->Release()) + delete base_; +} + +void Label::Binding::Set(Binding *binding, uint64_t addend) { + if (!base_ && !binding) { + // We're equating two constants. This could be okay. + assert(addend_ == addend); + } else if (!base_) { + // We are a known constant, but BINDING may not be, so turn the + // tables and try to set BINDING's value instead. + binding->Set(NULL, addend_ - addend); + } else { + if (binding) { + // Find binding's final value. Since the final value is always either + // completely unconstrained or a constant, never a reference to + // another variable (otherwise, it wouldn't be final), this + // guarantees we won't create cycles here, even for code like this: + // l = m, m = n, n = l; + uint64_t binding_addend; + binding->Get(&binding, &binding_addend); + addend += binding_addend; + } + + // It seems likely that setting a binding to itself is a bug + // (although I can imagine this might turn out to be helpful to + // permit). + assert(binding != this); + + if (base_ != this) { + // Set the other bindings on our chain as well. Note that this + // is sufficient even though binding relationships form trees: + // All binding operations traverse their chains to the end, and + // all bindings related to us share some tail of our chain, so + // they will see the changes we make here. + base_->Set(binding, addend - addend_); + // We're not going to use base_ any more. + if (base_->Release()) delete base_; + } + + // Adopt BINDING as our base. Note that it should be correct to + // acquire here, after the release above, even though the usual + // reference-counting rules call for acquiring first, and then + // releasing: the self-reference assertion above should have + // complained if BINDING were 'this' or anywhere along our chain, + // so we didn't release BINDING. + if (binding) binding->Acquire(); + base_ = binding; + addend_ = addend; + } +} + +void Label::Binding::Get(Binding **base, uint64_t *addend) { + if (base_ && base_ != this) { + // Recurse to find the end of our reference chain (the root of our + // tree), and then rewrite every binding along the chain to refer + // to it directly, adjusting addends appropriately. (This is why + // this member function isn't this-const.) + Binding *final_base; + uint64_t final_addend; + base_->Get(&final_base, &final_addend); + if (final_base) final_base->Acquire(); + if (base_->Release()) delete base_; + base_ = final_base; + addend_ += final_addend; + } + *base = base_; + *addend = addend_; +} + +template +static inline void InsertEndian(test_assembler::Endianness endianness, + size_t size, uint64_t number, Inserter dest) { + assert(size > 0); + if (endianness == kLittleEndian) { + for (size_t i = 0; i < size; i++) { + *dest++ = (char) (number & 0xff); + number >>= 8; + } + } else { + assert(endianness == kBigEndian); + // The loop condition is odd, but it's correct for size_t. + for (size_t i = size - 1; i < size; i--) + *dest++ = (char) ((number >> (i * 8)) & 0xff); + } +} + +Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { + InsertEndian(endianness, size, number, + back_insert_iterator(contents_)); + return *this; +} + +Section &Section::Append(Endianness endianness, size_t size, + const Label &label) { + // If this label's value is known, there's no reason to waste an + // entry in references_ on it. + uint64_t value; + if (label.IsKnownConstant(&value)) + return Append(endianness, size, value); + + // This will get caught when the references are resolved, but it's + // nicer to find out earlier. + assert(endianness != kUnsetEndian); + + references_.push_back(Reference(contents_.size(), endianness, size, label)); + contents_.append(size, 0); + return *this; +} + +#define ENDIANNESS_L kLittleEndian +#define ENDIANNESS_B kBigEndian +#define ENDIANNESS(e) ENDIANNESS_ ## e + +#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ + Section &Section::e ## bits(uint ## bits ## _t v) { \ + InsertEndian(ENDIANNESS(e), bits / 8, v, \ + back_insert_iterator(contents_)); \ + return *this; \ + } + +#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ + Section &Section::e ## bits(const Label &v) { \ + return Append(ENDIANNESS(e), bits / 8, v); \ + } + +// Define L16, B32, and friends. +#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ + DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ + DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) + +DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); +DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); +DEFINE_SHORT_APPEND_ENDIAN(L, 16); +DEFINE_SHORT_APPEND_ENDIAN(L, 32); +DEFINE_SHORT_APPEND_ENDIAN(L, 64); +DEFINE_SHORT_APPEND_ENDIAN(B, 16); +DEFINE_SHORT_APPEND_ENDIAN(B, 32); +DEFINE_SHORT_APPEND_ENDIAN(B, 64); + +#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ + Section &Section::D ## bits(uint ## bits ## _t v) { \ + InsertEndian(endianness_, bits / 8, v, \ + back_insert_iterator(contents_)); \ + return *this; \ + } +#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ + Section &Section::D ## bits(const Label &v) { \ + return Append(endianness_, bits / 8, v); \ + } +#define DEFINE_SHORT_APPEND_DEFAULT(bits) \ + DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ + DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) + +DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) +DEFINE_SHORT_APPEND_DEFAULT(16); +DEFINE_SHORT_APPEND_DEFAULT(32); +DEFINE_SHORT_APPEND_DEFAULT(64); + +Section &Section::Append(const Section §ion) { + size_t base = contents_.size(); + contents_.append(section.contents_); + for (vector::const_iterator it = section.references_.begin(); + it != section.references_.end(); it++) + references_.push_back(Reference(base + it->offset, it->endianness, + it->size, it->label)); + return *this; +} + +Section &Section::LEB128(long long value) { + while (value < -0x40 || 0x3f < value) { + contents_ += (value & 0x7f) | 0x80; + if (value < 0) + value = (value >> 7) | ~(((unsigned long long) -1) >> 7); + else + value = (value >> 7); + } + contents_ += value & 0x7f; + return *this; +} + +Section &Section::ULEB128(uint64_t value) { + while (value > 0x7f) { + contents_ += (value & 0x7f) | 0x80; + value = (value >> 7); + } + contents_ += value; + return *this; +} + +Section &Section::Align(size_t alignment, uint8_t pad_byte) { + // ALIGNMENT must be a power of two. + assert(((alignment - 1) & alignment) == 0); + size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); + contents_.append(new_size - contents_.size(), pad_byte); + assert((contents_.size() & (alignment - 1)) == 0); + return *this; +} + +void Section::Clear() { + contents_.clear(); + references_.clear(); +} + +bool Section::GetContents(string *contents) { + // For each label reference, find the label's value, and patch it into + // the section's contents. + for (size_t i = 0; i < references_.size(); i++) { + Reference &r = references_[i]; + uint64_t value; + if (!r.label.IsKnownConstant(&value)) { + fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); + return false; + } + assert(r.offset < contents_.size()); + assert(contents_.size() - r.offset >= r.size); + InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); + } + contents->clear(); + std::swap(contents_, *contents); + references_.clear(); + return true; +} + +} // namespace test_assembler +} // namespace google_breakpad diff --git a/breakpad/common/test_assembler.h b/breakpad/common/test_assembler.h new file mode 100644 index 0000000000..373dbebacd --- /dev/null +++ b/breakpad/common/test_assembler.h @@ -0,0 +1,484 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// test-assembler.h: interface to class for building complex binary streams. + +// To test the Breakpad symbol dumper and processor thoroughly, for +// all combinations of host system and minidump processor +// architecture, we need to be able to easily generate complex test +// data like debugging information and minidump files. +// +// For example, if we want our unit tests to provide full code +// coverage for stack walking, it may be difficult to persuade the +// compiler to generate every possible sort of stack walking +// information that we want to support; there are probably DWARF CFI +// opcodes that GCC never emits. Similarly, if we want to test our +// error handling, we will need to generate damaged minidumps or +// debugging information that (we hope) the client or compiler will +// never produce on its own. +// +// google_breakpad::TestAssembler provides a predictable and +// (relatively) simple way to generate complex formatted data streams +// like minidumps and CFI. Furthermore, because TestAssembler is +// portable, developers without access to (say) Visual Studio or a +// SPARC assembler can still work on test data for those targets. + +#ifndef PROCESSOR_TEST_ASSEMBLER_H_ +#define PROCESSOR_TEST_ASSEMBLER_H_ + +#include +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::list; +using std::vector; + +namespace test_assembler { + +// A Label represents a value not yet known that we need to store in a +// section. As long as all the labels a section refers to are defined +// by the time we retrieve its contents as bytes, we can use undefined +// labels freely in that section's construction. +// +// A label can be in one of three states: +// - undefined, +// - defined as the sum of some other label and a constant, or +// - a constant. +// +// A label's value never changes, but it can accumulate constraints. +// Adding labels and integers is permitted, and yields a label. +// Subtracting a constant from a label is permitted, and also yields a +// label. Subtracting two labels that have some relationship to each +// other is permitted, and yields a constant. +// +// For example: +// +// Label a; // a's value is undefined +// Label b; // b's value is undefined +// { +// Label c = a + 4; // okay, even though a's value is unknown +// b = c + 4; // also okay; b is now a+8 +// } +// Label d = b - 2; // okay; d == a+6, even though c is gone +// d.Value(); // error: d's value is not yet known +// d - a; // is 6, even though their values are not known +// a = 12; // now b == 20, and d == 18 +// d.Value(); // 18: no longer an error +// b.Value(); // 20 +// d = 10; // error: d is already defined. +// +// Label objects' lifetimes are unconstrained: notice that, in the +// above example, even though a and b are only related through c, and +// c goes out of scope, the assignment to a sets b's value as well. In +// particular, it's not necessary to ensure that a Label lives beyond +// Sections that refer to it. +class Label { + public: + Label(); // An undefined label. + Label(uint64_t value); // A label with a fixed value + Label(const Label &value); // A label equal to another. + ~Label(); + + // Return this label's value; it must be known. + // + // Providing this as a cast operator is nifty, but the conversions + // happen in unexpected places. In particular, ISO C++ says that + // Label + size_t becomes ambigious, because it can't decide whether + // to convert the Label to a uint64_t and then to a size_t, or use + // the overloaded operator that returns a new label, even though the + // former could fail if the label is not yet defined and the latter won't. + uint64_t Value() const; + + Label &operator=(uint64_t value); + Label &operator=(const Label &value); + Label operator+(uint64_t addend) const; + Label operator-(uint64_t subtrahend) const; + uint64_t operator-(const Label &subtrahend) const; + + // We could also provide == and != that work on undefined, but + // related, labels. + + // Return true if this label's value is known. If VALUE_P is given, + // set *VALUE_P to the known value if returning true. + bool IsKnownConstant(uint64_t *value_p = NULL) const; + + // Return true if the offset from LABEL to this label is known. If + // OFFSET_P is given, set *OFFSET_P to the offset when returning true. + // + // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m', + // except that it also returns a value indicating whether the + // subtraction is possible given what we currently know of l and m. + // It can be possible even if we don't know l and m's values. For + // example: + // + // Label l, m; + // m = l + 10; + // l.IsKnownConstant(); // false + // m.IsKnownConstant(); // false + // uint64_t d; + // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10. + // l-m // -10 + // m-l // 10 + // m.Value() // error: m's value is not known + bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const; + + private: + // A label's value, or if that is not yet known, how the value is + // related to other labels' values. A binding may be: + // - a known constant, + // - constrained to be equal to some other binding plus a constant, or + // - unconstrained, and free to take on any value. + // + // Many labels may point to a single binding, and each binding may + // refer to another, so bindings and labels form trees whose leaves + // are labels, whose interior nodes (and roots) are bindings, and + // where links point from children to parents. Bindings are + // reference counted, allowing labels to be lightweight, copyable, + // assignable, placed in containers, and so on. + class Binding { + public: + Binding(); + Binding(uint64_t addend); + ~Binding(); + + // Increment our reference count. + void Acquire() { reference_count_++; }; + // Decrement our reference count, and return true if it is zero. + bool Release() { return --reference_count_ == 0; } + + // Set this binding to be equal to BINDING + ADDEND. If BINDING is + // NULL, then set this binding to the known constant ADDEND. + // Update every binding on this binding's chain to point directly + // to BINDING, or to be a constant, with addends adjusted + // appropriately. + void Set(Binding *binding, uint64_t value); + + // Return what we know about the value of this binding. + // - If this binding's value is a known constant, set BASE to + // NULL, and set ADDEND to its value. + // - If this binding is not a known constant but related to other + // bindings, set BASE to the binding at the end of the relation + // chain (which will always be unconstrained), and set ADDEND to the + // value to add to that binding's value to get this binding's + // value. + // - If this binding is unconstrained, set BASE to this, and leave + // ADDEND unchanged. + void Get(Binding **base, uint64_t *addend); + + private: + // There are three cases: + // + // - A binding representing a known constant value has base_ NULL, + // and addend_ equal to the value. + // + // - A binding representing a completely unconstrained value has + // base_ pointing to this; addend_ is unused. + // + // - A binding whose value is related to some other binding's + // value has base_ pointing to that other binding, and addend_ + // set to the amount to add to that binding's value to get this + // binding's value. We only represent relationships of the form + // x = y+c. + // + // Thus, the bind_ links form a chain terminating in either a + // known constant value or a completely unconstrained value. Most + // operations on bindings do path compression: they change every + // binding on the chain to point directly to the final value, + // adjusting addends as appropriate. + Binding *base_; + uint64_t addend_; + + // The number of Labels and Bindings pointing to this binding. + // (When a binding points to itself, indicating a completely + // unconstrained binding, that doesn't count as a reference.) + int reference_count_; + }; + + // This label's value. + Binding *value_; +}; + +inline Label operator+(uint64_t a, const Label &l) { return l + a; } +// Note that int-Label isn't defined, as negating a Label is not an +// operation we support. + +// Conventions for representing larger numbers as sequences of bytes. +enum Endianness { + kBigEndian, // Big-endian: the most significant byte comes first. + kLittleEndian, // Little-endian: the least significant byte comes first. + kUnsetEndian, // used internally +}; + +// A section is a sequence of bytes, constructed by appending bytes +// to the end. Sections have a convenient and flexible set of member +// functions for appending data in various formats: big-endian and +// little-endian signed and unsigned values of different sizes; +// LEB128 and ULEB128 values (see below), and raw blocks of bytes. +// +// If you need to append a value to a section that is not convenient +// to compute immediately, you can create a label, append the +// label's value to the section, and then set the label's value +// later, when it's convenient to do so. Once a label's value is +// known, the section class takes care of updating all previously +// appended references to it. +// +// Once all the labels to which a section refers have had their +// values determined, you can get a copy of the section's contents +// as a string. +// +// Note that there is no specified "start of section" label. This is +// because there are typically several different meanings for "the +// start of a section": the offset of the section within an object +// file, the address in memory at which the section's content appear, +// and so on. It's up to the code that uses the Section class to +// keep track of these explicitly, as they depend on the application. +class Section { + public: + Section(Endianness endianness = kUnsetEndian) + : endianness_(endianness) { }; + + // A base class destructor should be either public and virtual, + // or protected and nonvirtual. + virtual ~Section() { }; + + // Set the default endianness of this section to ENDIANNESS. This + // sets the behavior of the D appending functions. If the + // assembler's default endianness was set, this is the + void set_endianness(Endianness endianness) { + endianness_ = endianness; + } + + // Return the default endianness of this section. + Endianness endianness() const { return endianness_; } + + // Append the SIZE bytes at DATA or the contents of STRING to the + // end of this section. Return a reference to this section. + Section &Append(const uint8_t *data, size_t size) { + contents_.append(reinterpret_cast(data), size); + return *this; + }; + Section &Append(const string &data) { + contents_.append(data); + return *this; + }; + + // Append SIZE copies of BYTE to the end of this section. Return a + // reference to this section. + Section &Append(size_t size, uint8_t byte) { + contents_.append(size, (char) byte); + return *this; + } + + // Append NUMBER to this section. ENDIANNESS is the endianness to + // use to write the number. SIZE is the length of the number in + // bytes. Return a reference to this section. + Section &Append(Endianness endianness, size_t size, uint64_t number); + Section &Append(Endianness endianness, size_t size, const Label &label); + + // Append SECTION to the end of this section. The labels SECTION + // refers to need not be defined yet. + // + // Note that this has no effect on any Labels' values, or on + // SECTION. If placing SECTION within 'this' provides new + // constraints on existing labels' values, then it's up to the + // caller to fiddle with those labels as needed. + Section &Append(const Section §ion); + + // Append the contents of DATA as a series of bytes terminated by + // a NULL character. + Section &AppendCString(const string &data) { + Append(data); + contents_ += '\0'; + return *this; + } + + // Append at most SIZE bytes from DATA; if DATA is less than SIZE bytes + // long, pad with '\0' characters. + Section &AppendCString(const string &data, size_t size) { + contents_.append(data, 0, size); + if (data.size() < size) + Append(size - data.size(), 0); + return *this; + } + + // Append VALUE or LABEL to this section, with the given bit width and + // endianness. Return a reference to this section. + // + // The names of these functions have the form : + // is either 'L' (little-endian, least significant byte first), + // 'B' (big-endian, most significant byte first), or + // 'D' (default, the section's default endianness) + // is 8, 16, 32, or 64. + // + // Since endianness doesn't matter for a single byte, all the + // =8 functions are equivalent. + // + // These can be used to write both signed and unsigned values, as + // the compiler will properly sign-extend a signed value before + // passing it to the function, at which point the function's + // behavior is the same either way. + Section &L8(uint8_t value) { contents_ += value; return *this; } + Section &B8(uint8_t value) { contents_ += value; return *this; } + Section &D8(uint8_t value) { contents_ += value; return *this; } + Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t), + &B16(uint16_t), &B32(uint32_t), &B64(uint64_t), + &D16(uint16_t), &D32(uint32_t), &D64(uint64_t); + Section &L8(const Label &label), &L16(const Label &label), + &L32(const Label &label), &L64(const Label &label), + &B8(const Label &label), &B16(const Label &label), + &B32(const Label &label), &B64(const Label &label), + &D8(const Label &label), &D16(const Label &label), + &D32(const Label &label), &D64(const Label &label); + + // Append VALUE in a signed LEB128 (Little-Endian Base 128) form. + // + // The signed LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between -0x40 and 0x3f, then its signed LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its signed LEB128 representation is (N & 0x7f) | + // 0x80, followed by the signed LEB128 representation of N / 128, + // rounded towards negative infinity. + // + // In other words, we break VALUE into groups of seven bits, put + // them in little-endian order, and then write them as eight-bit + // bytes with the high bit on all but the last. + // + // Note that VALUE cannot be a Label (we would have to implement + // relaxation). + Section &LEB128(long long value); + + // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form. + // + // The unsigned LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between 0 and 0x7f, then its unsigned LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | + // 0x80, followed by the unsigned LEB128 representation of N / + // 128, rounded towards negative infinity. + // + // Note that VALUE cannot be a Label (we would have to implement + // relaxation). + Section &ULEB128(uint64_t value); + + // Jump to the next location aligned on an ALIGNMENT-byte boundary, + // relative to the start of the section. Fill the gap with PAD_BYTE. + // ALIGNMENT must be a power of two. Return a reference to this + // section. + Section &Align(size_t alignment, uint8_t pad_byte = 0); + + // Clear the contents of this section. + void Clear(); + + // Return the current size of the section. + size_t Size() const { return contents_.size(); } + + // Return a label representing the start of the section. + // + // It is up to the user whether this label represents the section's + // position in an object file, the section's address in memory, or + // what have you; some applications may need both, in which case + // this simple-minded interface won't be enough. This class only + // provides a single start label, for use with the Here and Mark + // member functions. + // + // Ideally, we'd provide this in a subclass that actually knows more + // about the application at hand and can provide an appropriate + // collection of start labels. But then the appending member + // functions like Append and D32 would return a reference to the + // base class, not the derived class, and the chaining won't work. + // Since the only value here is in pretty notation, that's a fatal + // flaw. + Label start() const { return start_; } + + // Return a label representing the point at which the next Appended + // item will appear in the section, relative to start(). + Label Here() const { return start_ + Size(); } + + // Set *LABEL to Here, and return a reference to this section. + Section &Mark(Label *label) { *label = Here(); return *this; } + + // If there are no undefined label references left in this + // section, set CONTENTS to the contents of this section, as a + // string, and clear this section. Return true on success, or false + // if there were still undefined labels. + bool GetContents(string *contents); + + private: + // Used internally. A reference to a label's value. + struct Reference { + Reference(size_t set_offset, Endianness set_endianness, size_t set_size, + const Label &set_label) + : offset(set_offset), endianness(set_endianness), size(set_size), + label(set_label) { } + + // The offset of the reference within the section. + size_t offset; + + // The endianness of the reference. + Endianness endianness; + + // The size of the reference. + size_t size; + + // The label to which this is a reference. + Label label; + }; + + // The default endianness of this section. + Endianness endianness_; + + // The contents of the section. + string contents_; + + // References to labels within those contents. + vector references_; + + // A label referring to the beginning of the section. + Label start_; +}; + +} // namespace test_assembler +} // namespace google_breakpad + +#endif // PROCESSOR_TEST_ASSEMBLER_H_ diff --git a/breakpad/common/test_assembler_unittest.cc b/breakpad/common/test_assembler_unittest.cc new file mode 100644 index 0000000000..94b5a5ce5f --- /dev/null +++ b/breakpad/common/test_assembler_unittest.cc @@ -0,0 +1,1662 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" + +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using testing::Test; + +TEST(ConstructLabel, Simple) { + Label l; +} + +TEST(ConstructLabel, Undefined) { + Label l; + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(ConstructLabelDeathTest, Undefined) { + Label l; + ASSERT_DEATH(l.Value(), "IsKnownConstant\\(&v\\)"); +} + +TEST(ConstructLabel, Constant) { + Label l(0x060b9f974eaf301eULL); + uint64_t v; + EXPECT_TRUE(l.IsKnownConstant(&v)); + EXPECT_EQ(v, 0x060b9f974eaf301eULL); + EXPECT_EQ(l.Value(), 0x060b9f974eaf301eULL); +} + +TEST(ConstructLabel, Copy) { + Label l; + Label m(l); + uint64_t v; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &v)); + EXPECT_EQ(0U, v); +} + +// The left-hand-side of a label assignment can be either +// unconstrained, related, or known. The right-hand-side can be any of +// those, or an integer. +TEST(Assignment, UnconstrainedToUnconstrained) { + Label l, m; + l = m; + EXPECT_EQ(0U, l-m); + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, UnconstrainedToRelated) { + Label l, m, n; + l = n; + l = m; + EXPECT_EQ(0U, l-m); + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, UnconstrainedToKnown) { + Label l, m; + l = 0x8fd16e55b20a39c1ULL; + l = m; + EXPECT_EQ(0U, l-m); + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); + EXPECT_EQ(0U, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x8fd16e55b20a39c1ULL, m.Value()); +} + +TEST(Assignment, RelatedToUnconstrained) { + Label l, m, n; + m = n; + l = m; + EXPECT_EQ(0U, l-n); + EXPECT_TRUE(l.IsKnownOffsetFrom(n)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(n, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, RelatedToRelated) { + Label l, m, n, o; + l = n; + m = o; + l = m; + EXPECT_EQ(0U, n-o); + EXPECT_TRUE(n.IsKnownOffsetFrom(o)); + uint64_t d; + EXPECT_TRUE(n.IsKnownOffsetFrom(o, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, RelatedToKnown) { + Label l, m, n; + m = n; + l = 0xd2011f8c82ad56f2ULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0xd2011f8c82ad56f2ULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0xd2011f8c82ad56f2ULL, m.Value()); + EXPECT_TRUE(n.IsKnownConstant()); + EXPECT_EQ(0xd2011f8c82ad56f2ULL, n.Value()); +} + +TEST(Assignment, KnownToUnconstrained) { + Label l, m; + m = 0x50b024c0d6073887ULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x50b024c0d6073887ULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x50b024c0d6073887ULL, m.Value()); +} + +TEST(Assignment, KnownToRelated) { + Label l, m, n; + l = n; + m = 0x5348883655c727e5ULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x5348883655c727e5ULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x5348883655c727e5ULL, m.Value()); + EXPECT_TRUE(n.IsKnownConstant()); + EXPECT_EQ(0x5348883655c727e5ULL, n.Value()); +} + +TEST(Assignment, KnownToKnown) { + Label l, m; + l = 0x36c209c20987564eULL; + m = 0x36c209c20987564eULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x36c209c20987564eULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x36c209c20987564eULL, m.Value()); +} + +TEST(Assignment, ConstantToUnconstrained) { + Label l; + l = 0xc02495f4d7f5a957ULL; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0xc02495f4d7f5a957ULL, l.Value()); +} + +TEST(Assignment, ConstantToRelated) { + Label l, m; + l = m; + l = 0x4577901cf275488dULL; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x4577901cf275488dULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x4577901cf275488dULL, m.Value()); +} + +TEST(Assignment, ConstantToKnown) { + Label l; + l = 0xec0b9c369b7e8ea7ULL; + l = 0xec0b9c369b7e8ea7ULL; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0xec0b9c369b7e8ea7ULL, l.Value()); +} + +TEST(AssignmentDeathTest, Self) { + Label l; + ASSERT_DEATH(l = l, "binding != this"); +} + +TEST(AssignmentDeathTest, IndirectCycle) { + Label l, m, n; + l = m; + m = n; + ASSERT_DEATH(n = l, "binding != this"); +} + +TEST(AssignmentDeathTest, Cycle) { + Label l, m, n, o; + l = m; + m = n; + o = n; + ASSERT_DEATH(o = l, "binding != this"); +} + +TEST(Addition, LabelConstant) { + Label l, m; + m = l + 0x5248d93e8bbe9497ULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0x5248d93e8bbe9497ULL, d); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(Addition, ConstantLabel) { + Label l, m; + m = 0xf51e94e00d6e3c84ULL + l; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0xf51e94e00d6e3c84ULL, d); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(Addition, KnownLabelConstant) { + Label l, m; + l = 0x16286307042ce0d8ULL; + m = l + 0x3fdddd91306719d7ULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0x3fdddd91306719d7ULL, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x16286307042ce0d8ULL + 0x3fdddd91306719d7ULL, m.Value()); +} + +TEST(Addition, ConstantKnownLabel) { + Label l, m; + l = 0x50f62d0cdd1031deULL; + m = 0x1b13462d8577c538ULL + l; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0x1b13462d8577c538ULL, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x50f62d0cdd1031deULL + 0x1b13462d8577c538ULL, m.Value()); +} + +TEST(Subtraction, LabelConstant) { + Label l, m; + m = l - 0x0620884d21d3138eULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(-0x0620884d21d3138eULL, d); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(Subtraction, KnownLabelConstant) { + Label l, m; + l = 0x6237fbaf9ef7929eULL; + m = l - 0x317730995d2ab6eeULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(-0x317730995d2ab6eeULL, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x6237fbaf9ef7929eULL - 0x317730995d2ab6eeULL, m.Value()); +} + +TEST(SubtractionDeathTest, LabelLabel) { + Label l, m; + ASSERT_DEATH(l - m, "IsKnownOffsetFrom\\(label, &offset\\)"); +} + +TEST(Subtraction, LabelLabel) { + Label l, m; + l = m + 0x7fa77ec63e28a17aULL; + EXPECT_EQ(0x7fa77ec63e28a17aULL, l - m); + EXPECT_EQ(-0x7fa77ec63e28a17aULL, m - l); +} + +TEST(IsKnownConstant, Undefined) { + Label l; + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(IsKnownConstant, RelatedLabel) { + Label l, m; + l = m; + EXPECT_FALSE(l.IsKnownConstant()); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(IsKnownConstant, Constant) { + Label l; + l = 0xf374b1bdd6a22576ULL; + EXPECT_TRUE(l.IsKnownConstant()); +} + +TEST(IsKnownOffsetFrom, Unrelated) { + Label l, m; + EXPECT_FALSE(l.IsKnownOffsetFrom(m)); +} + +TEST(IsKnownOffsetFrom, Related) { + Label l, m; + l = m; + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); +} + +// Test the construction of chains of related labels, and the +// propagation of values through them. +// +// Although the relations between labels are supposed to behave +// symmetrically --- that is, 'a = b' should put a and b in +// indistinguishable states --- there's a distinction made internally +// between the target (a) and the source (b). +// +// So there are five test axes to cover: +// +// - Do we construct the chain with assignment ("Assign") or with constructors +// ("Construct")? +// +// - Do we set the value of the label at the start of the chain +// ("Start") or the label at the end ("End")? +// +// - Are we testing the propagation of a relationship between variable +// values ("Relation"), or the propagation of a known constant value +// ("Value")? +// +// - Do we set the value before building the chain ("Before") or after +// the chain has been built ("After")? +// +// - Do we add new relationships to the end of the existing chain +// ("Forward") or to the beginning ("Backward")? +// +// Of course, "Construct" and "Backward" can't be combined, which +// eliminates eight combinations, and "Construct", "End", and "Before" +// can't be combined, which eliminates two more, so there are are 22 +// combinations, not 32. + +TEST(LabelChain, AssignStartRelationBeforeForward) { + Label a, b, c, d; + Label x; + a = x; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartRelationBeforeBackward) { + Label a, b, c, d; + Label x; + a = x; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartRelationAfterForward) { + Label a, b, c, d; + Label x; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + a = x; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartRelationAfterBackward) { + Label a, b, c, d; + Label x; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + a = x; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartValueBeforeForward) { + Label a, b, c, d; + a = 0xa131200190546ac2ULL; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(0xa131200190546ac2ULL + 0x111U, d.Value()); + EXPECT_EQ(0xa131200190546ac2ULL + 0x11U, c.Value()); + EXPECT_EQ(0xa131200190546ac2ULL + 0x1U, b.Value()); + EXPECT_EQ(0xa131200190546ac2ULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignStartValueBeforeBackward) { + Label a, b, c, d; + a = 0x8da17e1670ad4fa2ULL; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x111U, d.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x11U, c.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x1U, b.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignStartValueAfterForward) { + Label a, b, c, d; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + a = 0x99b8f51bafd41adaULL; + EXPECT_EQ(0x99b8f51bafd41adaULL + 0x111U, d.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL + 0x11U, c.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL + 0x1U, b.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignStartValueAfterBackward) { + Label a, b, c, d; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + a = 0xc86ca1d97ab5df6eULL; + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x111U, d.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x11U, c.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x1U, b.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignEndRelationBeforeForward) { + Label a, b, c, d; + Label x; + x = d; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0U, d-x); +} + +TEST(LabelChain, AssignEndRelationBeforeBackward) { + Label a, b, c, d; + Label x; + x = d; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0U, d-x); +} + +TEST(LabelChain, AssignEndRelationAfterForward) { + Label a, b, c, d; + Label x; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + x = d; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0x000U, d-x); +} + +TEST(LabelChain, AssignEndRelationAfterBackward) { + Label a, b, c, d; + Label x; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + x = d; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0x000U, d-x); +} + +TEST(LabelChain, AssignEndValueBeforeForward) { + Label a, b, c, d; + d = 0xa131200190546ac2ULL; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(0xa131200190546ac2ULL - 0x111, a.Value()); + EXPECT_EQ(0xa131200190546ac2ULL - 0x110, b.Value()); + EXPECT_EQ(0xa131200190546ac2ULL - 0x100, c.Value()); + EXPECT_EQ(0xa131200190546ac2ULL - 0x000, d.Value()); +} + +TEST(LabelChain, AssignEndValueBeforeBackward) { + Label a, b, c, d; + d = 0x8da17e1670ad4fa2ULL; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x111, a.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x110, b.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x100, c.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x000, d.Value()); +} + +TEST(LabelChain, AssignEndValueAfterForward) { + Label a, b, c, d; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + d = 0x99b8f51bafd41adaULL; + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value()); +} + +TEST(LabelChain, AssignEndValueAfterBackward) { + Label a, b, c, d; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + d = 0xc86ca1d97ab5df6eULL; + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x111, a.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x110, b.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x100, c.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x000, d.Value()); +} + +TEST(LabelChain, ConstructStartRelationBeforeForward) { + Label x; + Label a(x); + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, ConstructStartRelationAfterForward) { + Label x; + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + a = x; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, ConstructStartValueBeforeForward) { + Label a(0x5d234d177d01ccc8ULL); + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x111U, d.Value()); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x011U, c.Value()); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x001U, b.Value()); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x000U, a.Value()); +} + +TEST(LabelChain, ConstructStartValueAfterForward) { + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + a = 0xded85d54586e84fcULL; + EXPECT_EQ(0xded85d54586e84fcULL + 0x111U, d.Value()); + EXPECT_EQ(0xded85d54586e84fcULL + 0x011U, c.Value()); + EXPECT_EQ(0xded85d54586e84fcULL + 0x001U, b.Value()); + EXPECT_EQ(0xded85d54586e84fcULL + 0x000U, a.Value()); +} + +TEST(LabelChain, ConstructEndRelationAfterForward) { + Label x; + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + x = d; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0x000U, d-x); +} + +TEST(LabelChain, ConstructEndValueAfterForward) { + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + d = 0x99b8f51bafd41adaULL; + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value()); +} + +TEST(LabelTree, KnownValue) { + Label l, m, n, o, p; + l = m; + m = n; + o = p; + p = n; + l = 0x536b5de3d468a1b5ULL; + EXPECT_EQ(0x536b5de3d468a1b5ULL, o.Value()); +} + +TEST(LabelTree, Related) { + Label l, m, n, o, p; + l = m - 1; + m = n - 10; + o = p + 100; + p = n + 1000; + EXPECT_EQ(1111U, o - l); +} + +TEST(EquationDeathTest, EqualConstants) { + Label m = 0x0d3962f280f07d24ULL; + Label n = 0x0d3962f280f07d24ULL; + m = n; // no death expected +} + +TEST(EquationDeathTest, EqualIndirectConstants) { + Label m = 0xa347f1e5238fe6a1ULL; + Label n; + Label o = n; + n = 0xa347f1e5238fe6a1ULL; + n = m; // no death expected +} + +TEST(EquationDeathTest, ConstantClash) { + Label m = 0xd4cc0f4f630ec741ULL; + Label n = 0x934cd2d8254fc3eaULL; + ASSERT_DEATH(m = n, "addend_ == addend"); +} + +TEST(EquationDeathTest, IndirectConstantClash) { + Label m = 0xd4cc0f4f630ec741ULL; + Label n, o; + n = o; + o = 0xcfbe3b83ac49ce86ULL; + ASSERT_DEATH(m = n, "addend_ == addend"); +} + +// Assigning to a related label may free the next Binding on its +// chain. This test always passes; it is interesting to memory +// checkers and coverage analysis. +TEST(LabelReferenceCount, AssignmentFree) { + Label l; + { + Label m; + l = m; + } + // This should free m's Binding. + l = 0xca8bae92f0376d4fULL; + ASSERT_EQ(0xca8bae92f0376d4fULL, l.Value()); +} + +// Finding the value of a label may free the Binding it refers to. This test +// always passes; it is interesting to memory checkers and coverage analysis. +TEST(LabelReferenceCount, FindValueFree) { + Label l; + { + Label m, n; + l = m; + m = n; + n = 0x7a0b0c576672daafULL; + // At this point, l's Binding refers to m's Binding, which refers + // to n's binding. + } + // Now, l is the only reference keeping the three Bindings alive. + // Resolving its value should free l's and m's original bindings. + ASSERT_EQ(0x7a0b0c576672daafULL, l.Value()); +} + +TEST(ConstructSection, Simple) { + Section s; +} + +TEST(ConstructSection, WithEndian) { + Section s(kBigEndian); +} + +// A fixture class for TestAssembler::Section tests. +class SectionFixture { + public: + Section section; + string contents; + static const uint8_t data[]; + static const size_t data_size; +}; + +const uint8_t SectionFixture::data[] = { + 0x87, 0x4f, 0x43, 0x67, 0x30, 0xd0, 0xd4, 0x0e +}; + +#define I0() +#define I1(a) { a } +#define I2(a,b) { a,b } +#define I3(a,b,c) { a,b,c } +#define I4(a,b,c,d) { a,b,c,d } +#define I5(a,b,c,d,e) { a,b,c,d,e } +#define I6(a,b,c,d,e,f) { a,b,c,d,e,f } +#define I7(a,b,c,d,e,f,g) { a,b,c,d,e,f,g } +#define I8(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g,h } +#define I9(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i } +#define ASSERT_BYTES(s, b) \ + do \ + { \ + static const uint8_t expected_bytes[] = b; \ + ASSERT_EQ(sizeof(expected_bytes), s.size()); \ + ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \ + sizeof(expected_bytes)) == 0); \ + } \ + while(0) + +class Append: public SectionFixture, public Test { }; + +TEST_F(Append, Bytes) { + section.Append(data, sizeof(data)); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(sizeof(data), contents.size()); + EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); +} + +TEST_F(Append, BytesTwice) { + section.Append(data, sizeof(data)); + section.Append(data, sizeof(data)); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(2 * sizeof(data), contents.size()); + ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); + ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data), + (const char *) data, sizeof(data))); +} + +TEST_F(Append, String) { + string s1 = "howdy "; + string s2 = "there"; + section.Append(s1); + section.Append(s2); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_STREQ(contents.c_str(), "howdy there"); +} + +TEST_F(Append, CString) { + section.AppendCString("howdy"); + section.AppendCString(""); + section.AppendCString("there"); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(string("howdy\0\0there\0", 13), contents); +} + +TEST_F(Append, CStringSize) { + section.AppendCString("howdy", 3); + section.AppendCString("there", 5); + section.AppendCString("fred", 6); + section.AppendCString("natalie", 0); + section.AppendCString("", 10); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(string("howtherefred\0\0\0\0\0\0\0\0\0\0\0\0", 24), contents); +} + +TEST_F(Append, RepeatedBytes) { + section.Append((size_t) 10, '*'); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_STREQ(contents.c_str(), "**********"); +} + +TEST_F(Append, GeneralLE1) { + section.Append(kLittleEndian, 1, 42); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(42)); +} + +TEST_F(Append, GeneralLE2) { + section.Append(kLittleEndian, 2, 0x15a1); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0xa1, 0x15)); +} + +TEST_F(Append, GeneralLE3) { + section.Append(kLittleEndian, 3, 0x59ae8d); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59)); +} + +TEST_F(Append, GeneralLE4) { + section.Append(kLittleEndian, 4, 0x51603c56); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51)); +} + +TEST_F(Append, GeneralLE5) { + section.Append(kLittleEndian, 5, 0x385e2803b4ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38)); +} + +TEST_F(Append, GeneralLE6) { + section.Append(kLittleEndian, 6, 0xc7db9534dd1fULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7)); +} + +TEST_F(Append, GeneralLE7) { + section.Append(kLittleEndian, 7, 0x1445c9f1b843e6ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14)); +} + +TEST_F(Append, GeneralLE8) { + section.Append(kLittleEndian, 8, 0xaf48019dfe5c01e5ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf)); +} + +TEST_F(Append, GeneralBE1) { + section.Append(kBigEndian, 1, 0xd0ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(0xd0)); +} + +TEST_F(Append, GeneralBE2) { + section.Append(kBigEndian, 2, 0x2e7eULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2e, 0x7e)); +} + +TEST_F(Append, GeneralBE3) { + section.Append(kBigEndian, 3, 0x37dad6ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6)); +} + +TEST_F(Append, GeneralBE4) { + section.Append(kBigEndian, 4, 0x715935c7ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7)); +} + +TEST_F(Append, GeneralBE5) { + section.Append(kBigEndian, 5, 0x42baeb02b7ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7)); +} + +TEST_F(Append, GeneralBE6) { + section.Append(kBigEndian, 6, 0xf1cdf10e7b18ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18)); +} + +TEST_F(Append, GeneralBE7) { + section.Append(kBigEndian, 7, 0xf50a724f0b0d20ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20)); +} + +TEST_F(Append, GeneralBE8) { + section.Append(kBigEndian, 8, 0xa6b2cb5e98dc9c16ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16)); +} + +TEST_F(Append, GeneralLE1Label) { + Label l; + section.Append(kLittleEndian, 1, l); + l = 42; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(42)); +} + +TEST_F(Append, GeneralLE2Label) { + Label l; + section.Append(kLittleEndian, 2, l); + l = 0x15a1; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0xa1, 0x15)); +} + +TEST_F(Append, GeneralLE3Label) { + Label l; + section.Append(kLittleEndian, 3, l); + l = 0x59ae8d; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59)); +} + +TEST_F(Append, GeneralLE4Label) { + Label l; + section.Append(kLittleEndian, 4, l); + l = 0x51603c56; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51)); +} + +TEST_F(Append, GeneralLE5Label) { + Label l; + section.Append(kLittleEndian, 5, l); + l = 0x385e2803b4ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38)); +} + +TEST_F(Append, GeneralLE6Label) { + Label l; + section.Append(kLittleEndian, 6, l); + l = 0xc7db9534dd1fULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7)); +} + +TEST_F(Append, GeneralLE7Label) { + Label l; + section.Append(kLittleEndian, 7, l); + l = 0x1445c9f1b843e6ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14)); +} + +TEST_F(Append, GeneralLE8Label) { + Label l; + section.Append(kLittleEndian, 8, l); + l = 0xaf48019dfe5c01e5ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf)); +} + +TEST_F(Append, GeneralBE1Label) { + Label l; + section.Append(kBigEndian, 1, l); + l = 0xd0ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(0xd0)); +} + +TEST_F(Append, GeneralBE2Label) { + Label l; + section.Append(kBigEndian, 2, l); + l = 0x2e7eULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2e, 0x7e)); +} + +TEST_F(Append, GeneralBE3Label) { + Label l; + section.Append(kBigEndian, 3, l); + l = 0x37dad6ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6)); +} + +TEST_F(Append, GeneralBE4Label) { + Label l; + section.Append(kBigEndian, 4, l); + l = 0x715935c7ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7)); +} + +TEST_F(Append, GeneralBE5Label) { + Label l; + section.Append(kBigEndian, 5, l); + l = 0x42baeb02b7ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7)); +} + +TEST_F(Append, GeneralBE6Label) { + Label l; + section.Append(kBigEndian, 6, l); + l = 0xf1cdf10e7b18ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18)); +} + +TEST_F(Append, GeneralBE7Label) { + Label l; + section.Append(kBigEndian, 7, l); + l = 0xf50a724f0b0d20ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20)); +} + +TEST_F(Append, GeneralBE8Label) { + Label l; + section.Append(kBigEndian, 8, l); + l = 0xa6b2cb5e98dc9c16ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16)); +} + +TEST_F(Append, B8) { + section.Append(1, 0x2a); + section.B8(0xd3U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xd3)); +} + +TEST_F(Append, B8Label) { + Label l; + section.Append(1, 0x2a); + section.B8(l); + l = 0x4bU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x4b)); +} + +TEST_F(Append, B16) { + section.Append(1, 0x2a); + section.B16(0x472aU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x47, 0x2a)); +} + +TEST_F(Append, B16Label) { + Label l; + section.Append(1, 0x2a); + section.B16(l); + l = 0x55e8U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x55, 0xe8)); +} + +TEST_F(Append, B32) { + section.Append(1, 0x2a); + section.B32(0xbd412cbcU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0xbd, 0x41, 0x2c, 0xbc)); +} + +TEST_F(Append, B32Label) { + Label l; + section.Append(1, 0x2a); + section.B32(l); + l = 0x208e37d5U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x20, 0x8e, 0x37, 0xd5)); +} + +TEST_F(Append, B64) { + section.Append(1, 0x2a); + section.B64(0x3402a013111e68adULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x34, 0x02, 0xa0, 0x13, 0x11, 0x1e, 0x68, 0xad)); +} + +TEST_F(Append, B64Label) { + Label l; + section.Append(1, 0x2a); + section.B64(l); + l = 0x355dbfbb4ac6d57fULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x35, 0x5d, 0xbf, 0xbb, 0x4a, 0xc6, 0xd5, 0x7f)); +} + +TEST_F(Append, L8) { + section.Append(1, 0x2a); + section.L8(0x26U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x26)); +} + +TEST_F(Append, L8Label) { + Label l; + section.Append(1, 0x2a); + section.L8(l); + l = 0xa8U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xa8)); +} + +TEST_F(Append, L16) { + section.Append(1, 0x2a); + section.L16(0xca6dU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x6d, 0xca)); +} + +TEST_F(Append, L16Label) { + Label l; + section.Append(1, 0x2a); + section.L16(l); + l = 0xd21fU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x1f, 0xd2)); +} + +TEST_F(Append, L32) { + section.Append(1, 0x2a); + section.L32(0x558f6181U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x81, 0x61, 0x8f, 0x55)); +} + +TEST_F(Append, L32Label) { + Label l; + section.Append(1, 0x2a); + section.L32(l); + l = 0x4b810f82U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x82, 0x0f, 0x81, 0x4b)); +} + +TEST_F(Append, L64) { + section.Append(1, 0x2a); + section.L64(0x564384f7579515bfULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xbf, 0x15, 0x95, 0x57, 0xf7, 0x84, 0x43, 0x56)); +} + +TEST_F(Append, L64Label) { + Label l; + section.Append(1, 0x2a); + section.L64(l); + l = 0x424b1d020667c8dbULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xdb, 0xc8, 0x67, 0x06, 0x02, 0x1d, 0x4b, 0x42)); +} + +TEST_F(Append, D8Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D8(0xe6U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xe6)); +} + +TEST_F(Append, D8BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D8(l); + l = 0xeeU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xee)); +} + +TEST_F(Append, D16Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D16(0x83b1U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x83, 0xb1)); +} + +TEST_F(Append, D16BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D16(l); + l = 0x5b55U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x5b, 0x55)); +} + +TEST_F(Append, D32Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D32(0xd0b0e431U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0xd0, 0xb0, 0xe4, 0x31)); +} + +TEST_F(Append, D32BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D32(l); + l = 0x312fb340U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x31, 0x2f, 0xb3, 0x40)); +} + +TEST_F(Append, D64Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D64(0xb109843500dbcb16ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xb1, 0x09, 0x84, 0x35, 0x00, 0xdb, 0xcb, 0x16)); +} + +TEST_F(Append, D64BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D64(l); + l = 0x9a0d61b70f671fd7ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x9a, 0x0d, 0x61, 0xb7, 0x0f, 0x67, 0x1f, 0xd7)); +} + +TEST_F(Append, D8Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D8(0x42U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x42)); +} + +TEST_F(Append, D8LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D8(l); + l = 0x05U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x05)); +} + +TEST_F(Append, D16Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D16(0xc5c5U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0xc5, 0xc5)); +} + +TEST_F(Append, D16LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D16(l); + l = 0xb620U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x20, 0xb6)); +} + +TEST_F(Append, D32Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D32(0x1a87d0feU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0xfe, 0xd0, 0x87, 0x1a)); +} + +TEST_F(Append, D32LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D32(l); + l = 0xb8012d6bU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x6b, 0x2d, 0x01, 0xb8)); +} + +TEST_F(Append, D64Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D64(0x42de75c61375a1deULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xde, 0xa1, 0x75, 0x13, 0xc6, 0x75, 0xde, 0x42)); +} + +TEST_F(Append, D64LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D64(l); + l = 0x8b3bececf3fb5312ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x12, 0x53, 0xfb, 0xf3, 0xec, 0xec, 0x3b, 0x8b)); +} + +TEST_F(Append, Variety) { + Label a, b, c, d, e, f, g, h; + section.Append(kBigEndian, 1, a) + .Append(kLittleEndian, 8, h) + .Append(kBigEndian, 1, 0x8bULL) + .Append(kLittleEndian, 8, 0x0ea56540448f4439ULL) + .Append(kBigEndian, 2, b) + .Append(kLittleEndian, 7, g) + .Append(kBigEndian, 2, 0xcf15ULL) + .Append(kLittleEndian, 7, 0x29694f04c5724aULL) + .Append(kBigEndian, 3, c) + .Append(kLittleEndian, 6, f) + .Append(kBigEndian, 3, 0x8c3ffdULL) + .Append(kLittleEndian, 6, 0x6f11ba80187aULL) + .Append(kBigEndian, 4, d) + .Append(kLittleEndian, 5, e) + .Append(kBigEndian, 4, 0x2fda2472ULL) + .Append(kLittleEndian, 5, 0x0aa02d423fULL) + .Append(kBigEndian, 5, e) + .Append(kLittleEndian, 4, d) + .Append(kBigEndian, 5, 0x53ba432138ULL) + .Append(kLittleEndian, 4, 0xf139ae60ULL) + .Append(kBigEndian, 6, f) + .Append(kLittleEndian, 3, c) + .Append(kBigEndian, 6, 0x168e436af716ULL) + .Append(kLittleEndian, 3, 0x3ef189ULL) + .Append(kBigEndian, 7, g) + .Append(kLittleEndian, 2, b) + .Append(kBigEndian, 7, 0xacd4ef233e47d9ULL) + .Append(kLittleEndian, 2, 0x5311ULL) + .Append(kBigEndian, 8, h) + .Append(kLittleEndian, 1, a) + .Append(kBigEndian, 8, 0x4668d5f1c93637a1ULL) + .Append(kLittleEndian, 1, 0x65ULL); + a = 0x79ac9bd8aa256b35ULL; + b = 0x22d13097ef86c91cULL; + c = 0xf204968b0a05862fULL; + d = 0x163177f15a0eb4ecULL; + e = 0xbd1b0f1d977f2246ULL; + f = 0x2b0842eee83c6461ULL; + g = 0x92f4b928a4bf875eULL; + h = 0x61a199a8f7286ba6ULL; + ASSERT_EQ(8 * 18U, section.Size()); + ASSERT_TRUE(section.GetContents(&contents)); + + static const uint8_t expected[] = { + 0x35, 0xa6, 0x6b, 0x28, 0xf7, 0xa8, 0x99, 0xa1, 0x61, + 0x8b, 0x39, 0x44, 0x8f, 0x44, 0x40, 0x65, 0xa5, 0x0e, + 0xc9, 0x1c, 0x5e, 0x87, 0xbf, 0xa4, 0x28, 0xb9, 0xf4, + 0xcf, 0x15, 0x4a, 0x72, 0xc5, 0x04, 0x4f, 0x69, 0x29, + 0x05, 0x86, 0x2f, 0x61, 0x64, 0x3c, 0xe8, 0xee, 0x42, + 0x8c, 0x3f, 0xfd, 0x7a, 0x18, 0x80, 0xba, 0x11, 0x6f, + 0x5a, 0x0e, 0xb4, 0xec, 0x46, 0x22, 0x7f, 0x97, 0x1d, + 0x2f, 0xda, 0x24, 0x72, 0x3f, 0x42, 0x2d, 0xa0, 0x0a, + 0x1d, 0x97, 0x7f, 0x22, 0x46, 0xec, 0xb4, 0x0e, 0x5a, + 0x53, 0xba, 0x43, 0x21, 0x38, 0x60, 0xae, 0x39, 0xf1, + 0x42, 0xee, 0xe8, 0x3c, 0x64, 0x61, 0x2f, 0x86, 0x05, + 0x16, 0x8e, 0x43, 0x6a, 0xf7, 0x16, 0x89, 0xf1, 0x3e, + 0xf4, 0xb9, 0x28, 0xa4, 0xbf, 0x87, 0x5e, 0x1c, 0xc9, + 0xac, 0xd4, 0xef, 0x23, 0x3e, 0x47, 0xd9, 0x11, 0x53, + 0x61, 0xa1, 0x99, 0xa8, 0xf7, 0x28, 0x6b, 0xa6, 0x35, + 0x46, 0x68, 0xd5, 0xf1, 0xc9, 0x36, 0x37, 0xa1, 0x65, + }; + + ASSERT_TRUE(0 == memcmp(contents.data(), expected, sizeof(expected))); +} + +TEST_F(Append, Section) { + section.Append("murder"); + { + Section middle; + middle.Append(" she"); + section.Append(middle); + } + section.Append(" wrote"); + EXPECT_EQ(16U, section.Size()); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_STREQ(contents.c_str(), "murder she wrote"); +} + +TEST_F(Append, SectionRefs) { + section.Append("sugar "); + Label l; + { + Section middle; + Label m; + middle.B32(m); + section.Append(middle); + m = 0x66726565; + } + section.Append(" jazz"); + EXPECT_EQ(15U, section.Size()); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_STREQ(contents.c_str(), "sugar free jazz"); +} + +TEST_F(Append, LEB128_0) { + section.LEB128(0); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\0", 1), contents); +} + +TEST_F(Append, LEB128_0x3f) { + section.LEB128(0x3f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x3f", 1), contents); +} + +TEST_F(Append, LEB128_0x40) { + section.LEB128(0x40); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xc0\x00", 2), contents); +} + +TEST_F(Append, LEB128_0x7f) { + section.LEB128(0x7f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x00", 2), contents); +} + +TEST_F(Append, LEB128_0x80) { + section.LEB128(0x80); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x01", 2), contents); +} + +TEST_F(Append, LEB128_0xff) { + section.LEB128(0xff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x01", 2), contents); +} + +TEST_F(Append, LEB128_0x1fff) { + section.LEB128(0x1fff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x3f", 2), contents); +} + +TEST_F(Append, LEB128_0x2000) { + section.LEB128(0x2000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\xc0\x00", 3), contents); +} + +TEST_F(Append, LEB128_n1) { + section.LEB128(-1); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x7f", 1), contents); +} + +TEST_F(Append, LEB128_n0x40) { + section.LEB128(-0x40); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x40", 1), contents); +} + +TEST_F(Append, LEB128_n0x41) { + section.LEB128(-0x41); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xbf\x7f", 2), contents); +} + +TEST_F(Append, LEB128_n0x7f) { + section.LEB128(-0x7f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x81\x7f", 2), contents); +} + +TEST_F(Append, LEB128_n0x80) { + section.LEB128(-0x80); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x7f", 2), contents); +} + +TEST_F(Append, LEB128_n0x2000) { + section.LEB128(-0x2000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x40", 2), contents); +} + +TEST_F(Append, LEB128_n0x2001) { + section.LEB128(-0x2001); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\xbf\x7f", 3), contents); +} + +TEST_F(Append,ULEB128_0) { + section.ULEB128(0); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\0", 1), contents); +} + +TEST_F(Append,ULEB128_1) { + section.ULEB128(1); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x01", 1), contents); +} + +TEST_F(Append,ULEB128_0x3f) { + section.ULEB128(0x3f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x3f", 1), contents); +} + +TEST_F(Append,ULEB128_0x40) { + section.ULEB128(0x40); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x40", 1), contents); +} + +TEST_F(Append,ULEB128_0x7f) { + section.ULEB128(0x7f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x7f", 1), contents); +} + +TEST_F(Append,ULEB128_0x80) { + section.ULEB128(0x80); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x01", 2), contents); +} + +TEST_F(Append,ULEB128_0xff) { + section.ULEB128(0xff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x01", 2), contents); +} + +TEST_F(Append,ULEB128_0x100) { + section.ULEB128(0x100); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x02", 2), contents); +} + +TEST_F(Append,ULEB128_0x1fff) { + section.ULEB128(0x1fff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x3f", 2), contents); +} + +TEST_F(Append,ULEB128_0x2000) { + section.ULEB128(0x2000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x40", 2), contents); +} + +TEST_F(Append,ULEB128_0x3fff) { + section.ULEB128(0x3fff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x7f", 2), contents); +} + +TEST_F(Append,ULEB128_0x4000) { + section.ULEB128(0x4000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x80\x01", 3), contents); +} + +TEST_F(Append,ULEB128_12857) { + section.ULEB128(12857); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xb9\x64", 2), contents); +} + +TEST_F(Append, LEBChain) { + section.LEB128(-0x80).ULEB128(12857).Append("*"); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x7f\xb9\x64*", 5), contents); +} + + +class GetContents: public SectionFixture, public Test { }; + +TEST_F(GetContents, Undefined) { + Label l; + section.Append(kLittleEndian, 8, l); + ASSERT_FALSE(section.GetContents(&contents)); +} + +TEST_F(GetContents, ClearsContents) { + section.Append((size_t) 10, '*'); + EXPECT_EQ(10U, section.Size()); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(0U, section.Size()); +} + +TEST_F(GetContents, ClearsReferences) { + Label l; + section.Append(kBigEndian, 1, l); + l = 42; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(42)); + ASSERT_TRUE(section.GetContents(&contents)); // should not die +} + +class Miscellanea: public SectionFixture, public Test { }; + +TEST_F(Miscellanea, Clear) { + section.Append("howdy"); + Label l; + section.L32(l); + EXPECT_EQ(9U, section.Size()); + section.Clear(); + EXPECT_EQ(0U, section.Size()); + l = 0x8d231bf0U; + ASSERT_TRUE(section.GetContents(&contents)); // should not die +} + +TEST_F(Miscellanea, Align) { + section.Append("*"); + EXPECT_EQ(1U, section.Size()); + section.Align(4).Append("*"); + EXPECT_EQ(5U, section.Size()); + section.Append("*").Align(2); + EXPECT_EQ(6U, section.Size()); +} + +TEST_F(Miscellanea, AlignPad) { + section.Append("*"); + EXPECT_EQ(1U, section.Size()); + section.Align(4, ' ').Append("*"); + EXPECT_EQ(5U, section.Size()); + section.Append("*").Align(2, ' '); + EXPECT_EQ(6U, section.Size()); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(string("* **"), contents); +} + +TEST_F(Miscellanea, StartHereMark) { + Label m; + section.Append(42, ' ').Mark(&m).Append(13, '+'); + EXPECT_EQ(42U, m - section.start()); + EXPECT_EQ(42U + 13U, section.Here() - section.start()); + EXPECT_FALSE(section.start().IsKnownConstant()); + EXPECT_FALSE(m.IsKnownConstant()); + EXPECT_FALSE(section.Here().IsKnownConstant()); +} + +TEST_F(Miscellanea, Endianness) { + section.set_endianness(kBigEndian); + EXPECT_EQ(kBigEndian, section.endianness()); + section.set_endianness(kLittleEndian); + EXPECT_EQ(kLittleEndian, section.endianness()); +} diff --git a/breakpad/common/using_std_string.h b/breakpad/common/using_std_string.h new file mode 100644 index 0000000000..13c1da59cc --- /dev/null +++ b/breakpad/common/using_std_string.h @@ -0,0 +1,65 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Ivan Penkov + +// using_std_string.h: Allows building this code in environments where +// global string (::string) exists. +// +// The problem: +// ------------- +// Let's say you want to build this code in an environment where a global +// string type is defined (i.e. ::string). Now, let's suppose that ::string +// is different that std::string and you'd like to have the option to easily +// choose between the two string types. Ideally you'd like to control which +// string type is chosen by simply #defining an identifier. +// +// The solution: +// ------------- +// #define HAS_GLOBAL_STRING somewhere in a global header file and then +// globally replace std::string with string. Then include this header +// file everywhere where string is used. If you want to revert back to +// using std::string, simply remove the #define (HAS_GLOBAL_STRING). + +#ifndef THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ +#define THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ + +#ifdef HAS_GLOBAL_STRING + typedef ::string google_breakpad_string; +#else + using std::string; + typedef std::string google_breakpad_string; +#endif + +// Inicates that type google_breakpad_string is defined +#define HAS_GOOGLE_BREAKPAD_STRING + +#endif // THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ diff --git a/breakpad/common/windows/dia_util.cc b/breakpad/common/windows/dia_util.cc new file mode 100644 index 0000000000..5322997d83 --- /dev/null +++ b/breakpad/common/windows/dia_util.cc @@ -0,0 +1,92 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/windows/dia_util.h" + +#include + +namespace google_breakpad { + +bool FindDebugStream(const wchar_t* name, + IDiaSession* session, + IDiaEnumDebugStreamData** debug_stream) { + CComPtr enum_debug_streams; + if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) { + fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n"); + return false; + } + + CComPtr temp_debug_stream; + ULONG fetched = 0; + while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) && + fetched == 1) { + CComBSTR stream_name; + if (FAILED(temp_debug_stream->get_name(&stream_name))) { + fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n"); + return false; + } + + // Found the stream? + if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) { + *debug_stream = temp_debug_stream.Detach(); + return true; + } + + temp_debug_stream.Release(); + } + + // No table was found. + return false; +} + +bool FindTable(REFIID iid, IDiaSession* session, void** table) { + // Get the table enumerator. + CComPtr enum_tables; + if (FAILED(session->getEnumTables(&enum_tables))) { + fprintf(stderr, "IDiaSession::getEnumTables failed\n"); + return false; + } + + // Iterate through the tables. + CComPtr temp_table; + ULONG fetched = 0; + while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) && + fetched == 1) { + void* temp = NULL; + if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) { + *table = temp; + return true; + } + temp_table.Release(); + } + + // The table was not found. + return false; +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/dia_util.h b/breakpad/common/windows/dia_util.h new file mode 100644 index 0000000000..3c09260953 --- /dev/null +++ b/breakpad/common/windows/dia_util.h @@ -0,0 +1,59 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utilities for loading debug streams and tables from a PDB file. + +#include +#include + +namespace google_breakpad { + +// Find the debug stream of the given |name| in the given |session|. Returns +// true on success, false on error of if the stream does not exist. On success +// the stream will be returned via |debug_stream|. +bool FindDebugStream(const wchar_t* name, + IDiaSession* session, + IDiaEnumDebugStreamData** debug_stream); + +// Finds the first table implementing the COM interface with ID |iid| in the +// given |session|. Returns true on success, false on error or if no such +// table is found. On success the table will be returned via |table|. +bool FindTable(REFIID iid, IDiaSession* session, void** table); + +// A templated version of FindTable. Finds the first table implementing type +// |InterfaceType| in the given |session|. Returns true on success, false on +// error or if no such table is found. On success the table will be returned via +// |table|. +template +bool FindTable(IDiaSession* session, InterfaceType** table) { + return FindTable(__uuidof(InterfaceType), + session, + reinterpret_cast(table)); +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/guid_string.cc b/breakpad/common/windows/guid_string.cc new file mode 100644 index 0000000000..b7f877e66e --- /dev/null +++ b/breakpad/common/windows/guid_string.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// guid_string.cc: Convert GUIDs to strings. +// +// See guid_string.h for documentation. + +#include + +#include "common/windows/string_utils-inl.h" + +#include "common/windows/guid_string.h" + +namespace google_breakpad { + +// static +wstring GUIDString::GUIDToWString(GUID *guid) { + wchar_t guid_string[37]; + swprintf( + guid_string, sizeof(guid_string) / sizeof(guid_string[0]), + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + + // remove when VC++7.1 is no longer supported + guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; + + return wstring(guid_string); +} + +// static +wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) { + wchar_t guid_string[33]; + swprintf( + guid_string, sizeof(guid_string) / sizeof(guid_string[0]), + L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + + // remove when VC++7.1 is no longer supported + guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; + + return wstring(guid_string); +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/guid_string.h b/breakpad/common/windows/guid_string.h new file mode 100644 index 0000000000..f8aa8a2313 --- /dev/null +++ b/breakpad/common/windows/guid_string.h @@ -0,0 +1,58 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// guid_string.cc: Convert GUIDs to strings. + +#ifndef COMMON_WINDOWS_GUID_STRING_H__ +#define COMMON_WINDOWS_GUID_STRING_H__ + +#include + +#include + +namespace google_breakpad { + +using std::wstring; + +class GUIDString { + public: + // Converts guid to a string in the format recommended by RFC 4122 and + // returns the string. + static wstring GUIDToWString(GUID *guid); + + // Converts guid to a string formatted as uppercase hexadecimal, with + // no separators, and returns the string. This is the format used for + // symbol server identifiers, although identifiers have an age tacked + // on to the string. + static wstring GUIDToSymbolServerWString(GUID *guid); +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_GUID_STRING_H__ diff --git a/breakpad/common/windows/http_upload.cc b/breakpad/common/windows/http_upload.cc new file mode 100644 index 0000000000..838185b75b --- /dev/null +++ b/breakpad/common/windows/http_upload.cc @@ -0,0 +1,418 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +// Disable exception handler warnings. +#pragma warning(disable:4530) + +#include + +#include "common/windows/string_utils-inl.h" + +#include "common/windows/http_upload.h" + +namespace google_breakpad { + +using std::ifstream; +using std::ios; + +static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)"; + +// Helper class which closes an internet handle when it goes away +class HTTPUpload::AutoInternetHandle { + public: + explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {} + ~AutoInternetHandle() { + if (handle_) { + InternetCloseHandle(handle_); + } + } + + HINTERNET get() { return handle_; } + + private: + HINTERNET handle_; +}; + +// static +bool HTTPUpload::SendRequest(const wstring &url, + const map ¶meters, + const wstring &upload_file, + const wstring &file_part_name, + int *timeout, + wstring *response_body, + int *response_code) { + if (response_code) { + *response_code = 0; + } + + // TODO(bryner): support non-ASCII parameter names + if (!CheckParameters(parameters)) { + return false; + } + + // Break up the URL and make sure we can handle it + wchar_t scheme[16], host[256], path[256]; + URL_COMPONENTS components; + memset(&components, 0, sizeof(components)); + components.dwStructSize = sizeof(components); + components.lpszScheme = scheme; + components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]); + components.lpszHostName = host; + components.dwHostNameLength = sizeof(host) / sizeof(host[0]); + components.lpszUrlPath = path; + components.dwUrlPathLength = sizeof(path) / sizeof(path[0]); + if (!InternetCrackUrl(url.c_str(), static_cast(url.size()), + 0, &components)) { + return false; + } + bool secure = false; + if (wcscmp(scheme, L"https") == 0) { + secure = true; + } else if (wcscmp(scheme, L"http") != 0) { + return false; + } + + AutoInternetHandle internet(InternetOpen(kUserAgent, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, // proxy name + NULL, // proxy bypass + 0)); // flags + if (!internet.get()) { + return false; + } + + AutoInternetHandle connection(InternetConnect(internet.get(), + host, + components.nPort, + NULL, // user name + NULL, // password + INTERNET_SERVICE_HTTP, + 0, // flags + NULL)); // context + if (!connection.get()) { + return false; + } + + DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0; + http_open_flags |= INTERNET_FLAG_NO_COOKIES; + AutoInternetHandle request(HttpOpenRequest(connection.get(), + L"POST", + path, + NULL, // version + NULL, // referer + NULL, // agent type + http_open_flags, + NULL)); // context + if (!request.get()) { + return false; + } + + wstring boundary = GenerateMultipartBoundary(); + wstring content_type_header = GenerateRequestHeader(boundary); + HttpAddRequestHeaders(request.get(), + content_type_header.c_str(), + static_cast(-1), + HTTP_ADDREQ_FLAG_ADD); + + string request_body; + if (!GenerateRequestBody(parameters, upload_file, + file_part_name, boundary, &request_body)) { + return false; + } + + if (timeout) { + if (!InternetSetOption(request.get(), + INTERNET_OPTION_SEND_TIMEOUT, + timeout, + sizeof(*timeout))) { + fwprintf(stderr, L"Could not unset send timeout, continuing...\n"); + } + + if (!InternetSetOption(request.get(), + INTERNET_OPTION_RECEIVE_TIMEOUT, + timeout, + sizeof(*timeout))) { + fwprintf(stderr, L"Could not unset receive timeout, continuing...\n"); + } + } + + if (!HttpSendRequest(request.get(), NULL, 0, + const_cast(request_body.data()), + static_cast(request_body.size()))) { + return false; + } + + // The server indicates a successful upload with HTTP status 200. + wchar_t http_status[4]; + DWORD http_status_size = sizeof(http_status); + if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE, + static_cast(&http_status), &http_status_size, + 0)) { + return false; + } + + int http_response = wcstol(http_status, NULL, 10); + if (response_code) { + *response_code = http_response; + } + + bool result = (http_response == 200); + + if (result) { + result = ReadResponse(request.get(), response_body); + } + + return result; +} + +// static +bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) { + bool has_content_length_header = false; + wchar_t content_length[32]; + DWORD content_length_size = sizeof(content_length); + DWORD claimed_size = 0; + string response_body; + + if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH, + static_cast(&content_length), + &content_length_size, 0)) { + has_content_length_header = true; + claimed_size = wcstol(content_length, NULL, 10); + response_body.reserve(claimed_size); + } + + + DWORD bytes_available; + DWORD total_read = 0; + BOOL return_code; + + while (((return_code = InternetQueryDataAvailable(request, &bytes_available, + 0, 0)) != 0) && bytes_available > 0) { + vector response_buffer(bytes_available); + DWORD size_read; + + return_code = InternetReadFile(request, + &response_buffer[0], + bytes_available, &size_read); + + if (return_code && size_read > 0) { + total_read += size_read; + response_body.append(&response_buffer[0], size_read); + } else { + break; + } + } + + bool succeeded = return_code && (!has_content_length_header || + (total_read == claimed_size)); + if (succeeded && response) { + *response = UTF8ToWide(response_body); + } + + return succeeded; +} + +// static +wstring HTTPUpload::GenerateMultipartBoundary() { + // The boundary has 27 '-' characters followed by 16 hex digits + static const wchar_t kBoundaryPrefix[] = L"---------------------------"; + static const int kBoundaryLength = 27 + 16 + 1; + + // Generate some random numbers to fill out the boundary + int r0 = rand(); + int r1 = rand(); + + wchar_t temp[kBoundaryLength]; + swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1); + + // remove when VC++7.1 is no longer supported + temp[kBoundaryLength - 1] = L'\0'; + + return wstring(temp); +} + +// static +wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) { + wstring header = L"Content-Type: multipart/form-data; boundary="; + header += boundary; + return header; +} + +// static +bool HTTPUpload::GenerateRequestBody(const map ¶meters, + const wstring &upload_file, + const wstring &file_part_name, + const wstring &boundary, + string *request_body) { + vector contents; + if (!GetFileContents(upload_file, &contents)) { + return false; + } + + string boundary_str = WideToUTF8(boundary); + if (boundary_str.empty()) { + return false; + } + + request_body->clear(); + + // Append each of the parameter pairs as a form-data part + for (map::const_iterator pos = parameters.begin(); + pos != parameters.end(); ++pos) { + request_body->append("--" + boundary_str + "\r\n"); + request_body->append("Content-Disposition: form-data; name=\"" + + WideToUTF8(pos->first) + "\"\r\n\r\n" + + WideToUTF8(pos->second) + "\r\n"); + } + + // Now append the upload file as a binary (octet-stream) part + string filename_utf8 = WideToUTF8(upload_file); + if (filename_utf8.empty()) { + return false; + } + + string file_part_name_utf8 = WideToUTF8(file_part_name); + if (file_part_name_utf8.empty()) { + return false; + } + + request_body->append("--" + boundary_str + "\r\n"); + request_body->append("Content-Disposition: form-data; " + "name=\"" + file_part_name_utf8 + "\"; " + "filename=\"" + filename_utf8 + "\"\r\n"); + request_body->append("Content-Type: application/octet-stream\r\n"); + request_body->append("\r\n"); + + if (!contents.empty()) { + request_body->append(&(contents[0]), contents.size()); + } + request_body->append("\r\n"); + request_body->append("--" + boundary_str + "--\r\n"); + return true; +} + +// static +bool HTTPUpload::GetFileContents(const wstring &filename, + vector *contents) { + bool rv = false; + // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a + // wchar_t* filename, so use _wfopen directly in that case. For VC8 and + // later, _wfopen has been deprecated in favor of _wfopen_s, which does + // not exist in earlier versions, so let the ifstream open the file itself. +#if _MSC_VER >= 1400 // MSVC 2005/8 + ifstream file; + file.open(filename.c_str(), ios::binary); +#else // _MSC_VER >= 1400 + ifstream file(_wfopen(filename.c_str(), L"rb")); +#endif // _MSC_VER >= 1400 + if (file.is_open()) { + file.seekg(0, ios::end); + std::streamoff length = file.tellg(); + // Check for loss of data when converting lenght from std::streamoff into + // std::vector::size_type + std::vector::size_type vector_size = + static_cast::size_type>(length); + if (static_cast(vector_size) == length) { + contents->resize(vector_size); + if (length != 0) { + file.seekg(0, ios::beg); + file.read(&((*contents)[0]), length); + } + rv = true; + } + file.close(); + } + return rv; +} + +// static +wstring HTTPUpload::UTF8ToWide(const string &utf8) { + if (utf8.length() == 0) { + return wstring(); + } + + // compute the length of the buffer we'll need + int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0); + + if (charcount == 0) { + return wstring(); + } + + // convert + wchar_t* buf = new wchar_t[charcount]; + MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount); + wstring result(buf); + delete[] buf; + return result; +} + +// static +string HTTPUpload::WideToUTF8(const wstring &wide) { + if (wide.length() == 0) { + return string(); + } + + // compute the length of the buffer we'll need + int charcount = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, + NULL, 0, NULL, NULL); + if (charcount == 0) { + return string(); + } + + // convert + char *buf = new char[charcount]; + WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, buf, charcount, + NULL, NULL); + + string result(buf); + delete[] buf; + return result; +} + +// static +bool HTTPUpload::CheckParameters(const map ¶meters) { + for (map::const_iterator pos = parameters.begin(); + pos != parameters.end(); ++pos) { + const wstring &str = pos->first; + if (str.size() == 0) { + return false; // disallow empty parameter names + } + for (unsigned int i = 0; i < str.size(); ++i) { + wchar_t c = str[i]; + if (c < 32 || c == '"' || c > 127) { + return false; + } + } + } + return true; +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/http_upload.h b/breakpad/common/windows/http_upload.h new file mode 100644 index 0000000000..8a17aab170 --- /dev/null +++ b/breakpad/common/windows/http_upload.h @@ -0,0 +1,126 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST +// request using wininet. It currently supports requests that contain +// a set of string parameters (key/value pairs), and a file to upload. + +#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H__ +#define COMMON_WINDOWS_HTTP_UPLOAD_H__ + +#pragma warning( push ) +// Disable exception handler warnings. +#pragma warning( disable : 4530 ) + +#include +#include + +#include +#include +#include + +namespace google_breakpad { + +using std::string; +using std::wstring; +using std::map; +using std::vector; + +class HTTPUpload { + public: + // Sends the given set of parameters, along with the contents of + // upload_file, as a multipart POST request to the given URL. + // file_part_name contains the name of the file part of the request + // (i.e. it corresponds to the name= attribute on an . + // Parameter names must contain only printable ASCII characters, + // and may not contain a quote (") character. + // Only HTTP(S) URLs are currently supported. Returns true on success. + // If the request is successful and response_body is non-NULL, + // the response body will be returned in response_body. + // If response_code is non-NULL, it will be set to the HTTP response code + // received (or 0 if the request failed before getting an HTTP response). + static bool SendRequest(const wstring &url, + const map ¶meters, + const wstring &upload_file, + const wstring &file_part_name, + int *timeout, + wstring *response_body, + int *response_code); + + private: + class AutoInternetHandle; + + // Retrieves the HTTP response. If NULL is passed in for response, + // this merely checks (via the return value) that we were successfully + // able to retrieve exactly as many bytes of content in the response as + // were specified in the Content-Length header. + static bool HTTPUpload::ReadResponse(HINTERNET request, wstring* response); + + // Generates a new multipart boundary for a POST request + static wstring GenerateMultipartBoundary(); + + // Generates a HTTP request header for a multipart form submit. + static wstring GenerateRequestHeader(const wstring &boundary); + + // Given a set of parameters, an upload filename, and a file part name, + // generates a multipart request body string with these parameters + // and minidump contents. Returns true on success. + static bool GenerateRequestBody(const map ¶meters, + const wstring &upload_file, + const wstring &file_part_name, + const wstring &boundary, + string *request_body); + + // Fills the supplied vector with the contents of filename. + static bool GetFileContents(const wstring &filename, vector *contents); + + // Converts a UTF8 string to UTF16. + static wstring UTF8ToWide(const string &utf8); + + // Converts a UTF16 string to UTF8. + static string WideToUTF8(const wstring &wide); + + // Checks that the given list of parameters has only printable + // ASCII characters in the parameter name, and does not contain + // any quote (") characters. Returns true if so. + static bool CheckParameters(const map ¶meters); + + // No instances of this class should be created. + // Disallow all constructors, destructors, and operator=. + HTTPUpload(); + explicit HTTPUpload(const HTTPUpload &); + void operator=(const HTTPUpload &); + ~HTTPUpload(); +}; + +} // namespace google_breakpad + +#pragma warning( pop ) + +#endif // COMMON_WINDOWS_HTTP_UPLOAD_H__ diff --git a/breakpad/common/windows/omap.cc b/breakpad/common/windows/omap.cc new file mode 100644 index 0000000000..39e4722b3d --- /dev/null +++ b/breakpad/common/windows/omap.cc @@ -0,0 +1,694 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This contains a suite of tools for transforming symbol information when +// when that information has been extracted from a PDB containing OMAP +// information. + +// OMAP information is a lightweight description of a mapping between two +// address spaces. It consists of two streams, each of them a vector 2-tuples. +// The OMAPTO stream contains tuples of the form +// +// (RVA in transformed image, RVA in original image) +// +// while the OMAPFROM stream contains tuples of the form +// +// (RVA in original image, RVA in transformed image) +// +// The entries in each vector are sorted by the first value of the tuple, and +// the lengths associated with a mapping are implicit as the distance between +// two successive addresses in the vector. + +// Consider a trivial 10-byte function described by the following symbol: +// +// Function: RVA 0x00001000, length 10, "foo" +// +// Now consider the same function, but with 5-bytes of instrumentation injected +// at offset 5. The OMAP streams describing this would look like: +// +// OMAPTO : [ [0x00001000, 0x00001000], +// [0x00001005, 0xFFFFFFFF], +// [0x0000100a, 0x00001005] ] +// OMAPFROM: [ [0x00001000, 0x00001000], +// [0x00001005, 0x0000100a] ] +// +// In this case the injected code has been marked as not originating in the +// source image, and thus it will have no symbol information at all. However, +// the injected code may also be associated with an original address range; +// for example, when prepending instrumentation to a basic block the +// instrumentation can be labelled as originating from the same source BB such +// that symbol resolution will still find the appropriate source code line +// number. In this case the OMAP stream would look like: +// +// OMAPTO : [ [0x00001000, 0x00001000], +// [0x00001005, 0x00001005], +// [0x0000100a, 0x00001005] ] +// OMAPFROM: [ [0x00001000, 0x00001000], +// [0x00001005, 0x0000100a] ] +// +// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the +// instrumented image. It would first run this through the OMAPTO table and +// translate that address to 0x00001005. It would then lookup the symbol +// at that address and return the symbol for the function "foo". This is the +// correct result. +// +// However, if we query DIA for the length and address of the symbol it will +// tell us that it has length 10 and is at RVA 0x00001000. The location is +// correct, but the length doesn't take into account the 5-bytes of injected +// code. Symbol resolution works (starting from an instrumented address, +// mapping to an original address, and looking up a symbol), but the symbol +// metadata is incorrect. +// +// If we dump the symbols using DIA they will have their addresses +// appropriately transformed and reflect positions in the instrumented image. +// However, if we try to do a lookup using those symbols resolution can fail. +// For example, the address 0x0000100a will not map to the symbol for "foo", +// because DIA tells us it is at location 0x00001000 (correct) with length +// 10 (incorrect). The problem is one of order of operations: in this case +// we're attempting symbol resolution by looking up an instrumented address +// in the table of translated symbols. +// +// One way to handle this is to dump the OMAP information as part of the +// breakpad symbols. This requires the rest of the toolchain to be aware of +// OMAP information and to use it when present prior to performing lookup. The +// other option is to properly transform the symbols (updating length as well as +// position) so that resolution will work as expected for translated addresses. +// This is transparent to the rest of the toolchain. + +#include "common/windows/omap.h" + +#include + +#include +#include +#include + +#include "common/windows/dia_util.h" + +namespace google_breakpad { + +namespace { + +static const wchar_t kOmapToDebugStreamName[] = L"OMAPTO"; +static const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM"; + +// Dependending on where this is used in breakpad we sometimes get min/max from +// windef, and other times from algorithm. To get around this we simply +// define our own min/max functions. +template +const T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; } +template +const T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; } + +// It makes things more readable to have two different OMAP types. We cast +// normal OMAPs into these. They must be the same size as the OMAP structure +// for this to work, hence the static asserts. +struct OmapOrigToTran { + DWORD rva_original; + DWORD rva_transformed; +}; +struct OmapTranToOrig { + DWORD rva_transformed; + DWORD rva_original; +}; +static_assert(sizeof(OmapOrigToTran) == sizeof(OMAP), + "OmapOrigToTran must have same size as OMAP."); +static_assert(sizeof(OmapTranToOrig) == sizeof(OMAP), + "OmapTranToOrig must have same size as OMAP."); +typedef std::vector OmapFromTable; +typedef std::vector OmapToTable; + +// Used for sorting and searching through a Mapping. +bool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) { + if (lhs.rva_original < rhs.rva_original) + return true; + if (lhs.rva_original > rhs.rva_original) + return false; + return lhs.length < rhs.length; +} +bool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) { + if (lhs.rva_transformed < rhs.rva_transformed) + return true; + if (lhs.rva_transformed > rhs.rva_transformed) + return false; + return lhs.length < rhs.length; +} + +// Used for searching through the EndpointIndexMap. +bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) { + return ei1.endpoint < ei2.endpoint; +} + +// Finds the debug stream with the given |name| in the given |session|, and +// populates |table| with its contents. Casts the data directly into OMAP +// structs. +bool FindAndLoadOmapTable(const wchar_t* name, + IDiaSession* session, + OmapTable* table) { + assert(name != NULL); + assert(session != NULL); + assert(table != NULL); + + CComPtr stream; + if (!FindDebugStream(name, session, &stream)) + return false; + assert(stream.p != NULL); + + LONG count = 0; + if (FAILED(stream->get_Count(&count))) { + fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream " + "\"%ws\"\n", name); + return false; + } + + // Get the length of the stream in bytes. + DWORD bytes_read = 0; + ULONG count_read = 0; + if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) { + fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " + "length of stream \"%ws\"\n", name); + return false; + } + + // Ensure it's consistent with the OMAP data type. + DWORD bytes_expected = count * sizeof(OmapTable::value_type); + if (count * sizeof(OmapTable::value_type) != bytes_read) { + fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name); + return false; + } + + // Read the table. + table->resize(count); + bytes_read = 0; + count_read = 0; + if (FAILED(stream->Next(count, bytes_expected, &bytes_read, + reinterpret_cast(&table->at(0)), + &count_read))) { + fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " + "data from stream \"%ws\"\n"); + return false; + } + + return true; +} + +// This determines the original image length by looking through the segment +// table. +bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { + assert(session != NULL); + assert(image_length != NULL); + + CComPtr enum_segments; + if (!FindTable(session, &enum_segments)) + return false; + assert(enum_segments.p != NULL); + + DWORD temp_image_length = 0; + CComPtr segment; + ULONG fetched = 0; + while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) && + fetched == 1) { + assert(segment.p != NULL); + + DWORD rva = 0; + DWORD length = 0; + DWORD frame = 0; + if (FAILED(segment->get_relativeVirtualAddress(&rva)) || + FAILED(segment->get_length(&length)) || + FAILED(segment->get_frame(&frame))) { + fprintf(stderr, "Failed to get basic properties for IDiaSegment\n"); + return false; + } + + if (frame > 0) { + DWORD segment_end = rva + length; + if (segment_end > temp_image_length) + temp_image_length = segment_end; + } + segment.Release(); + } + + *image_length = temp_image_length; + return true; +} + +// Detects regions of the original image that have been removed in the +// transformed image, and sets the 'removed' property on all mapped ranges +// immediately preceding a gap. The mapped ranges must be sorted by +// 'rva_original'. +void FillInRemovedLengths(Mapping* mapping) { + assert(mapping != NULL); + + // Find and fill gaps. We do this with two sweeps. We first sweep forward + // looking for gaps. When we identify a gap we then sweep forward with a + // second scan and set the 'removed' property for any intervals that + // immediately precede the gap. + // + // Gaps are typically between two successive intervals, but not always: + // + // Range 1: --------------- + // Range 2: ------- + // Range 3: ------------- + // Gap : ****** + // + // In the above example the gap is between range 1 and range 3. A forward + // sweep finds the gap, and a second forward sweep identifies that range 1 + // immediately precedes the gap and sets its 'removed' property. + + size_t fill = 0; + DWORD rva_front = 0; + for (size_t find = 0; find < mapping->size(); ++find) { +#ifndef NDEBUG + // We expect the mapped ranges to be sorted by 'rva_original'. + if (find > 0) { + assert(mapping->at(find - 1).rva_original <= + mapping->at(find).rva_original); + } +#endif + + if (rva_front < mapping->at(find).rva_original) { + // We've found a gap. Fill it in by setting the 'removed' property for + // any affected intervals. + DWORD removed = mapping->at(find).rva_original - rva_front; + for (; fill < find; ++fill) { + if (mapping->at(fill).rva_original + mapping->at(fill).length != + rva_front) { + continue; + } + + // This interval ends right where the gap starts. It needs to have its + // 'removed' information filled in. + mapping->at(fill).removed = removed; + } + } + + // Advance the front that indicates the covered portion of the image. + rva_front = mapping->at(find).rva_original + mapping->at(find).length; + } +} + +// Builds a unified view of the mapping between the original and transformed +// image space by merging OMAPTO and OMAPFROM data. +void BuildMapping(const OmapData& omap_data, Mapping* mapping) { + assert(mapping != NULL); + + mapping->clear(); + + if (omap_data.omap_from.empty() || omap_data.omap_to.empty()) + return; + + // The names 'omap_to' and 'omap_from' are awfully confusing, so we make + // ourselves more explicit here. This cast is only safe because the underlying + // types have the exact same size. + const OmapToTable& tran2orig = + reinterpret_cast(omap_data.omap_to); + const OmapFromTable& orig2tran = reinterpret_cast( + omap_data.omap_from); + + // Handle the range of data at the beginning of the image. This is not usually + // specified by the OMAP data. + if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) { + DWORD header_transformed = tran2orig[0].rva_transformed; + DWORD header_original = orig2tran[0].rva_original; + DWORD header = Min(header_transformed, header_original); + + MappedRange mr = {}; + mr.length = header; + mr.injected = header_transformed - header; + mr.removed = header_original - header; + mapping->push_back(mr); + } + + // Convert the implied lengths to explicit lengths, and infer which content + // has been injected into the transformed image. Injected content is inferred + // as regions of the transformed address space that does not map back to + // known valid content in the original image. + for (size_t i = 0; i < tran2orig.size(); ++i) { + const OmapTranToOrig& o1 = tran2orig[i]; + + // This maps to content that is outside the original image, thus it + // describes injected content. We can skip this entry. + if (o1.rva_original >= omap_data.length_original) + continue; + + // Calculate the length of the current OMAP entry. This is implicit as the + // distance between successive |rva| values, capped at the end of the + // original image. + DWORD length = 0; + if (i + 1 < tran2orig.size()) { + const OmapTranToOrig& o2 = tran2orig[i + 1]; + + // We expect the table to be sorted by rva_transformed. + assert(o1.rva_transformed <= o2.rva_transformed); + + length = o2.rva_transformed - o1.rva_transformed; + if (o1.rva_original + length > omap_data.length_original) { + length = omap_data.length_original - o1.rva_original; + } + } else { + length = omap_data.length_original - o1.rva_original; + } + + // Zero-length entries don't describe anything and can be ignored. + if (length == 0) + continue; + + // Any gaps in the transformed address-space are due to injected content. + if (!mapping->empty()) { + MappedRange& prev_mr = mapping->back(); + prev_mr.injected += o1.rva_transformed - + (prev_mr.rva_transformed + prev_mr.length); + } + + MappedRange mr = {}; + mr.rva_original = o1.rva_original; + mr.rva_transformed = o1.rva_transformed; + mr.length = length; + mapping->push_back(mr); + } + + // Sort based on the original image addresses. + std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess); + + // Fill in the 'removed' lengths by looking for gaps in the coverage of the + // original address space. + FillInRemovedLengths(mapping); + + return; +} + +void BuildEndpointIndexMap(ImageMap* image_map) { + assert(image_map != NULL); + + if (image_map->mapping.size() == 0) + return; + + const Mapping& mapping = image_map->mapping; + EndpointIndexMap& eim = image_map->endpoint_index_map; + + // Get the unique set of interval endpoints. + std::set endpoints; + for (size_t i = 0; i < mapping.size(); ++i) { + endpoints.insert(mapping[i].rva_original); + endpoints.insert(mapping[i].rva_original + + mapping[i].length + + mapping[i].removed); + } + + // Use the endpoints to initialize the secondary search structure for the + // mapping. + eim.resize(endpoints.size()); + std::set::const_iterator it = endpoints.begin(); + for (size_t i = 0; it != endpoints.end(); ++it, ++i) { + eim[i].endpoint = *it; + eim[i].index = mapping.size(); + } + + // For each endpoint we want the smallest index of any interval containing + // it. We iterate over the intervals and update the indices associated with + // each interval endpoint contained in the current interval. In the general + // case of an arbitrary set of intervals this is O(n^2), but the structure of + // OMAP data makes this O(n). + for (size_t i = 0; i < mapping.size(); ++i) { + EndpointIndex ei1 = { mapping[i].rva_original, 0 }; + EndpointIndexMap::iterator it1 = std::lower_bound( + eim.begin(), eim.end(), ei1, EndpointIndexLess); + + EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length + + mapping[i].removed, 0 }; + EndpointIndexMap::iterator it2 = std::lower_bound( + eim.begin(), eim.end(), ei2, EndpointIndexLess); + + for (; it1 != it2; ++it1) + it1->index = Min(i, it1->index); + } +} + +// Clips the given mapped range. +void ClipMappedRangeOriginal(const AddressRange& clip_range, + MappedRange* mapped_range) { + assert(mapped_range != NULL); + + // The clipping range is entirely outside of the mapped range. + if (clip_range.end() <= mapped_range->rva_original || + mapped_range->rva_original + mapped_range->length + + mapped_range->removed <= clip_range.rva) { + mapped_range->length = 0; + mapped_range->injected = 0; + mapped_range->removed = 0; + return; + } + + // Clip the left side. + if (mapped_range->rva_original < clip_range.rva) { + DWORD clip_left = clip_range.rva - mapped_range->rva_original; + mapped_range->rva_original += clip_left; + mapped_range->rva_transformed += clip_left; + + if (clip_left > mapped_range->length) { + // The left clipping boundary entirely erases the content section of the + // range. + DWORD trim = clip_left - mapped_range->length; + mapped_range->length = 0; + mapped_range->injected -= Min(trim, mapped_range->injected); + // We know that trim <= mapped_range->remove. + mapped_range->removed -= trim; + } else { + // The left clipping boundary removes some, but not all, of the content. + // As such it leaves the removed/injected component intact. + mapped_range->length -= clip_left; + } + } + + // Clip the right side. + DWORD end_original = mapped_range->rva_original + mapped_range->length; + if (clip_range.end() < end_original) { + // The right clipping boundary lands in the 'content' section of the range, + // entirely clearing the injected/removed portion. + DWORD clip_right = end_original - clip_range.end(); + mapped_range->length -= clip_right; + mapped_range->injected = 0; + mapped_range->removed = 0; + return; + } else { + // The right clipping boundary is outside of the content, but may affect + // the removed/injected portion of the range. + DWORD end_removed = end_original + mapped_range->removed; + if (clip_range.end() < end_removed) + mapped_range->removed = clip_range.end() - end_original; + + DWORD end_injected = end_original + mapped_range->injected; + if (clip_range.end() < end_injected) + mapped_range->injected = clip_range.end() - end_original; + } + + return; +} + +} // namespace + +int AddressRange::Compare(const AddressRange& rhs) const { + if (end() <= rhs.rva) + return -1; + if (rhs.end() <= rva) + return 1; + return 0; +} + +bool GetOmapDataAndDisableTranslation(IDiaSession* session, + OmapData* omap_data) { + assert(session != NULL); + assert(omap_data != NULL); + + CComPtr address_map; + if (FAILED(session->QueryInterface(&address_map))) { + fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n"); + return false; + } + assert(address_map.p != NULL); + + BOOL omap_enabled = FALSE; + if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) { + fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n"); + return false; + } + + if (!omap_enabled) { + // We indicate the non-presence of OMAP data by returning empty tables. + omap_data->omap_from.clear(); + omap_data->omap_to.clear(); + omap_data->length_original = 0; + return true; + } + + // OMAP data is present. Disable translation. + if (FAILED(address_map->put_addressMapEnabled(FALSE))) { + fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n"); + return false; + } + + // Read the OMAP streams. + if (!FindAndLoadOmapTable(kOmapFromDebugStreamName, + session, + &omap_data->omap_from)) { + return false; + } + if (!FindAndLoadOmapTable(kOmapToDebugStreamName, + session, + &omap_data->omap_to)) { + return false; + } + + // Get the lengths of the address spaces. + if (!GetOriginalImageLength(session, &omap_data->length_original)) + return false; + + return true; +} + +void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { + assert(image_map != NULL); + + BuildMapping(omap_data, &image_map->mapping); + BuildEndpointIndexMap(image_map); +} + +void MapAddressRange(const ImageMap& image_map, + const AddressRange& original_range, + AddressRangeVector* mapped_ranges) { + assert(mapped_ranges != NULL); + + const Mapping& map = image_map.mapping; + + // Handle the trivial case of an empty image_map. This means that there is + // no transformation to be applied, and we can simply return the original + // range. + if (map.empty()) { + mapped_ranges->push_back(original_range); + return; + } + + // If we get a query of length 0 we need to handle it by using a non-zero + // query length. + AddressRange query_range(original_range); + if (query_range.length == 0) + query_range.length = 1; + + // Find the range of intervals that can potentially intersect our query range. + size_t imin = 0; + size_t imax = 0; + { + // The index of the earliest possible range that can affect is us done by + // searching through the secondary indexing structure. + const EndpointIndexMap& eim = image_map.endpoint_index_map; + EndpointIndex q1 = { query_range.rva, 0 }; + EndpointIndexMap::const_iterator it1 = std::lower_bound( + eim.begin(), eim.end(), q1, EndpointIndexLess); + if (it1 == eim.end()) { + imin = map.size(); + } else { + // Backup to find the interval that contains our query point. + if (it1 != eim.begin() && query_range.rva < it1->endpoint) + --it1; + imin = it1->index; + } + + // The first range that can't possibly intersect us is found by searching + // through the image map directly as it is already sorted by interval start + // point. + MappedRange q2 = { query_range.end(), 0 }; + Mapping::const_iterator it2 = std::lower_bound( + map.begin(), map.end(), q2, MappedRangeOriginalLess); + imax = it2 - map.begin(); + } + + // Find all intervals that intersect the query range. + Mapping temp_map; + for (size_t i = imin; i < imax; ++i) { + MappedRange mr = map[i]; + ClipMappedRangeOriginal(query_range, &mr); + if (mr.length + mr.injected > 0) + temp_map.push_back(mr); + } + + // If there are no intersecting ranges then the query range has been removed + // from the image in question. + if (temp_map.empty()) + return; + + // Sort based on transformed addresses. + std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess); + + // Zero-length queries can't actually be merged. We simply output the set of + // unique RVAs that correspond to the query RVA. + if (original_range.length == 0) { + mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0)); + for (size_t i = 1; i < temp_map.size(); ++i) { + if (temp_map[i].rva_transformed > mapped_ranges->back().rva) + mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0)); + } + return; + } + + // Merge any ranges that are consecutive in the mapped image. We merge over + // injected content if it makes ranges contiguous, but we ignore any injected + // content at the tail end of a range. This allows us to detect symbols that + // have been lengthened by injecting content in the middle. However, it + // misses the case where content has been injected at the head or the tail. + // The problem is that it doesn't know whether to attribute it to the + // preceding or following symbol. It is up to the author of the transform to + // output explicit OMAP info in these cases to ensure full coverage of the + // transformed address space. + DWORD rva_begin = temp_map[0].rva_transformed; + DWORD rva_cur_content = rva_begin + temp_map[0].length; + DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected; + for (size_t i = 1; i < temp_map.size(); ++i) { + if (rva_cur_injected < temp_map[i].rva_transformed) { + // This marks the end of a continuous range in the image. Output the + // current range and start a new one. + if (rva_begin < rva_cur_content) { + mapped_ranges->push_back( + AddressRange(rva_begin, rva_cur_content - rva_begin)); + } + rva_begin = temp_map[i].rva_transformed; + } + + rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length; + rva_cur_injected = rva_cur_content + temp_map[i].injected; + } + + // Output the range in progress. + if (rva_begin < rva_cur_content) { + mapped_ranges->push_back( + AddressRange(rva_begin, rva_cur_content - rva_begin)); + } + + return; +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/omap.h b/breakpad/common/windows/omap.h new file mode 100644 index 0000000000..1e023d1178 --- /dev/null +++ b/breakpad/common/windows/omap.h @@ -0,0 +1,72 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Provides an API for mapping symbols through OMAP information, if a PDB file +// is augmented with it. This allows breakpad to work with addresses in +// transformed images by transforming the symbols themselves, rather than +// transforming addresses prior to querying symbols (the way it is typically +// done by Windows-native tools, including the DIA). + +#ifndef COMMON_WINDOWS_OMAP_H__ +#define COMMON_WINDOWS_OMAP_H__ + +#include "common/windows/omap_internal.h" + +namespace google_breakpad { + +// If the given session contains OMAP data this extracts it, populating +// |omap_data|, and then disabling automatic translation for the session. +// OMAP data is present in the PDB if |omap_data| is not empty. This returns +// true on success, false otherwise. +bool GetOmapDataAndDisableTranslation(IDiaSession* dia_session, + OmapData* omap_data); + +// Given raw OMAP data builds an ImageMap. This can be used to query individual +// image ranges using MapAddressRange. +// |omap_data|| is the OMAP data extracted from the PDB. +// |image_map| will be populated with a description of the image mapping. If +// |omap_data| is empty then this will also be empty. +void BuildImageMap(const OmapData& omap_data, ImageMap* image_map); + +// Given an address range in the original image space determines how exactly it +// has been tranformed. +// |omap_data| is the OMAP data extracted from the PDB, which must not be +// empty. +// |original_range| is the address range in the original image being queried. +// |mapped_ranges| will be populated with a full description of the mapping. +// They may be disjoint in the transformed image so a vector is needed to +// fully represent the mapping. This will be appended to if it is not +// empty. If |omap_data| is empty then |mapped_ranges| will simply be +// populated with a copy of |original_range| (the identity transform). +void MapAddressRange(const ImageMap& image_map, + const AddressRange& original_range, + AddressRangeVector* mapped_ranges); + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_OMAP_H__ diff --git a/breakpad/common/windows/omap_internal.h b/breakpad/common/windows/omap_internal.h new file mode 100644 index 0000000000..6c37d7f874 --- /dev/null +++ b/breakpad/common/windows/omap_internal.h @@ -0,0 +1,137 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Declares internal implementation details for functionality in omap.h and +// omap.cc. + +#ifndef COMMON_WINDOWS_OMAP_INTERNAL_H__ +#define COMMON_WINDOWS_OMAP_INTERNAL_H__ + +#include +#include + +#include + +namespace google_breakpad { + +// The OMAP struct is defined by debughlp.h, which doesn't play nicely with +// imagehlp.h. We simply redefine it. +struct OMAP { + DWORD rva; + DWORD rvaTo; +}; +static_assert(sizeof(OMAP) == 8, "Wrong size for OMAP structure."); +typedef std::vector OmapTable; + +// This contains the OMAP data extracted from an image. +struct OmapData { + // The table of OMAP entries describing the transformation from the + // original image to the transformed image. + OmapTable omap_from; + // The table of OMAP entries describing the transformation from the + // instrumented image to the original image. + OmapTable omap_to; + // The length of the original untransformed image. + DWORD length_original; + + OmapData() : length_original(0) { } +}; + +// This represents a range of addresses in an image. +struct AddressRange { + DWORD rva; + DWORD length; + + AddressRange() : rva(0), length(0) { } + AddressRange(DWORD rva, DWORD length) : rva(rva), length(length) { } + + // Returns the end address of this range. + DWORD end() const { return rva + length; } + + // Addreses only compare as less-than or greater-than if they are not + // overlapping. Otherwise, they compare equal. + int Compare(const AddressRange& rhs) const; + bool operator<(const AddressRange& rhs) const { return Compare(rhs) == -1; } + bool operator>(const AddressRange& rhs) const { return Compare(rhs) == 1; } + + // Equality operators compare exact values. + bool operator==(const AddressRange& rhs) const { + return rva == rhs.rva && length == rhs.length; + } + bool operator!=(const AddressRange& rhs) const { return !((*this) == rhs); } +}; + +typedef std::vector AddressRangeVector; + +// This represents an address range in an original image, and its corresponding +// range in the transformed image. +struct MappedRange { + // An address in the original image. + DWORD rva_original; + // The corresponding addresses in the transformed image. + DWORD rva_transformed; + // The length of the address range. + DWORD length; + // It is possible for code to be injected into a transformed image, for which + // there is no corresponding code in the original image. If this range of + // transformed image is immediately followed by such injected code we maintain + // a record of its length here. + DWORD injected; + // It is possible for code to be removed from the original image. This happens + // for things like padding between blocks. There is no actual content lost, + // but the spacing between items may be lost. This keeps track of any removed + // content immediately following the |original| range. + DWORD removed; +}; +// A vector of mapped ranges is used as a more useful representation of +// OMAP data. +typedef std::vector Mapping; + +// Used as a secondary search structure accompanying a Mapping. +struct EndpointIndex { + DWORD endpoint; + size_t index; +}; +typedef std::vector EndpointIndexMap; + +// An ImageMap is vector of mapped ranges, plus a secondary index into it for +// doing interval searches. (An interval tree would also work, but is overkill +// because we don't need insertion and deletion.) +struct ImageMap { + // This is a description of the mapping between original and transformed + // image, sorted by addresses in the original image. + Mapping mapping; + // For all interval endpoints in |mapping| this stores the minimum index of + // an interval in |mapping| that contains the endpoint. Useful for doing + // interval intersection queries. + EndpointIndexMap endpoint_index_map; +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_OMAP_INTERNAL_H__ diff --git a/breakpad/common/windows/omap_unittest.cc b/breakpad/common/windows/omap_unittest.cc new file mode 100644 index 0000000000..c1a2c512e1 --- /dev/null +++ b/breakpad/common/windows/omap_unittest.cc @@ -0,0 +1,330 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Unittests for OMAP related functions. + +#include "common/windows/omap.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace google_breakpad { + +// Equality operators for ContainerEq. These must be outside of the anonymous +// namespace in order for them to be found. +bool operator==(const MappedRange& mr1, const MappedRange& mr2) { + return mr1.rva_original == mr2.rva_original && + mr1.rva_transformed == mr2.rva_transformed && + mr1.length == mr2.length && + mr1.injected == mr2.injected && + mr1.removed == mr2.removed; +} +bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) { + return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index; +} + +// Pretty printers for more meaningful error messages. Also need to be outside +// the anonymous namespace. +std::ostream& operator<<(std::ostream& os, const MappedRange& mr) { + os << "MappedRange(rva_original=" << mr.rva_original + << ", rva_transformed=" << mr.rva_transformed + << ", length=" << mr.length + << ", injected=" << mr.injected + << ", removed=" << mr.removed << ")"; + return os; +} +std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) { + os << "EndpointIndex(endpoint=" << ei.endpoint + << ", index=" << ei.index << ")"; + return os; +} +std::ostream& operator<<(std::ostream& os, const AddressRange& ar) { + os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")"; + return os; +} + +namespace { + +OMAP CreateOmap(DWORD rva, DWORD rvaTo) { + OMAP o = { rva, rvaTo }; + return o; +} + +MappedRange CreateMappedRange(DWORD rva_original, + DWORD rva_transformed, + DWORD length, + DWORD injected, + DWORD removed) { + MappedRange mr = { rva_original, rva_transformed, length, injected, removed }; + return mr; +} + +EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) { + EndpointIndex ei = { endpoint, index }; + return ei; +} + +// (C is removed) +// Original : A B C D E F G H +// Transformed: A B D F E * H1 G1 G2 H2 +// (* is injected, G is copied, H is split) +// A is implied. + +// Layout of the original image. +const AddressRange B(100, 15); +const AddressRange C(B.end(), 10); +const AddressRange D(C.end(), 25); +const AddressRange E(D.end(), 10); +const AddressRange F(E.end(), 40); +const AddressRange G(F.end(), 3); +const AddressRange H(G.end(), 7); + +// Layout of the transformed image. +const AddressRange Bt(100, 15); +const AddressRange Dt(Bt.end(), 20); // D is shortened. +const AddressRange Ft(Dt.end(), F.length); +const AddressRange Et(Ft.end(), E.length); +const AddressRange injected(Et.end(), 5); +const AddressRange H1t(injected.end(), 4); // H is split. +const AddressRange G1t(H1t.end(), G.length); // G is copied. +const AddressRange G2t(G1t.end(), G.length); // G is copied. +const AddressRange H2t(G2t.end(), 3); // H is split. + +class BuildImageMapTest : public testing::Test { + public: + static const DWORD kInvalidAddress = 0xFFFFFFFF; + + void InitOmapData() { + omap_data.length_original = H.end(); + + // Build the OMAPTO vector (from transformed to original). + omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva)); + omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva)); + omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva)); + omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva)); + omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress)); + omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva)); + omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva)); + omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva)); + omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length)); + omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress)); + + // Build the OMAPFROM vector (from original to transformed). + omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva)); + omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress)); + omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva)); + omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva)); + omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva)); + omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress)); + } + + OmapData omap_data; +}; + +} // namespace + +TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) { + ASSERT_EQ(0u, omap_data.omap_from.size()); + ASSERT_EQ(0u, omap_data.omap_to.size()); + ASSERT_EQ(0u, omap_data.length_original); + + ImageMap image_map; + BuildImageMap(omap_data, &image_map); + EXPECT_EQ(0u, image_map.mapping.size()); + EXPECT_EQ(0u, image_map.endpoint_index_map.size()); +} + +TEST_F(BuildImageMapTest, ImageMapIsCorrect) { + InitOmapData(); + ASSERT_LE(0u, omap_data.omap_from.size()); + ASSERT_LE(0u, omap_data.omap_to.size()); + ASSERT_LE(0u, omap_data.length_original); + + ImageMap image_map; + BuildImageMap(omap_data, &image_map); + EXPECT_LE(9u, image_map.mapping.size()); + EXPECT_LE(9u, image_map.endpoint_index_map.size()); + + Mapping mapping; + mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0)); + // C is removed, and it originally comes immediately after B. + mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length)); + // D is shortened by a length of 5. + mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5)); + // The injected content comes immediately after E in the transformed image. + mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length, + 0)); + mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0)); + // G is copied so creates two entries. + mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0)); + mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0)); + // H is split, so create two entries. + mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0)); + mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length, + 0, 0)); + EXPECT_THAT(mapping, + testing::ContainerEq(image_map.mapping)); + + EndpointIndexMap endpoint_index_map; + endpoint_index_map.push_back(CreateEndpointIndex(0, 0)); + endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1)); + endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2)); + endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3)); + endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4)); + // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7. + endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5)); + // H is split so we expect 2 endpoints to show up attributed to it. + endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7)); + endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8)); + endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9)); + EXPECT_THAT(endpoint_index_map, + testing::ContainerEq(image_map.endpoint_index_map)); +} + +namespace { + +class MapAddressRangeTest : public BuildImageMapTest { + public: + typedef BuildImageMapTest Super; + virtual void SetUp() { + Super::SetUp(); + InitOmapData(); + BuildImageMap(omap_data, &image_map); + } + + ImageMap image_map; + + private: + using BuildImageMapTest::InitOmapData; + using BuildImageMapTest::omap_data; +}; + +} // namespace + +TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) { + ImageMap im; + AddressRangeVector mapped_ranges; + AddressRange ar(0, 1024); + MapAddressRange(im, ar, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_EQ(ar, mapped_ranges[0]); +} + +TEST_F(MapAddressRangeTest, MapOutOfImage) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges); + EXPECT_EQ(0u, mapped_ranges.size()); +} + +TEST_F(MapAddressRangeTest, MapIdentity) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, B, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(B)); +} + +TEST_F(MapAddressRangeTest, MapReorderedContiguous) { + AddressRangeVector mapped_ranges; + + AddressRange DEF(D.rva, F.end() - D.rva); + MapAddressRange(image_map, DEF, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange DFEt(Dt.rva, Et.end() - Dt.rva); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt)); +} + +TEST_F(MapAddressRangeTest, MapEmptySingle) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0))); +} + +TEST_F(MapAddressRangeTest, MapEmptyCopied) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges); + EXPECT_EQ(2u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0), + AddressRange(G2t.rva, 0))); +} + +TEST_F(MapAddressRangeTest, MapCopiedContiguous) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, G, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre( + AddressRange(G1t.rva, G2t.end() - G1t.rva))); +} + +TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, H, &mapped_ranges); + EXPECT_EQ(2u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t)); +} + +TEST_F(MapAddressRangeTest, MapInjected) { + AddressRangeVector mapped_ranges; + + AddressRange EFGH(E.rva, H.end() - E.rva); + MapAddressRange(image_map, EFGH, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt)); +} + +TEST_F(MapAddressRangeTest, MapRemovedEntirely) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, C, &mapped_ranges); + EXPECT_EQ(0u, mapped_ranges.size()); +} + +TEST_F(MapAddressRangeTest, MapRemovedPartly) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, D, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt)); +} + +TEST_F(MapAddressRangeTest, MapFull) { + AddressRangeVector mapped_ranges; + + AddressRange AH(0, H.end()); + MapAddressRange(image_map, AH, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange AHt(0, H2t.end()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt)); +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/pdb_source_line_writer.cc b/breakpad/common/windows/pdb_source_line_writer.cc new file mode 100644 index 0000000000..dba2ea764a --- /dev/null +++ b/breakpad/common/windows/pdb_source_line_writer.cc @@ -0,0 +1,1066 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/windows/pdb_source_line_writer.h" + +#include +#include +#include +#include +#include +#include + +#include "common/windows/dia_util.h" +#include "common/windows/guid_string.h" +#include "common/windows/string_utils-inl.h" + +// This constant may be missing from DbgHelp.h. See the documentation for +// IDiaSymbol::get_undecoratedNameEx. +#ifndef UNDNAME_NO_ECSU +#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union. +#endif // UNDNAME_NO_ECSU + +namespace google_breakpad { + +namespace { + +using std::vector; + +// A helper class to scope a PLOADED_IMAGE. +class AutoImage { + public: + explicit AutoImage(PLOADED_IMAGE img) : img_(img) {} + ~AutoImage() { + if (img_) + ImageUnload(img_); + } + + operator PLOADED_IMAGE() { return img_; } + PLOADED_IMAGE operator->() { return img_; } + + private: + PLOADED_IMAGE img_; +}; + +} // namespace + +PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { +} + +PDBSourceLineWriter::~PDBSourceLineWriter() { +} + +bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { + Close(); + + if (FAILED(CoInitialize(NULL))) { + fprintf(stderr, "CoInitialize failed\n"); + return false; + } + + CComPtr data_source; + if (FAILED(data_source.CoCreateInstance(CLSID_DiaSource))) { + const int kGuidSize = 64; + wchar_t classid[kGuidSize] = {0}; + StringFromGUID2(CLSID_DiaSource, classid, kGuidSize); + // vc80 uses bce36434-2c24-499e-bf49-8bd99b0eeb68. + // vc90 uses 4C41678E-887B-4365-A09E-925D28DB33C2. + fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed " + "(msdia*.dll unregistered?)\n", classid); + return false; + } + + switch (format) { + case PDB_FILE: + if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { + fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str()); + return false; + } + break; + case EXE_FILE: + if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { + fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str()); + return false; + } + code_file_ = file; + break; + case ANY_FILE: + if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { + if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { + fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n", file.c_str()); + return false; + } + code_file_ = file; + } + break; + default: + fprintf(stderr, "Unknown file format\n"); + return false; + } + + if (FAILED(data_source->openSession(&session_))) { + fprintf(stderr, "openSession failed\n"); + } + + return true; +} + +bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { + // The line number format is: + // + CComPtr line; + ULONG count; + + while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { + DWORD rva; + if (FAILED(line->get_relativeVirtualAddress(&rva))) { + fprintf(stderr, "failed to get line rva\n"); + return false; + } + + DWORD length; + if (FAILED(line->get_length(&length))) { + fprintf(stderr, "failed to get line code length\n"); + return false; + } + + DWORD dia_source_id; + if (FAILED(line->get_sourceFileId(&dia_source_id))) { + fprintf(stderr, "failed to get line source file id\n"); + return false; + } + // duplicate file names are coalesced to share one ID + DWORD source_id = GetRealFileID(dia_source_id); + + DWORD line_num; + if (FAILED(line->get_lineNumber(&line_num))) { + fprintf(stderr, "failed to get line number\n"); + return false; + } + + AddressRangeVector ranges; + MapAddressRange(image_map_, AddressRange(rva, length), &ranges); + for (size_t i = 0; i < ranges.size(); ++i) { + fprintf(output_, "%x %x %d %d\n", ranges[i].rva, ranges[i].length, + line_num, source_id); + } + line.Release(); + } + return true; +} + +bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function, + IDiaSymbol *block) { + // The function format is: + // FUNC
+ DWORD rva; + if (FAILED(block->get_relativeVirtualAddress(&rva))) { + fprintf(stderr, "couldn't get rva\n"); + return false; + } + + ULONGLONG length; + if (FAILED(block->get_length(&length))) { + fprintf(stderr, "failed to get function length\n"); + return false; + } + + if (length == 0) { + // Silently ignore zero-length functions, which can infrequently pop up. + return true; + } + + CComBSTR name; + int stack_param_size; + if (!GetSymbolFunctionName(function, &name, &stack_param_size)) { + return false; + } + + // If the decorated name didn't give the parameter size, try to + // calculate it. + if (stack_param_size < 0) { + stack_param_size = GetFunctionStackParamSize(function); + } + + AddressRangeVector ranges; + MapAddressRange(image_map_, AddressRange(rva, static_cast(length)), + &ranges); + for (size_t i = 0; i < ranges.size(); ++i) { + fprintf(output_, "FUNC %x %x %x %ws\n", + ranges[i].rva, ranges[i].length, stack_param_size, name); + } + + CComPtr lines; + if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) { + return false; + } + + if (!PrintLines(lines)) { + return false; + } + return true; +} + +bool PDBSourceLineWriter::PrintSourceFiles() { + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + fprintf(stderr, "get_globalScope failed\n"); + return false; + } + + CComPtr compilands; + if (FAILED(global->findChildren(SymTagCompiland, NULL, + nsNone, &compilands))) { + fprintf(stderr, "findChildren failed\n"); + return false; + } + + CComPtr compiland; + ULONG count; + while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { + CComPtr source_files; + if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) { + return false; + } + CComPtr file; + while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) { + DWORD file_id; + if (FAILED(file->get_uniqueId(&file_id))) { + return false; + } + + CComBSTR file_name; + if (FAILED(file->get_fileName(&file_name))) { + return false; + } + + wstring file_name_string(file_name); + if (!FileIDIsCached(file_name_string)) { + // this is a new file name, cache it and output a FILE line. + CacheFileID(file_name_string, file_id); + fwprintf(output_, L"FILE %d %s\n", file_id, file_name); + } else { + // this file name has already been seen, just save this + // ID for later lookup. + StoreDuplicateFileID(file_name_string, file_id); + } + file.Release(); + } + compiland.Release(); + } + return true; +} + +bool PDBSourceLineWriter::PrintFunctions() { + CComPtr symbols; + if (FAILED(session_->getSymbolsByAddr(&symbols))) { + fprintf(stderr, "failed to get symbol enumerator\n"); + return false; + } + + CComPtr symbol; + if (FAILED(symbols->symbolByAddr(1, 0, &symbol))) { + fprintf(stderr, "failed to enumerate symbols\n"); + return false; + } + + DWORD rva_last = 0; + if (FAILED(symbol->get_relativeVirtualAddress(&rva_last))) { + fprintf(stderr, "failed to get symbol rva\n"); + return false; + } + + ULONG count; + do { + DWORD tag; + if (FAILED(symbol->get_symTag(&tag))) { + fprintf(stderr, "failed to get symbol tag\n"); + return false; + } + + // For a given function, DIA seems to give either a symbol with + // SymTagFunction or SymTagPublicSymbol, but not both. This means + // that PDBSourceLineWriter will output either a FUNC or PUBLIC line, + // but not both. + if (tag == SymTagFunction) { + if (!PrintFunction(symbol, symbol)) { + return false; + } + } else if (tag == SymTagPublicSymbol) { + if (!PrintCodePublicSymbol(symbol)) { + return false; + } + } + symbol.Release(); + } while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1); + + // When building with PGO, the compiler can split functions into + // "hot" and "cold" blocks, and move the "cold" blocks out to separate + // pages, so the function can be noncontiguous. To find these blocks, + // we have to iterate over all the compilands, and then find blocks + // that are children of them. We can then find the lexical parents + // of those blocks and print out an extra FUNC line for blocks + // that are not contained in their parent functions. + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + fprintf(stderr, "get_globalScope failed\n"); + return false; + } + + CComPtr compilands; + if (FAILED(global->findChildren(SymTagCompiland, NULL, + nsNone, &compilands))) { + fprintf(stderr, "findChildren failed on the global\n"); + return false; + } + + CComPtr compiland; + while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { + CComPtr blocks; + if (FAILED(compiland->findChildren(SymTagBlock, NULL, + nsNone, &blocks))) { + fprintf(stderr, "findChildren failed on a compiland\n"); + return false; + } + + CComPtr block; + while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) { + // find this block's lexical parent function + CComPtr parent; + DWORD tag; + if (SUCCEEDED(block->get_lexicalParent(&parent)) && + SUCCEEDED(parent->get_symTag(&tag)) && + tag == SymTagFunction) { + // now get the block's offset and the function's offset and size, + // and determine if the block is outside of the function + DWORD func_rva, block_rva; + ULONGLONG func_length; + if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) && + SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) && + SUCCEEDED(parent->get_length(&func_length))) { + if (block_rva < func_rva || block_rva > (func_rva + func_length)) { + if (!PrintFunction(parent, block)) { + return false; + } + } + } + } + parent.Release(); + block.Release(); + } + blocks.Release(); + compiland.Release(); + } + + return true; +} + +bool PDBSourceLineWriter::PrintFrameData() { + // It would be nice if it were possible to output frame data alongside the + // associated function, as is done with line numbers, but the DIA API + // doesn't make it possible to get the frame data in that way. + + CComPtr frame_data_enum; + if (!FindTable(session_, &frame_data_enum)) + return false; + + DWORD last_type = -1; + DWORD last_rva = -1; + DWORD last_code_size = 0; + DWORD last_prolog_size = -1; + + CComPtr frame_data; + ULONG count = 0; + while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) && + count == 1) { + DWORD type; + if (FAILED(frame_data->get_type(&type))) + return false; + + DWORD rva; + if (FAILED(frame_data->get_relativeVirtualAddress(&rva))) + return false; + + DWORD code_size; + if (FAILED(frame_data->get_lengthBlock(&code_size))) + return false; + + DWORD prolog_size; + if (FAILED(frame_data->get_lengthProlog(&prolog_size))) + return false; + + // parameter_size is the size of parameters passed on the stack. If any + // parameters are not passed on the stack (such as in registers), their + // sizes will not be included in parameter_size. + DWORD parameter_size; + if (FAILED(frame_data->get_lengthParams(¶meter_size))) + return false; + + DWORD saved_register_size; + if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size))) + return false; + + DWORD local_size; + if (FAILED(frame_data->get_lengthLocals(&local_size))) + return false; + + // get_maxStack can return S_FALSE, just use 0 in that case. + DWORD max_stack_size = 0; + if (FAILED(frame_data->get_maxStack(&max_stack_size))) + return false; + + // get_programString can return S_FALSE, indicating that there is no + // program string. In that case, check whether %ebp is used. + HRESULT program_string_result; + CComBSTR program_string; + if (FAILED(program_string_result = frame_data->get_program( + &program_string))) { + return false; + } + + // get_allocatesBasePointer can return S_FALSE, treat that as though + // %ebp is not used. + BOOL allocates_base_pointer = FALSE; + if (program_string_result != S_OK) { + if (FAILED(frame_data->get_allocatesBasePointer( + &allocates_base_pointer))) { + return false; + } + } + + // Only print out a line if type, rva, code_size, or prolog_size have + // changed from the last line. It is surprisingly common (especially in + // system library PDBs) for DIA to return a series of identical + // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86, + // this check reduces the size of the dumped symbol file by a third. + if (type != last_type || rva != last_rva || code_size != last_code_size || + prolog_size != last_prolog_size) { + // The prolog and the code portions of the frame have to be treated + // independently as they may have independently changed in size, or may + // even have been split. + // NOTE: If epilog size is ever non-zero, we have to do something + // similar with it. + + // Figure out where the prolog bytes have landed. + AddressRangeVector prolog_ranges; + if (prolog_size > 0) { + MapAddressRange(image_map_, AddressRange(rva, prolog_size), + &prolog_ranges); + } + + // And figure out where the code bytes have landed. + AddressRangeVector code_ranges; + MapAddressRange(image_map_, + AddressRange(rva + prolog_size, + code_size - prolog_size), + &code_ranges); + + struct FrameInfo { + DWORD rva; + DWORD code_size; + DWORD prolog_size; + }; + std::vector frame_infos; + + // Special case: The prolog and the code bytes remain contiguous. This is + // only done for compactness of the symbol file, and we could actually + // be outputting independent frame info for the prolog and code portions. + if (prolog_ranges.size() == 1 && code_ranges.size() == 1 && + prolog_ranges[0].end() == code_ranges[0].rva) { + FrameInfo fi = { prolog_ranges[0].rva, + prolog_ranges[0].length + code_ranges[0].length, + prolog_ranges[0].length }; + frame_infos.push_back(fi); + } else { + // Otherwise we output the prolog and code frame info independently. + for (size_t i = 0; i < prolog_ranges.size(); ++i) { + FrameInfo fi = { prolog_ranges[i].rva, + prolog_ranges[i].length, + prolog_ranges[i].length }; + frame_infos.push_back(fi); + } + for (size_t i = 0; i < code_ranges.size(); ++i) { + FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 }; + frame_infos.push_back(fi); + } + } + + for (size_t i = 0; i < frame_infos.size(); ++i) { + const FrameInfo& fi(frame_infos[i]); + fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ", + type, fi.rva, fi.code_size, fi.prolog_size, + 0 /* epilog_size */, parameter_size, saved_register_size, + local_size, max_stack_size, program_string_result == S_OK); + if (program_string_result == S_OK) { + fprintf(output_, "%ws\n", program_string); + } else { + fprintf(output_, "%d\n", allocates_base_pointer); + } + } + + last_type = type; + last_rva = rva; + last_code_size = code_size; + last_prolog_size = prolog_size; + } + + frame_data.Release(); + } + + return true; +} + +bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) { + BOOL is_code; + if (FAILED(symbol->get_code(&is_code))) { + return false; + } + if (!is_code) { + return true; + } + + DWORD rva; + if (FAILED(symbol->get_relativeVirtualAddress(&rva))) { + return false; + } + + CComBSTR name; + int stack_param_size; + if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) { + return false; + } + + AddressRangeVector ranges; + MapAddressRange(image_map_, AddressRange(rva, 1), &ranges); + for (size_t i = 0; i < ranges.size(); ++i) { + fprintf(output_, "PUBLIC %x %x %ws\n", ranges[i].rva, + stack_param_size > 0 ? stack_param_size : 0, name); + } + return true; +} + +bool PDBSourceLineWriter::PrintPDBInfo() { + PDBModuleInfo info; + if (!GetModuleInfo(&info)) { + return false; + } + + // Hard-code "windows" for the OS because that's the only thing that makes + // sense for PDB files. (This might not be strictly correct for Windows CE + // support, but we don't care about that at the moment.) + fprintf(output_, "MODULE windows %ws %ws %ws\n", + info.cpu.c_str(), info.debug_identifier.c_str(), + info.debug_file.c_str()); + + return true; +} + +bool PDBSourceLineWriter::PrintPEInfo() { + PEModuleInfo info; + if (!GetPEInfo(&info)) { + return false; + } + + fprintf(output_, "INFO CODE_ID %ws %ws\n", + info.code_identifier.c_str(), + info.code_file.c_str()); + return true; +} + +// wcstol_positive_strict is sort of like wcstol, but much stricter. string +// should be a buffer pointing to a null-terminated string containing only +// decimal digits. If the entire string can be converted to an integer +// without overflowing, and there are no non-digit characters before the +// result is set to the value and this function returns true. Otherwise, +// this function returns false. This is an alternative to the strtol, atoi, +// and scanf families, which are not as strict about input and in some cases +// don't provide a good way for the caller to determine if a conversion was +// successful. +static bool wcstol_positive_strict(wchar_t *string, int *result) { + int value = 0; + for (wchar_t *c = string; *c != '\0'; ++c) { + int last_value = value; + value *= 10; + // Detect overflow. + if (value / 10 != last_value || value < 0) { + return false; + } + if (*c < '0' || *c > '9') { + return false; + } + unsigned int c_value = *c - '0'; + last_value = value; + value += c_value; + // Detect overflow. + if (value < last_value) { + return false; + } + // Forbid leading zeroes unless the string is just "0". + if (value == 0 && *(c+1) != '\0') { + return false; + } + } + *result = value; + return true; +} + +bool PDBSourceLineWriter::FindPEFile() { + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + fprintf(stderr, "get_globalScope failed\n"); + return false; + } + + CComBSTR symbols_file; + if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) { + wstring file(symbols_file); + + // Look for an EXE or DLL file. + const wchar_t *extensions[] = { L"exe", L"dll" }; + for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) { + size_t dot_pos = file.find_last_of(L"."); + if (dot_pos != wstring::npos) { + file.replace(dot_pos + 1, wstring::npos, extensions[i]); + // Check if this file exists. + if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) { + code_file_ = file; + return true; + } + } + } + } + + return false; +} + +// static +bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, + BSTR *name, + int *stack_param_size) { + *stack_param_size = -1; + const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS | + UNDNAME_NO_FUNCTION_RETURNS | + UNDNAME_NO_ALLOCATION_MODEL | + UNDNAME_NO_ALLOCATION_LANGUAGE | + UNDNAME_NO_THISTYPE | + UNDNAME_NO_ACCESS_SPECIFIERS | + UNDNAME_NO_THROW_SIGNATURES | + UNDNAME_NO_MEMBER_TYPE | + UNDNAME_NO_RETURN_UDT_MODEL | + UNDNAME_NO_ECSU; + + // Use get_undecoratedNameEx to get readable C++ names with arguments. + if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) { + if (function->get_name(name) != S_OK) { + fprintf(stderr, "failed to get function name\n"); + return false; + } + // If a name comes from get_name because no undecorated form existed, + // it's already formatted properly to be used as output. Don't do any + // additional processing. + // + // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's. + // This will result in calling get_name for some C++ symbols, so + // all of the parameter and return type information may not be included in + // the name string. + } else { + // C++ uses a bogus "void" argument for functions and methods that don't + // take any parameters. Take it out of the undecorated name because it's + // ugly and unnecessary. + const wchar_t *replace_string = L"(void)"; + const size_t replace_length = wcslen(replace_string); + const wchar_t *replacement_string = L"()"; + size_t length = wcslen(*name); + if (length >= replace_length) { + wchar_t *name_end = *name + length - replace_length; + if (wcscmp(name_end, replace_string) == 0) { + WindowsStringUtils::safe_wcscpy(name_end, replace_length, + replacement_string); + length = wcslen(*name); + } + } + + // Undecorate names used for stdcall and fastcall. These names prefix + // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it + // with '@' followed by the number of bytes of parameters, in decimal. + // If such a name is found, take note of the size and undecorate it. + // Only do this for names that aren't C++, which is determined based on + // whether the undecorated name contains any ':' or '(' characters. + if (!wcschr(*name, ':') && !wcschr(*name, '(') && + (*name[0] == '_' || *name[0] == '@')) { + wchar_t *last_at = wcsrchr(*name + 1, '@'); + if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) { + // If this function adheres to the fastcall convention, it accepts up + // to the first 8 bytes of parameters in registers (%ecx and %edx). + // We're only interested in the stack space used for parameters, so + // so subtract 8 and don't let the size go below 0. + if (*name[0] == '@') { + if (*stack_param_size > 8) { + *stack_param_size -= 8; + } else { + *stack_param_size = 0; + } + } + + // Undecorate the name by moving it one character to the left in its + // buffer, and terminating it where the last '@' had been. + WindowsStringUtils::safe_wcsncpy(*name, length, + *name + 1, last_at - *name - 1); + } else if (*name[0] == '_') { + // This symbol's name is encoded according to the cdecl rules. The + // name doesn't end in a '@' character followed by a decimal positive + // integer, so it's not a stdcall name. Strip off the leading + // underscore. + WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length); + } + } + } + + return true; +} + +// static +int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) { + // This implementation is highly x86-specific. + + // Gather the symbols corresponding to data. + CComPtr data_children; + if (FAILED(function->findChildren(SymTagData, NULL, nsNone, + &data_children))) { + return 0; + } + + // lowest_base is the lowest %ebp-relative byte offset used for a parameter. + // highest_end is one greater than the highest offset (i.e. base + length). + // Stack parameters are assumed to be contiguous, because in reality, they + // are. + int lowest_base = INT_MAX; + int highest_end = INT_MIN; + + CComPtr child; + DWORD count; + while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) { + // If any operation fails at this point, just proceed to the next child. + // Use the next_child label instead of continue because child needs to + // be released before it's reused. Declare constructable/destructable + // types early to avoid gotos that cross initializations. + CComPtr child_type; + + // DataIsObjectPtr is only used for |this|. Because |this| can be passed + // as a stack parameter, look for it in addition to traditional + // parameters. + DWORD child_kind; + if (FAILED(child->get_dataKind(&child_kind)) || + (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) { + goto next_child; + } + + // Only concentrate on register-relative parameters. Parameters may also + // be enregistered (passed directly in a register), but those don't + // consume any stack space, so they're not of interest. + DWORD child_location_type; + if (FAILED(child->get_locationType(&child_location_type)) || + child_location_type != LocIsRegRel) { + goto next_child; + } + + // Of register-relative parameters, the only ones that make any sense are + // %ebp- or %esp-relative. Note that MSVC's debugging information always + // gives parameters as %ebp-relative even when a function doesn't use a + // traditional frame pointer and stack parameters are accessed relative to + // %esp, so just look for %ebp-relative parameters. If you wanted to + // access parameters, you'd probably want to treat these %ebp-relative + // offsets as if they were relative to %esp before a function's prolog + // executed. + DWORD child_register; + if (FAILED(child->get_registerId(&child_register)) || + child_register != CV_REG_EBP) { + goto next_child; + } + + LONG child_register_offset; + if (FAILED(child->get_offset(&child_register_offset))) { + goto next_child; + } + + // IDiaSymbol::get_type can succeed but still pass back a NULL value. + if (FAILED(child->get_type(&child_type)) || !child_type) { + goto next_child; + } + + ULONGLONG child_length; + if (FAILED(child_type->get_length(&child_length))) { + goto next_child; + } + + int child_end = child_register_offset + static_cast(child_length); + if (child_register_offset < lowest_base) { + lowest_base = child_register_offset; + } + if (child_end > highest_end) { + highest_end = child_end; + } + +next_child: + child.Release(); + } + + int param_size = 0; + // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest + // possible address to find a stack parameter before executing a function's + // prolog (see above). Some optimizations cause parameter offsets to be + // lower than 4, but we're not concerned with those because we're only + // looking for parameters contained in addresses higher than where the + // return address is stored. + if (lowest_base < 4) { + lowest_base = 4; + } + if (highest_end > lowest_base) { + // All stack parameters are pushed as at least 4-byte quantities. If the + // last type was narrower than 4 bytes, promote it. This assumes that all + // parameters' offsets are 4-byte-aligned, which is always the case. Only + // worry about the last type, because we're not summing the type sizes, + // just looking at the lowest and highest offsets. + int remainder = highest_end % 4; + if (remainder) { + highest_end += 4 - remainder; + } + + param_size = highest_end - lowest_base; + } + + return param_size; +} + +bool PDBSourceLineWriter::WriteMap(FILE *map_file) { + output_ = map_file; + + // Load the OMAP information, and disable auto-translation of addresses in + // preference of doing it ourselves. + OmapData omap_data; + if (!GetOmapDataAndDisableTranslation(session_, &omap_data)) + return false; + BuildImageMap(omap_data, &image_map_); + + bool ret = PrintPDBInfo(); + // This is not a critical piece of the symbol file. + PrintPEInfo(); + ret = ret && + PrintSourceFiles() && + PrintFunctions() && + PrintFrameData(); + + output_ = NULL; + return ret; +} + +void PDBSourceLineWriter::Close() { + session_.Release(); +} + +bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { + if (!info) { + return false; + } + + info->debug_file.clear(); + info->debug_identifier.clear(); + info->cpu.clear(); + + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + return false; + } + + DWORD machine_type; + // get_machineType can return S_FALSE. + if (global->get_machineType(&machine_type) == S_OK) { + // The documentation claims that get_machineType returns a value from + // the CV_CPU_TYPE_e enumeration, but that's not the case. + // Instead, it returns one of the IMAGE_FILE_MACHINE values as + // defined here: + // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx + switch (machine_type) { + case IMAGE_FILE_MACHINE_I386: + info->cpu = L"x86"; + break; + case IMAGE_FILE_MACHINE_AMD64: + info->cpu = L"x86_64"; + break; + default: + info->cpu = L"unknown"; + break; + } + } else { + // Unexpected, but handle gracefully. + info->cpu = L"unknown"; + } + + // DWORD* and int* are not compatible. This is clean and avoids a cast. + DWORD age; + if (FAILED(global->get_age(&age))) { + return false; + } + + bool uses_guid; + if (!UsesGUID(&uses_guid)) { + return false; + } + + if (uses_guid) { + GUID guid; + if (FAILED(global->get_guid(&guid))) { + return false; + } + + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + wchar_t age_string[9]; + swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]), + L"%x", age); + + // remove when VC++7.1 is no longer supported + age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0'; + + info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid); + info->debug_identifier.append(age_string); + } else { + DWORD signature; + if (FAILED(global->get_signature(&signature))) { + return false; + } + + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + wchar_t identifier_string[17]; + swprintf(identifier_string, + sizeof(identifier_string) / sizeof(identifier_string[0]), + L"%08X%x", signature, age); + + // remove when VC++7.1 is no longer supported + identifier_string[sizeof(identifier_string) / + sizeof(identifier_string[0]) - 1] = L'\0'; + + info->debug_identifier = identifier_string; + } + + CComBSTR debug_file_string; + if (FAILED(global->get_symbolsFileName(&debug_file_string))) { + return false; + } + info->debug_file = + WindowsStringUtils::GetBaseName(wstring(debug_file_string)); + + return true; +} + +bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { + if (!info) { + return false; + } + + if (code_file_.empty() && !FindPEFile()) { + fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); + return false; + } + + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string code_file; + if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { + return false; + } + + AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str()); + return false; + } + + info->code_file = WindowsStringUtils::GetBaseName(code_file_); + + // The date and time that the file was created by the linker. + DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp; + // The size of the file in bytes, including all headers. + DWORD SizeOfImage = 0; + PIMAGE_OPTIONAL_HEADER64 opt = + &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader; + if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // 64-bit PE file. + SizeOfImage = opt->SizeOfImage; + } + else { + // 32-bit PE file. + SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage; + } + wchar_t code_identifier[32]; + swprintf(code_identifier, + sizeof(code_identifier) / sizeof(code_identifier[0]), + L"%08X%X", TimeDateStamp, SizeOfImage); + info->code_identifier = code_identifier; + + return true; +} + +bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { + if (!uses_guid) + return false; + + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) + return false; + + GUID guid; + if (FAILED(global->get_guid(&guid))) + return false; + + DWORD signature; + if (FAILED(global->get_signature(&signature))) + return false; + + // There are two possibilities for guid: either it's a real 128-bit GUID + // as identified in a code module by a new-style CodeView record, or it's + // a 32-bit signature (timestamp) as identified by an old-style record. + // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h. + // + // Because DIA doesn't provide a way to directly determine whether a module + // uses a GUID or a 32-bit signature, this code checks whether the first 32 + // bits of guid are the same as the signature, and if the rest of guid is + // zero. If so, then with a pretty high degree of certainty, there's an + // old-style CodeView record in use. This method will only falsely find an + // an old-style CodeView record if a real 128-bit GUID has its first 32 + // bits set the same as the module's signature (timestamp) and the rest of + // the GUID is set to 0. This is highly unlikely. + + GUID signature_guid = {signature}; // 0-initializes other members + *uses_guid = !IsEqualGUID(guid, signature_guid); + return true; +} + +} // namespace google_breakpad diff --git a/breakpad/common/windows/pdb_source_line_writer.h b/breakpad/common/windows/pdb_source_line_writer.h new file mode 100644 index 0000000000..be6121c3fa --- /dev/null +++ b/breakpad/common/windows/pdb_source_line_writer.h @@ -0,0 +1,243 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// PDBSourceLineWriter uses a pdb file produced by Visual C++ to output +// a line/address map for use with BasicSourceLineResolver. + +#ifndef _PDB_SOURCE_LINE_WRITER_H__ +#define _PDB_SOURCE_LINE_WRITER_H__ + +#include + +#include +#include + +#include "common/windows/omap.h" + +struct IDiaEnumLineNumbers; +struct IDiaSession; +struct IDiaSymbol; + +namespace google_breakpad { + +using std::wstring; +using stdext::hash_map; + +// A structure that carries information that identifies a pdb file. +struct PDBModuleInfo { + public: + // The basename of the pdb file from which information was loaded. + wstring debug_file; + + // The pdb's identifier. For recent pdb files, the identifier consists + // of the pdb's guid, in uppercase hexadecimal form without any dashes + // or separators, followed immediately by the pdb's age, also in + // uppercase hexadecimal form. For older pdb files which have no guid, + // the identifier is the pdb's 32-bit signature value, in zero-padded + // hexadecimal form, followed immediately by the pdb's age, in lowercase + // hexadecimal form. + wstring debug_identifier; + + // A string identifying the cpu that the pdb is associated with. + // Currently, this may be "x86" or "unknown". + wstring cpu; +}; + +// A structure that carries information that identifies a PE file, +// either an EXE or a DLL. +struct PEModuleInfo { + // The basename of the PE file. + wstring code_file; + + // The PE file's code identifier, which consists of its timestamp + // and file size concatenated together into a single hex string. + // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and + // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp + // documentation.) This is not well documented, if it's documented + // at all, but it's what symstore does and what DbgHelp supports. + wstring code_identifier; +}; + +class PDBSourceLineWriter { + public: + enum FileFormat { + PDB_FILE, // a .pdb file containing debug symbols + EXE_FILE, // a .exe or .dll file + ANY_FILE // try PDB_FILE and then EXE_FILE + }; + + explicit PDBSourceLineWriter(); + ~PDBSourceLineWriter(); + + // Opens the given file. For executable files, the corresponding pdb + // file must be available; Open will be if it is not. + // If there is already a pdb file open, it is automatically closed. + // Returns true on success. + bool Open(const wstring &file, FileFormat format); + + // Locates the pdb file for the given executable (exe or dll) file, + // and opens it. If there is already a pdb file open, it is automatically + // closed. Returns true on success. + bool OpenExecutable(const wstring &exe_file); + + // Writes a map file from the current pdb file to the given file stream. + // Returns true on success. + bool WriteMap(FILE *map_file); + + // Closes the current pdb file and its associated resources. + void Close(); + + // Retrieves information about the module's debugging file. Returns + // true on success and false on failure. + bool GetModuleInfo(PDBModuleInfo *info); + + // Retrieves information about the module's PE file. Returns + // true on success and false on failure. + bool GetPEInfo(PEModuleInfo *info); + + // Sets uses_guid to true if the opened file uses a new-style CodeView + // record with a 128-bit GUID, or false if the opened file uses an old-style + // CodeView record. When no GUID is available, a 32-bit signature should be + // used to identify the module instead. If the information cannot be + // determined, this method returns false. + bool UsesGUID(bool *uses_guid); + + private: + // Outputs the line/address pairs for each line in the enumerator. + // Returns true on success. + bool PrintLines(IDiaEnumLineNumbers *lines); + + // Outputs a function address and name, followed by its source line list. + // block can be the same object as function, or it can be a reference + // to a code block that is lexically part of this function, but + // resides at a separate address. + // Returns true on success. + bool PrintFunction(IDiaSymbol *function, IDiaSymbol *block); + + // Outputs all functions as described above. Returns true on success. + bool PrintFunctions(); + + // Outputs all of the source files in the session's pdb file. + // Returns true on success. + bool PrintSourceFiles(); + + // Outputs all of the frame information necessary to construct stack + // backtraces in the absence of frame pointers. Returns true on success. + bool PrintFrameData(); + + // Outputs a single public symbol address and name, if the symbol corresponds + // to a code address. Returns true on success. If symbol is does not + // correspond to code, returns true without outputting anything. + bool PrintCodePublicSymbol(IDiaSymbol *symbol); + + // Outputs a line identifying the PDB file that is being dumped, along with + // its uuid and age. + bool PrintPDBInfo(); + + // Outputs a line identifying the PE file corresponding to the PDB + // file that is being dumped, along with its code identifier, + // which consists of its timestamp and file size. + bool PrintPEInfo(); + + // Returns true if this filename has already been seen, + // and an ID is stored for it, or false if it has not. + bool FileIDIsCached(const wstring &file) { + return unique_files_.find(file) != unique_files_.end(); + }; + + // Cache this filename and ID for later reuse. + void CacheFileID(const wstring &file, DWORD id) { + unique_files_[file] = id; + }; + + // Store this ID in the cache as a duplicate for this filename. + void StoreDuplicateFileID(const wstring &file, DWORD id) { + hash_map::iterator iter = unique_files_.find(file); + if (iter != unique_files_.end()) { + // map this id to the previously seen one + file_ids_[id] = iter->second; + } + }; + + // Given a file's unique ID, return the ID that should be used to + // reference it. There may be multiple files with identical filenames + // but different unique IDs. The cache attempts to coalesce these into + // one ID per unique filename. + DWORD GetRealFileID(DWORD id) { + hash_map::iterator iter = file_ids_.find(id); + if (iter == file_ids_.end()) + return id; + return iter->second; + }; + + // Find the PE file corresponding to the loaded PDB file, and + // set the code_file_ member. Returns false on failure. + bool FindPEFile(); + + // Returns the function name for a symbol. If possible, the name is + // undecorated. If the symbol's decorated form indicates the size of + // parameters on the stack, this information is returned in stack_param_size. + // Returns true on success. If the symbol doesn't encode parameter size + // information, stack_param_size is set to -1. + static bool GetSymbolFunctionName(IDiaSymbol *function, BSTR *name, + int *stack_param_size); + + // Returns the number of bytes of stack space used for a function's + // parameters. function must have the tag SymTagFunction. In the event of + // a failure, returns 0, which is also a valid number of bytes. + static int GetFunctionStackParamSize(IDiaSymbol *function); + + // The filename of the PE file corresponding to the currently-open + // pdb file. + wstring code_file_; + + // The session for the currently-open pdb file. + CComPtr session_; + + // The current output file for this WriteMap invocation. + FILE *output_; + + // There may be many duplicate filenames with different IDs. + // This maps from the DIA "unique ID" to a single ID per unique + // filename. + hash_map file_ids_; + // This maps unique filenames to file IDs. + hash_map unique_files_; + + // This is used for calculating post-transform symbol addresses and lengths. + ImageMap image_map_; + + // Disallow copy ctor and operator= + PDBSourceLineWriter(const PDBSourceLineWriter&); + void operator=(const PDBSourceLineWriter&); +}; + +} // namespace google_breakpad + +#endif // _PDB_SOURCE_LINE_WRITER_H__ diff --git a/breakpad/common/windows/string_utils-inl.h b/breakpad/common/windows/string_utils-inl.h new file mode 100644 index 0000000000..d281aaa1fe --- /dev/null +++ b/breakpad/common/windows/string_utils-inl.h @@ -0,0 +1,142 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// string_utils-inl.h: Safer string manipulation on Windows, supporting +// pre-MSVC8 environments. + +#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__ +#define COMMON_WINDOWS_STRING_UTILS_INL_H__ + +#include +#include + +#include + +// The "ll" printf format size specifier corresponding to |long long| was +// intrudced in MSVC8. Earlier versions did not provide this size specifier, +// but "I64" can be used to print 64-bit types. Don't use "I64" where "ll" +// is available, in the event of oddball systems where |long long| is not +// 64 bits wide. +#if _MSC_VER >= 1400 // MSVC 2005/8 +#define WIN_STRING_FORMAT_LL "ll" +#else // MSC_VER >= 1400 +#define WIN_STRING_FORMAT_LL "I64" +#endif // MSC_VER >= 1400 + +// A nonconforming version of swprintf, without the length argument, was +// included with the CRT prior to MSVC8. Although a conforming version was +// also available via an overload, it is not reliably chosen. _snwprintf +// behaves as a standards-confirming swprintf should, so force the use of +// _snwprintf when using older CRTs. +#if _MSC_VER < 1400 // MSVC 2005/8 +#define swprintf _snwprintf +#else +// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently, +// it takes the same argument list as swprintf. +#define swprintf swprintf_s +#endif // MSC_VER < 1400 + +namespace google_breakpad { + +using std::string; +using std::wstring; + +class WindowsStringUtils { + public: + // Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does + // not fail if source is longer than destination_size. The destination + // buffer is always 0-terminated. + static void safe_wcscpy(wchar_t *destination, size_t destination_size, + const wchar_t *source); + + // Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot + // be passed directly, and pre-MSVC8, this will not fail if source or count + // are longer than destination_size. The destination buffer is always + // 0-terminated. + static void safe_wcsncpy(wchar_t *destination, size_t destination_size, + const wchar_t *source, size_t count); + + // Performs multi-byte to wide character conversion on C++ strings, using + // mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure, + // without setting wcs. + static bool safe_mbstowcs(const string &mbs, wstring *wcs); + + // The inverse of safe_mbstowcs. + static bool safe_wcstombs(const wstring &wcs, string *mbs); + + // Returns the base name of a file, e.g. strips off the path. + static wstring GetBaseName(const wstring &filename); + + private: + // Disallow instantiation and other object-based operations. + WindowsStringUtils(); + WindowsStringUtils(const WindowsStringUtils&); + ~WindowsStringUtils(); + void operator=(const WindowsStringUtils&); +}; + +// static +inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination, + size_t destination_size, + const wchar_t *source) { +#if _MSC_VER >= 1400 // MSVC 2005/8 + wcscpy_s(destination, destination_size, source); +#else // _MSC_VER >= 1400 + // Pre-MSVC 2005/8 doesn't have wcscpy_s. Simulate it with wcsncpy. + // wcsncpy doesn't 0-terminate the destination buffer if the source string + // is longer than size. Ensure that the destination is 0-terminated. + wcsncpy(destination, source, destination_size); + if (destination && destination_size) + destination[destination_size - 1] = 0; +#endif // _MSC_VER >= 1400 +} + +// static +inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination, + size_t destination_size, + const wchar_t *source, + size_t count) { +#if _MSC_VER >= 1400 // MSVC 2005/8 + wcsncpy_s(destination, destination_size, source, count); +#else // _MSC_VER >= 1400 + // Pre-MSVC 2005/8 doesn't have wcsncpy_s. Simulate it with wcsncpy. + // wcsncpy doesn't 0-terminate the destination buffer if the source string + // is longer than size. Ensure that the destination is 0-terminated. + if (destination_size < count) + count = destination_size; + + wcsncpy(destination, source, count); + if (destination && count) + destination[count - 1] = 0; +#endif // _MSC_VER >= 1400 +} + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_STRING_UTILS_INL_H__ diff --git a/breakpad/common/windows/string_utils.cc b/breakpad/common/windows/string_utils.cc new file mode 100644 index 0000000000..e6ffa0823f --- /dev/null +++ b/breakpad/common/windows/string_utils.cc @@ -0,0 +1,133 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include "common/windows/string_utils-inl.h" + +namespace google_breakpad { + +// static +wstring WindowsStringUtils::GetBaseName(const wstring &filename) { + wstring base_name(filename); + size_t slash_pos = base_name.find_last_of(L"/\\"); + if (slash_pos != wstring::npos) { + base_name.erase(0, slash_pos + 1); + } + return base_name; +} + +// static +bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) { + assert(wcs); + + // First, determine the length of the destination buffer. + size_t wcs_length; + +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) { + return false; + } + assert(wcs_length > 0); +#else // _MSC_VER >= 1400 + if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) < 0) { + return false; + } + + // Leave space for the 0-terminator. + ++wcs_length; +#endif // _MSC_VER >= 1400 + + std::vector wcs_v(wcs_length); + + // Now, convert. +#if _MSC_VER >= 1400 // MSVC 2005/8 + if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(), + _TRUNCATE)) != 0) { + return false; + } +#else // _MSC_VER >= 1400 + if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) < 0) { + return false; + } + + // Ensure presence of 0-terminator. + wcs_v[wcs_length - 1] = '\0'; +#endif // _MSC_VER >= 1400 + + *wcs = &wcs_v[0]; + return true; +} + +// static +bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) { + assert(mbs); + + // First, determine the length of the destination buffer. + size_t mbs_length; + +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) { + return false; + } + assert(mbs_length > 0); +#else // _MSC_VER >= 1400 + if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) < 0) { + return false; + } + + // Leave space for the 0-terminator. + ++mbs_length; +#endif // _MSC_VER >= 1400 + + std::vector mbs_v(mbs_length); + + // Now, convert. +#if _MSC_VER >= 1400 // MSVC 2005/8 + if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(), + _TRUNCATE)) != 0) { + return false; + } +#else // _MSC_VER >= 1400 + if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) < 0) { + return false; + } + + // Ensure presence of 0-terminator. + mbs_v[mbs_length - 1] = '\0'; +#endif // _MSC_VER >= 1400 + + *mbs = &mbs_v[0]; + return true; +} + +} // namespace google_breakpad diff --git a/breakpad/dump_syms.exe b/breakpad/dump_syms.exe new file mode 100644 index 0000000000..2f2611fd6e Binary files /dev/null and b/breakpad/dump_syms.exe differ diff --git a/breakpad/getmssym.sh b/breakpad/getmssym.sh new file mode 100644 index 0000000000..cd6e5aff1b --- /dev/null +++ b/breakpad/getmssym.sh @@ -0,0 +1,5 @@ +#!/bin/bash +curl --user-agent "Microsoft-Symbol-Server" http://msdl.microsoft.com/download/symbols/$1/$2/${1%.*}.pd_ --output ${1%.*}.pd_ +expand ${1%.*}.pd_ ${1%.*}.pdb +./makesym.sh ${1%.*}.pdb +rm ${1%.*}.pd_ ${1%.*}.pdb diff --git a/breakpad/google_breakpad/common/breakpad_types.h b/breakpad/google_breakpad/common/breakpad_types.h new file mode 100644 index 0000000000..a60c5f3593 --- /dev/null +++ b/breakpad/google_breakpad/common/breakpad_types.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* breakpad_types.h: Precise-width types + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file ensures that types uintN_t are defined for N = 8, 16, 32, and + * 64. Types of precise widths are crucial to the task of writing data + * structures on one platform and reading them on another. + * + * Author: Mark Mentovai */ + +#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ +#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ + +#ifndef _WIN32 + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ +#include + +#else /* !_WIN32 */ + +#if _MSC_VER >= 1600 +#include +#elif defined(BREAKPAD_CUSTOM_STDINT_H) +/* Visual C++ Pre-2010 did not ship a stdint.h, so allow + * consumers of this library to provide their own because + * there are often subtle type incompatibilities. + */ +#include BREAKPAD_CUSTOM_STDINT_H +#else +#include + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + +#endif /* !_WIN32 */ + +typedef struct { + uint64_t high; + uint64_t low; +} uint128_struct; + +typedef uint64_t breakpad_time_t; + +/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to + * llx, which is the format string for "long long" - this is a 64-bit + * integral type on many systems. */ +#ifndef PRIx64 +#define PRIx64 "llx" +#endif /* !PRIx64 */ + +#endif /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_cpu_amd64.h b/breakpad/google_breakpad/common/minidump_cpu_amd64.h new file mode 100644 index 0000000000..4256706d77 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_cpu_amd64.h @@ -0,0 +1,235 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on amd64. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai + * Change to split into its own file: Neal Sidhwaney */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ + + +/* + * AMD64 support, see WINNT.H + */ + +typedef struct { + uint16_t control_word; + uint16_t status_word; + uint8_t tag_word; + uint8_t reserved1; + uint16_t error_opcode; + uint32_t error_offset; + uint16_t error_selector; + uint16_t reserved2; + uint32_t data_offset; + uint16_t data_selector; + uint16_t reserved3; + uint32_t mx_csr; + uint32_t mx_csr_mask; + uint128_struct float_registers[8]; + uint128_struct xmm_registers[16]; + uint8_t reserved4[96]; +} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */ + +#define MD_CONTEXT_AMD64_VR_COUNT 26 + +typedef struct { + /* + * Register parameter home addresses. + */ + uint64_t p1_home; + uint64_t p2_home; + uint64_t p3_home; + uint64_t p4_home; + uint64_t p5_home; + uint64_t p6_home; + + /* The next field determines the layout of the structure, and which parts + * of it are populated */ + uint32_t context_flags; + uint32_t mx_csr; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint16_t cs; + + /* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */ + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + + /* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */ + uint16_t ss; + uint32_t eflags; + + /* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr6; + uint64_t dr7; + + /* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */ + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint64_t rsp; + + /* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */ + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint64_t rip; + + /* The next set of registers are included with + * MD_CONTEXT_AMD64_FLOATING_POINT + */ + union { + MDXmmSaveArea32AMD64 flt_save; + struct { + uint128_struct header[2]; + uint128_struct legacy[8]; + uint128_struct xmm0; + uint128_struct xmm1; + uint128_struct xmm2; + uint128_struct xmm3; + uint128_struct xmm4; + uint128_struct xmm5; + uint128_struct xmm6; + uint128_struct xmm7; + uint128_struct xmm8; + uint128_struct xmm9; + uint128_struct xmm10; + uint128_struct xmm11; + uint128_struct xmm12; + uint128_struct xmm13; + uint128_struct xmm14; + uint128_struct xmm15; + } sse_registers; + }; + + uint128_struct vector_register[MD_CONTEXT_AMD64_VR_COUNT]; + uint64_t vector_control; + + /* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ + uint64_t debug_control; + uint64_t last_branch_to_rip; + uint64_t last_branch_from_rip; + uint64_t last_exception_to_rip; + uint64_t last_exception_from_rip; + +} MDRawContextAMD64; /* CONTEXT */ + +/* For (MDRawContextAMD64).context_flags. These values indicate the type of + * context stored in the structure. The high 24 bits identify the CPU, the + * low 8 bits identify the type of context saved. */ +#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */ +#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001) + /* CONTEXT_CONTROL */ +#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002) + /* CONTEXT_INTEGER */ +#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004) + /* CONTEXT_SEGMENTS */ +#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008) + /* CONTEXT_FLOATING_POINT */ +#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010) + /* CONTEXT_DEBUG_REGISTERS */ +#define MD_CONTEXT_AMD64_XSTATE (MD_CONTEXT_AMD64 | 0x00000040) + /* CONTEXT_XSTATE */ + +/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it + * I think it really means CONTEXT_FLOATING_POINT. + */ + +#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \ + MD_CONTEXT_AMD64_INTEGER | \ + MD_CONTEXT_AMD64_FLOATING_POINT) + /* CONTEXT_FULL */ + +#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \ + MD_CONTEXT_AMD64_SEGMENTS | \ + MD_CONTEXT_X86_DEBUG_REGISTERS) + /* CONTEXT_ALL */ + + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_cpu_arm.h b/breakpad/google_breakpad/common/minidump_cpu_arm.h new file mode 100644 index 0000000000..6a71138337 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_cpu_arm.h @@ -0,0 +1,151 @@ +/* Copyright (c) 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ARM. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by + * ensuring that all members are aligned on their natural boundaries. + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Julian Seward + */ + +/* + * ARM support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ + +#define MD_FLOATINGSAVEAREA_ARM_FPR_COUNT 32 +#define MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT 8 + +/* + * Note that these structures *do not* map directly to the CONTEXT + * structure defined in WinNT.h in the Windows Mobile SDK. That structure + * does not accomodate VFPv3, and I'm unsure if it was ever used in the + * wild anyway, as Windows CE only seems to produce "cedumps" which + * are not exactly minidumps. + */ +typedef struct { + uint64_t fpscr; /* FPU status register */ + + /* 32 64-bit floating point registers, d0 .. d31. */ + uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT]; + + /* Miscellaneous control words */ + uint32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT]; +} MDFloatingSaveAreaARM; + +#define MD_CONTEXT_ARM_GPR_COUNT 16 + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint32_t context_flags; + + /* 16 32-bit integer registers, r0 .. r15 + * Note the following fixed uses: + * r13 is the stack pointer + * r14 is the link register + * r15 is the program counter + */ + uint32_t iregs[MD_CONTEXT_ARM_GPR_COUNT]; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* The next field is included with MD_CONTEXT_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM float_save; + +} MDRawContextARM; + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDARMRegisterNumbers { + MD_CONTEXT_ARM_REG_IOS_FP = 7, + MD_CONTEXT_ARM_REG_FP = 11, + MD_CONTEXT_ARM_REG_SP = 13, + MD_CONTEXT_ARM_REG_LR = 14, + MD_CONTEXT_ARM_REG_PC = 15 +}; + +/* For (MDRawContextARM).context_flags. These values indicate the type of + * context stored in the structure. */ +/* CONTEXT_ARM from the Windows CE 5.0 SDK. This value isn't correct + * because this bit can be used for flags. Presumably this value was + * never actually used in minidumps, but only in "CEDumps" which + * are a whole parallel minidump file format for Windows CE. + * Therefore, Breakpad defines its own value for ARM CPUs. + */ +#define MD_CONTEXT_ARM_OLD 0x00000040 +/* This value was chosen to avoid likely conflicts with MD_CONTEXT_* + * for other CPUs. */ +#define MD_CONTEXT_ARM 0x40000000 +#define MD_CONTEXT_ARM_INTEGER (MD_CONTEXT_ARM | 0x00000002) +#define MD_CONTEXT_ARM_FLOATING_POINT (MD_CONTEXT_ARM | 0x00000004) + +#define MD_CONTEXT_ARM_FULL (MD_CONTEXT_ARM_INTEGER | \ + MD_CONTEXT_ARM_FLOATING_POINT) + +#define MD_CONTEXT_ARM_ALL (MD_CONTEXT_ARM_INTEGER | \ + MD_CONTEXT_ARM_FLOATING_POINT) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_cpu_ppc.h b/breakpad/google_breakpad/common/minidump_cpu_ppc.h new file mode 100644 index 0000000000..02ac322023 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_cpu_ppc.h @@ -0,0 +1,163 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ppc. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai + * Change to split into its own file: Neal Sidhwaney */ + +/* + * Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X' + * mach/ppc/_types.h + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ + +#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32 + +typedef struct { + /* fpregs is a double[32] in mach/ppc/_types.h, but a uint64_t is used + * here for precise sizing. */ + uint64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT]; + uint32_t fpscr_pad; + uint32_t fpscr; /* Status/control */ +} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */ + + +#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32 + +typedef struct { + /* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h + * exposes them as four 32-bit quantities. */ + uint128_struct save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT]; + uint128_struct save_vscr; /* Status/control */ + uint32_t save_pad5[4]; + uint32_t save_vrvalid; /* Indicates which vector registers are saved */ + uint32_t save_pad6[7]; +} MDVectorSaveAreaPPC; /* ppc_vector_state */ + + +#define MD_CONTEXT_PPC_GPR_COUNT 32 + +/* Use the same 32-bit alignment when accessing this structure from 64-bit code + * as is used natively in 32-bit code. #pragma pack is a MSVC extension + * supported by gcc. */ +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma pack(4) +#else +#pragma pack(push, 4) +#endif + +typedef struct { + /* context_flags is not present in ppc_thread_state, but it aids + * identification of MDRawContextPPC among other raw context types, + * and it guarantees alignment when we get to float_save. */ + uint32_t context_flags; + + uint32_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ + uint32_t srr1; /* Machine status save/restore: stores msr + * (ps, program/machine state) */ + /* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is + * used for brevity. */ + uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT]; + uint32_t cr; /* Condition */ + uint32_t xer; /* Integer (fiXed-point) exception */ + uint32_t lr; /* Link */ + uint32_t ctr; /* Count */ + uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */ + uint32_t vrsave; /* Vector save */ + + /* float_save and vector_save aren't present in ppc_thread_state, but + * are represented in separate structures that still define a thread's + * context. */ + MDFloatingSaveAreaPPC float_save; + MDVectorSaveAreaPPC vector_save; +} MDRawContextPPC; /* Based on ppc_thread_state */ + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma pack(0) +#else +#pragma pack(pop) +#endif + +/* For (MDRawContextPPC).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its + * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other + * CPUs. */ +#define MD_CONTEXT_PPC 0x20000000 +#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001) +#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008) +#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020) + +#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE +#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \ + MD_CONTEXT_PPC_FLOATING_POINT | \ + MD_CONTEXT_PPC_VECTOR) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_cpu_ppc64.h b/breakpad/google_breakpad/common/minidump_cpu_ppc64.h new file mode 100644 index 0000000000..3a883230a6 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_cpu_ppc64.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2008, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ppc64. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Neal Sidhwaney */ + + +/* + * Breakpad minidump extension for PPC64 support. Based on Darwin/Mac OS X' + * mach/ppc/_types.h + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ + +#include "minidump_cpu_ppc.h" + +// these types are the same in ppc64 & ppc +typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64; +typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64; + +#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT + +typedef struct { + /* context_flags is not present in ppc_thread_state, but it aids + * identification of MDRawContextPPC among other raw context types, + * and it guarantees alignment when we get to float_save. */ + uint64_t context_flags; + + uint64_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ + uint64_t srr1; /* Machine status save/restore: stores msr + * (ps, program/machine state) */ + /* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is + * used for brevity. */ + uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT]; + uint64_t cr; /* Condition */ + uint64_t xer; /* Integer (fiXed-point) exception */ + uint64_t lr; /* Link */ + uint64_t ctr; /* Count */ + uint64_t vrsave; /* Vector save */ + + /* float_save and vector_save aren't present in ppc_thread_state, but + * are represented in separate structures that still define a thread's + * context. */ + MDFloatingSaveAreaPPC float_save; + MDVectorSaveAreaPPC vector_save; +} MDRawContextPPC64; /* Based on ppc_thread_state */ + +/* For (MDRawContextPPC).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its + * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other + * CPUs. */ +#define MD_CONTEXT_PPC64 0x01000000 +#define MD_CONTEXT_PPC64_BASE (MD_CONTEXT_PPC64 | 0x00000001) +#define MD_CONTEXT_PPC64_FLOATING_POINT (MD_CONTEXT_PPC64 | 0x00000008) +#define MD_CONTEXT_PPC64_VECTOR (MD_CONTEXT_PPC64 | 0x00000020) + +#define MD_CONTEXT_PPC64_FULL MD_CONTEXT_PPC64_BASE +#define MD_CONTEXT_PPC64_ALL (MD_CONTEXT_PPC64_FULL | \ + MD_CONTEXT_PPC64_FLOATING_POINT | \ + MD_CONTEXT_PPC64_VECTOR) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_cpu_sparc.h b/breakpad/google_breakpad/common/minidump_cpu_sparc.h new file mode 100644 index 0000000000..ddc4c7590d --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_cpu_sparc.h @@ -0,0 +1,158 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on sparc. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai + * Change to split into its own file: Neal Sidhwaney */ + +/* + * SPARC support, see (solaris)sys/procfs_isa.h also + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ + +#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32 + +typedef struct { + + /* FPU floating point regs */ + uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT]; + + uint64_t filler; + uint64_t fsr; /* FPU status register */ +} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */ + +#define MD_CONTEXT_SPARC_GPR_COUNT 32 + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint32_t context_flags; + uint32_t flag_pad; + /* + * General register access (SPARC). + * Don't confuse definitions here with definitions in . + * Registers are 32 bits for ILP32, 64 bits for LP64. + * SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit + */ + + /* 32 Integer working registers */ + + /* g_r[0-7] global registers(g0-g7) + * g_r[8-15] out registers(o0-o7) + * g_r[16-23] local registers(l0-l7) + * g_r[24-31] in registers(i0-i7) + */ + uint64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT]; + + /* several control registers */ + + /* Processor State register(PSR) for SPARC V7/V8 + * Condition Code register (CCR) for SPARC V9 + */ + uint64_t ccr; + + uint64_t pc; /* Program Counter register (PC) */ + uint64_t npc; /* Next Program Counter register (nPC) */ + uint64_t y; /* Y register (Y) */ + + /* Address Space Identifier register (ASI) for SPARC V9 + * WIM for SPARC V7/V8 + */ + uint64_t asi; + + /* Floating-Point Registers State register (FPRS) for SPARC V9 + * TBR for for SPARC V7/V8 + */ + uint64_t fprs; + + /* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */ + MDFloatingSaveAreaSPARC float_save; + +} MDRawContextSPARC; /* CONTEXT_SPARC */ + +/* For (MDRawContextSPARC).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its + * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other + * CPUs. */ +#define MD_CONTEXT_SPARC 0x10000000 +#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001) +#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002) +#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004) +#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008) + +#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \ + MD_CONTEXT_SPARC_INTEGER) + +#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \ + MD_CONTEXT_SAPARC_FLOATING_POINT | \ + MD_CONTEXT_SAPARC_EXTRA) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_cpu_x86.h b/breakpad/google_breakpad/common/minidump_cpu_x86.h new file mode 100644 index 0000000000..e09cb7cb52 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_cpu_x86.h @@ -0,0 +1,174 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on x86. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ + +#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80 + /* SIZE_OF_80387_REGISTERS */ + +typedef struct { + uint32_t control_word; + uint32_t status_word; + uint32_t tag_word; + uint32_t error_offset; + uint32_t error_selector; + uint32_t data_offset; + uint32_t data_selector; + + /* register_area contains eight 80-bit (x87 "long double") quantities for + * floating-point registers %st0 (%mm0) through %st7 (%mm7). */ + uint8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE]; + uint32_t cr0_npx_state; +} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */ + + +#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512 + /* MAXIMUM_SUPPORTED_EXTENSION */ + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated */ + uint32_t context_flags; + + /* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */ + uint32_t dr0; + uint32_t dr1; + uint32_t dr2; + uint32_t dr3; + uint32_t dr6; + uint32_t dr7; + + /* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */ + MDFloatingSaveAreaX86 float_save; + + /* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */ + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + /* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */ + uint32_t edi; + uint32_t esi; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + + /* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */ + uint32_t ebp; + uint32_t eip; + uint32_t cs; /* WinNT.h says "must be sanitized" */ + uint32_t eflags; /* WinNT.h says "must be sanitized" */ + uint32_t esp; + uint32_t ss; + + /* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS. + * It contains vector (MMX/SSE) registers. It it laid out in the + * format used by the fxsave and fsrstor instructions, so it includes + * a copy of the x87 floating-point registers as well. See FXSAVE in + * "Intel Architecture Software Developer's Manual, Volume 2." */ + uint8_t extended_registers[ + MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE]; +} MDRawContextX86; /* CONTEXT */ + +/* For (MDRawContextX86).context_flags. These values indicate the type of + * context stored in the structure. The high 24 bits identify the CPU, the + * low 8 bits identify the type of context saved. */ +#define MD_CONTEXT_X86 0x00010000 + /* CONTEXT_i386, CONTEXT_i486: identifies CPU */ +#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001) + /* CONTEXT_CONTROL */ +#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002) + /* CONTEXT_INTEGER */ +#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004) + /* CONTEXT_SEGMENTS */ +#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008) + /* CONTEXT_FLOATING_POINT */ +#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010) + /* CONTEXT_DEBUG_REGISTERS */ +#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020) + /* CONTEXT_EXTENDED_REGISTERS */ +#define MD_CONTEXT_X86_XSTATE (MD_CONTEXT_X86 | 0x00000040) + /* CONTEXT_XSTATE */ + +#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \ + MD_CONTEXT_X86_INTEGER | \ + MD_CONTEXT_X86_SEGMENTS) + /* CONTEXT_FULL */ + +#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \ + MD_CONTEXT_X86_FLOATING_POINT | \ + MD_CONTEXT_X86_DEBUG_REGISTERS | \ + MD_CONTEXT_X86_EXTENDED_REGISTERS) + /* CONTEXT_ALL */ + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_exception_linux.h b/breakpad/google_breakpad/common/minidump_exception_linux.h new file mode 100644 index 0000000000..9e7e4f1e12 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_exception_linux.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_exception_linux.h: A definition of exception codes for + * Linux + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + + +/* For (MDException).exception_code. These values come from bits/signum.h. + */ +typedef enum { + MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */ + MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */ + MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGURG = 23, + /* Urgent condition on socket (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25, + /* File size limit exceeded (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */ + MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */ + MD_EXCEPTION_CODE_LIN_SIGSYS = 31, /* Bad system call */ + MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception, + dump requested. */ +} MDExceptionCodeLinux; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_exception_mac.h b/breakpad/google_breakpad/common/minidump_exception_mac.h new file mode 100644 index 0000000000..91c1c09746 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_exception_mac.h @@ -0,0 +1,205 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_exception_mac.h: A definition of exception codes for Mac + * OS X + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X + * support. Based on Darwin/Mac OS X' mach/exception_types.h. This is + * what Mac OS X calls an "exception", not a "code". */ +typedef enum { + /* Exception code. The high 16 bits of exception_code contains one of + * these values. */ + MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */ + /* EXC_BAD_ACCESS */ + MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */ + /* EXC_BAD_INSTRUCTION */ + MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */ + /* EXC_ARITHMETIC */ + MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */ + /* EXC_EMULATION */ + MD_EXCEPTION_MAC_SOFTWARE = 5, + /* EXC_SOFTWARE */ + MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */ + /* EXC_BREAKPOINT */ + MD_EXCEPTION_MAC_SYSCALL = 7, + /* EXC_SYSCALL */ + MD_EXCEPTION_MAC_MACH_SYSCALL = 8, + /* EXC_MACH_SYSCALL */ + MD_EXCEPTION_MAC_RPC_ALERT = 9 + /* EXC_RPC_ALERT */ +} MDExceptionMac; + +/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X + * support. Based on Darwin/Mac OS X' mach/ppc/exception.h and + * mach/i386/exception.h. This is what Mac OS X calls a "code". */ +typedef enum { + /* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values + * from mach/kern_return.h. */ + MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1, + /* KERN_INVALID_ADDRESS */ + MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2, + /* KERN_PROTECTION_FAILURE */ + MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8, + /* KERN_NO_ACCESS */ + MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9, + /* KERN_MEMORY_FAILURE */ + MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10, + /* KERN_MEMORY_ERROR */ + + /* With MD_EXCEPTION_SOFTWARE */ + MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */ + MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */ + MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */ + /* Custom values */ + MD_EXCEPTION_CODE_MAC_NS_EXCEPTION = 0xDEADC0DE, /* uncaught NSException */ + + /* With MD_EXCEPTION_MAC_BAD_ACCESS on arm */ + MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN = 0x0101, /* EXC_ARM_DA_ALIGN */ + MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG = 0x0102, /* EXC_ARM_DA_DEBUG */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on arm */ + MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED = 1, /* EXC_ARM_UNDEFINED */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on arm */ + MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT = 1, /* EXC_ARM_BREAKPOINT */ + + /* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101, + /* EXC_PPC_VM_PROT_READ */ + MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102, + /* EXC_PPC_BADSPACE */ + MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103, + /* EXC_PPC_UNALIGNED */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1, + /* EXC_PPC_INVALID_SYSCALL */ + MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2, + /* EXC_PPC_UNIPL_INST */ + MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3, + /* EXC_PPC_PRIVINST */ + MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4, + /* EXC_PPC_PRIVREG */ + MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5, + /* EXC_PPC_TRACE */ + MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6, + /* EXC_PPC_PERFMON */ + + /* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1, + /* EXC_PPC_OVERFLOW */ + MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2, + /* EXC_PPC_ZERO_DIVIDE */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3, + /* EXC_FLT_INEXACT */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4, + /* EXC_PPC_FLT_ZERO_DIVIDE */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5, + /* EXC_PPC_FLT_UNDERFLOW */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6, + /* EXC_PPC_FLT_OVERFLOW */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7, + /* EXC_PPC_FLT_NOT_A_NUMBER */ + + /* With MD_EXCEPTION_MAC_EMULATION on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8, + /* EXC_PPC_NOEMULATION */ + MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9, + /* EXC_PPC_ALTIVECASSIST */ + + /* With MD_EXCEPTION_MAC_SOFTWARE on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */ + MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt + * values below. */ + MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */ + + /* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */ + MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */ + MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */ + MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */ + MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */ + MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */ + MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */ + MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */ + MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */ + MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */ + MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw + * x86 interrupt codes. Most of these are mapped to other Mach + * exceptions and codes, are handled, or should not occur in user space. + * A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */ + /* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */ + /* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */ + /* EXC_I386_NMIFLT = 2: should not occur in user space */ + /* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */ + /* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */ + /* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */ + /* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */ + /* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */ + /* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */ + /* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */ + MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10, + /* EXC_INVTSSFLT */ + MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11, + /* EXC_SEGNPFLT */ + MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12, + /* EXC_STKFLT */ + MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13, + /* EXC_GPFLT */ + /* EXC_I386_PGFLT = 14: should not occur in user space */ + /* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */ + MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17 + /* EXC_ALIGNFLT (for vector operations) */ + /* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */ + /* EXC_I386_ENDPERR = 33: should not occur */ +} MDExceptionCodeMac; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_exception_ps3.h b/breakpad/google_breakpad/common/minidump_exception_ps3.h new file mode 100644 index 0000000000..adff5a6bbc --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_exception_ps3.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2013, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_exception_ps3.h: A definition of exception codes for + * PS3 */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +typedef enum { + MD_EXCEPTION_CODE_PS3_UNKNOWN = 0, + MD_EXCEPTION_CODE_PS3_TRAP_EXCEP = 1, + MD_EXCEPTION_CODE_PS3_PRIV_INSTR = 2, + MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR = 3, + MD_EXCEPTION_CODE_PS3_INSTR_STORAGE = 4, + MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT = 5, + MD_EXCEPTION_CODE_PS3_DATA_STORAGE = 6, + MD_EXCEPTION_CODE_PS3_DATA_SEGMENT = 7, + MD_EXCEPTION_CODE_PS3_FLOAT_POINT = 8, + MD_EXCEPTION_CODE_PS3_DABR_MATCH = 9, + MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP = 10, + MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS = 11, + MD_EXCEPTION_CODE_PS3_COPRO_ALIGN = 12, + MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM = 13, + MD_EXCEPTION_CODE_PS3_COPRO_ERR = 14, + MD_EXCEPTION_CODE_PS3_COPRO_FIR = 15, + MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT = 16, + MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE = 17, + MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR = 18, + MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR = 19, + MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN = 20, + MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS = 21, + MD_EXCEPTION_CODE_PS3_GRAPHIC = 22 +} MDExceptionCodePS3; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_exception_solaris.h b/breakpad/google_breakpad/common/minidump_exception_solaris.h new file mode 100644 index 0000000000..f18ddf4247 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_exception_solaris.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_exception_solaris.h: A definition of exception codes for + * Solaris + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h + */ +typedef enum { + MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */ + MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */ + MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */ + MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */ + MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */ + MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */ + MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */ + MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */ + MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */ + MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */ + MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */ + MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */ + MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */ + MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */ + MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */ + MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */ + MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */ + MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */ + MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */ + MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */ + MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */ + MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */ + MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */ + MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occurred */ + MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */ + MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */ + MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */ + MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */ + MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */ + MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */ + MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */ + MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */ + MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */ + MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */ + MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */ + MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */ + MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */ + MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */ + MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */ + MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */ + MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */ + MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */ + MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */ +} MDExceptionCodeSolaris; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_exception_win32.h b/breakpad/google_breakpad/common/minidump_exception_win32.h new file mode 100644 index 0000000000..458a705438 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_exception_win32.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_exception_win32.h: Definitions of exception codes for + * Win32 platform + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + + +/* For (MDException).exception_code. These values come from WinBase.h + * and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h, + * they are STATUS_ in WinNT.h). */ +typedef enum { + MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005, + /* DBG_CONTROL_C */ + MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001, + /* EXCEPTION_GUARD_PAGE */ + MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002, + /* EXCEPTION_DATATYPE_MISALIGNMENT */ + MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003, + /* EXCEPTION_BREAKPOINT */ + MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004, + /* EXCEPTION_SINGLE_STEP */ + MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005, + /* EXCEPTION_ACCESS_VIOLATION */ + MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006, + /* EXCEPTION_IN_PAGE_ERROR */ + MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008, + /* EXCEPTION_INVALID_HANDLE */ + MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d, + /* EXCEPTION_ILLEGAL_INSTRUCTION */ + MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025, + /* EXCEPTION_NONCONTINUABLE_EXCEPTION */ + MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026, + /* EXCEPTION_INVALID_DISPOSITION */ + MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c, + /* EXCEPTION_BOUNDS_EXCEEDED */ + MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d, + /* EXCEPTION_FLT_DENORMAL_OPERAND */ + MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e, + /* EXCEPTION_FLT_DIVIDE_BY_ZERO */ + MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f, + /* EXCEPTION_FLT_INEXACT_RESULT */ + MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090, + /* EXCEPTION_FLT_INVALID_OPERATION */ + MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091, + /* EXCEPTION_FLT_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092, + /* EXCEPTION_FLT_STACK_CHECK */ + MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093, + /* EXCEPTION_FLT_UNDERFLOW */ + MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094, + /* EXCEPTION_INT_DIVIDE_BY_ZERO */ + MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095, + /* EXCEPTION_INT_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096, + /* EXCEPTION_PRIV_INSTRUCTION */ + MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd, + /* EXCEPTION_STACK_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194, + /* EXCEPTION_POSSIBLE_DEADLOCK */ + MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409, + /* STATUS_STACK_BUFFER_OVERRUN */ + MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374, + /* STATUS_HEAP_CORRUPTION */ + MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363 + /* Per http://support.microsoft.com/kb/185294, + generated by Visual C++ compiler */ +} MDExceptionCodeWin; + +// These constants are defined in the MSDN documentation of +// the EXCEPTION_RECORD structure. +typedef enum { + MD_ACCESS_VIOLATION_WIN_READ = 0, + MD_ACCESS_VIOLATION_WIN_WRITE = 1, + MD_ACCESS_VIOLATION_WIN_EXEC = 8 +} MDAccessViolationTypeWin; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_format.h b/breakpad/google_breakpad/common/minidump_format.h new file mode 100644 index 0000000000..90e5ba5b63 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_format.h @@ -0,0 +1,949 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + + +#if defined(_MSC_VER) +/* Disable "zero-sized array in struct/union" warnings when compiling in + * MSVC. DbgHelp.h does this too. */ +#pragma warning(push) +#pragma warning(disable:4200) +#endif /* _MSC_VER */ + + +/* + * guiddef.h + */ + +typedef struct { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} MDGUID; /* GUID */ + + +/* + * WinNT.h + */ + +/* Non-x86 CPU identifiers found in the high 24 bits of + * (MDRawContext*).context_flags. These aren't used by Breakpad, but are + * defined here for reference, to avoid assigning values that conflict + * (although some values already conflict). */ +#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */ +/* Additional values from winnt.h in the Windows CE 5.0 SDK: */ +#define MD_CONTEXT_SHX 0x000000c0 /* CONTEXT_SH4 (Super-H, includes SH3) */ +#define MD_CONTEXT_MIPS 0x00010000 /* CONTEXT_R4000 (same value as x86?) */ +#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */ + +/* As of Windows 7 SP1, the number of flag bits has increased to + * include 0x40 (CONTEXT_XSTATE): + * http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx */ +#define MD_CONTEXT_CPU_MASK 0xffffff00 + + +/* This is a base type for MDRawContextX86 and MDRawContextPPC. This + * structure should never be allocated directly. The actual structure type + * can be determined by examining the context_flags field. */ +typedef struct { + uint32_t context_flags; +} MDRawContextBase; + +#include "minidump_cpu_amd64.h" +#include "minidump_cpu_arm.h" +#include "minidump_cpu_ppc.h" +#include "minidump_cpu_ppc64.h" +#include "minidump_cpu_sparc.h" +#include "minidump_cpu_x86.h" + +/* + * WinVer.h + */ + + +typedef struct { + uint32_t signature; + uint32_t struct_version; + uint32_t file_version_hi; + uint32_t file_version_lo; + uint32_t product_version_hi; + uint32_t product_version_lo; + uint32_t file_flags_mask; /* Identifies valid bits in fileFlags */ + uint32_t file_flags; + uint32_t file_os; + uint32_t file_type; + uint32_t file_subtype; + uint32_t file_date_hi; + uint32_t file_date_lo; +} MDVSFixedFileInfo; /* VS_FIXEDFILEINFO */ + +/* For (MDVSFixedFileInfo).signature */ +#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd + /* VS_FFI_SIGNATURE */ + +/* For (MDVSFixedFileInfo).version */ +#define MD_VSFIXEDFILEINFO_VERSION 0x00010000 + /* VS_FFI_STRUCVERSION */ + +/* For (MDVSFixedFileInfo).file_flags_mask and + * (MDVSFixedFileInfo).file_flags */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG 0x00000001 + /* VS_FF_DEBUG */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE 0x00000002 + /* VS_FF_PRERELEASE */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED 0x00000004 + /* VS_FF_PATCHED */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008 + /* VS_FF_PRIVATEBUILD */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010 + /* VS_FF_INFOINFERRED */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020 + /* VS_FF_SPECIALBUILD */ + +/* For (MDVSFixedFileInfo).file_os: high 16 bits */ +#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN 0 /* VOS_UNKNOWN */ +#define MD_VSFIXEDFILEINFO_FILE_OS_DOS (1 << 16) /* VOS_DOS */ +#define MD_VSFIXEDFILEINFO_FILE_OS_OS216 (2 << 16) /* VOS_OS216 */ +#define MD_VSFIXEDFILEINFO_FILE_OS_OS232 (3 << 16) /* VOS_OS232 */ +#define MD_VSFIXEDFILEINFO_FILE_OS_NT (4 << 16) /* VOS_NT */ +#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE (5 << 16) /* VOS_WINCE */ +/* Low 16 bits */ +#define MD_VSFIXEDFILEINFO_FILE_OS__BASE 0 /* VOS__BASE */ +#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1 /* VOS__WINDOWS16 */ +#define MD_VSFIXEDFILEINFO_FILE_OS__PM16 2 /* VOS__PM16 */ +#define MD_VSFIXEDFILEINFO_FILE_OS__PM32 3 /* VOS__PM32 */ +#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4 /* VOS__WINDOWS32 */ + +/* For (MDVSFixedFileInfo).file_type */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN 0 /* VFT_UNKNOWN */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP 1 /* VFT_APP */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL 2 /* VFT_DLL */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV 3 /* VFT_DLL */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT 4 /* VFT_FONT */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD 5 /* VFT_VXD */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7 /* VFT_STATIC_LIB */ + +/* For (MDVSFixedFileInfo).file_subtype */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN 0 + /* VFT2_UNKNOWN */ +/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER 1 + /* VFT2_DRV_PRINTER */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD 2 + /* VFT2_DRV_KEYBOARD */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE 3 + /* VFT2_DRV_LANGUAGE */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY 4 + /* VFT2_DRV_DISPLAY */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE 5 + /* VFT2_DRV_MOUSE */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK 6 + /* VFT2_DRV_NETWORK */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM 7 + /* VFT2_DRV_SYSTEM */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE 8 + /* VFT2_DRV_INSTALLABLE */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND 9 + /* VFT2_DRV_SOUND */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM 10 + /* VFT2_DRV_COMM */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD 11 + /* VFT2_DRV_INPUTMETHOD */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12 + /* VFT2_DRV_VERSIONED_PRINTER */ +/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER 1 + /* VFT2_FONT_RASTER */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR 2 + /* VFT2_FONT_VECTOR */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE 3 + /* VFT2_FONT_TRUETYPE */ + + +/* + * DbgHelp.h + */ + + +/* An MDRVA is an offset into the minidump file. The beginning of the + * MDRawHeader is at offset 0. */ +typedef uint32_t MDRVA; /* RVA */ + +typedef struct { + uint32_t data_size; + MDRVA rva; +} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */ + + +typedef struct { + /* The base address of the memory range on the host that produced the + * minidump. */ + uint64_t start_of_memory_range; + + MDLocationDescriptor memory; +} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */ + + +typedef struct { + uint32_t signature; + uint32_t version; + uint32_t stream_count; + MDRVA stream_directory_rva; /* A |stream_count|-sized array of + * MDRawDirectory structures. */ + uint32_t checksum; /* Can be 0. In fact, that's all that's + * been found in minidump files. */ + uint32_t time_date_stamp; /* time_t */ + uint64_t flags; +} MDRawHeader; /* MINIDUMP_HEADER */ + +/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the + * low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION. Per the + * documentation, the high 16 bits are implementation-specific. */ +#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */ + /* MINIDUMP_SIGNATURE */ +#define MD_HEADER_VERSION 0x0000a793 /* 42899 */ + /* MINIDUMP_VERSION */ + +/* For (MDRawHeader).flags: */ +typedef enum { + /* MD_NORMAL is the standard type of minidump. It includes full + * streams for the thread list, module list, exception, system info, + * and miscellaneous info. A memory list stream is also present, + * pointing to the same stack memory contained in the thread list, + * as well as a 256-byte region around the instruction address that + * was executing when the exception occurred. Stack memory is from + * 4 bytes below a thread's stack pointer up to the top of the + * memory region encompassing the stack. */ + MD_NORMAL = 0x00000000, + MD_WITH_DATA_SEGS = 0x00000001, + MD_WITH_FULL_MEMORY = 0x00000002, + MD_WITH_HANDLE_DATA = 0x00000004, + MD_FILTER_MEMORY = 0x00000008, + MD_SCAN_MEMORY = 0x00000010, + MD_WITH_UNLOADED_MODULES = 0x00000020, + MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040, + MD_FILTER_MODULE_PATHS = 0x00000080, + MD_WITH_PROCESS_THREAD_DATA = 0x00000100, + MD_WITH_PRIVATE_READ_WRITE_MEMORY = 0x00000200, + MD_WITHOUT_OPTIONAL_DATA = 0x00000400, + MD_WITH_FULL_MEMORY_INFO = 0x00000800, + MD_WITH_THREAD_INFO = 0x00001000, + MD_WITH_CODE_SEGS = 0x00002000, + MD_WITHOUT_AUXILLIARY_SEGS = 0x00004000, + MD_WITH_FULL_AUXILLIARY_STATE = 0x00008000, + MD_WITH_PRIVATE_WRITE_COPY_MEMORY = 0x00010000, + MD_IGNORE_INACCESSIBLE_MEMORY = 0x00020000, + MD_WITH_TOKEN_INFORMATION = 0x00040000 +} MDType; /* MINIDUMP_TYPE */ + + +typedef struct { + uint32_t stream_type; + MDLocationDescriptor location; +} MDRawDirectory; /* MINIDUMP_DIRECTORY */ + +/* For (MDRawDirectory).stream_type */ +typedef enum { + MD_UNUSED_STREAM = 0, + MD_RESERVED_STREAM_0 = 1, + MD_RESERVED_STREAM_1 = 2, + MD_THREAD_LIST_STREAM = 3, /* MDRawThreadList */ + MD_MODULE_LIST_STREAM = 4, /* MDRawModuleList */ + MD_MEMORY_LIST_STREAM = 5, /* MDRawMemoryList */ + MD_EXCEPTION_STREAM = 6, /* MDRawExceptionStream */ + MD_SYSTEM_INFO_STREAM = 7, /* MDRawSystemInfo */ + MD_THREAD_EX_LIST_STREAM = 8, + MD_MEMORY_64_LIST_STREAM = 9, + MD_COMMENT_STREAM_A = 10, + MD_COMMENT_STREAM_W = 11, + MD_HANDLE_DATA_STREAM = 12, + MD_FUNCTION_TABLE_STREAM = 13, + MD_UNLOADED_MODULE_LIST_STREAM = 14, + MD_MISC_INFO_STREAM = 15, /* MDRawMiscInfo */ + MD_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */ + MD_THREAD_INFO_LIST_STREAM = 17, + MD_HANDLE_OPERATION_LIST_STREAM = 18, + MD_LAST_RESERVED_STREAM = 0x0000ffff, + + /* Breakpad extension types. 0x4767 = "Gg" */ + MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */ + MD_ASSERTION_INFO_STREAM = 0x47670002, /* MDRawAssertionInfo */ + /* These are additional minidump stream values which are specific to + * the linux breakpad implementation. */ + MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */ + MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */ + MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */ + MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */ + MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */ + MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */ + MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */ + MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug */ +} MDStreamType; /* MINIDUMP_STREAM_TYPE */ + + +typedef struct { + uint32_t length; /* Length of buffer in bytes (not characters), + * excluding 0-terminator */ + uint16_t buffer[1]; /* UTF-16-encoded, 0-terminated */ +} MDString; /* MINIDUMP_STRING */ + +static const size_t MDString_minsize = offsetof(MDString, buffer[0]); + + +typedef struct { + uint32_t thread_id; + uint32_t suspend_count; + uint32_t priority_class; + uint32_t priority; + uint64_t teb; /* Thread environment block */ + MDMemoryDescriptor stack; + MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ +} MDRawThread; /* MINIDUMP_THREAD */ + + +typedef struct { + uint32_t number_of_threads; + MDRawThread threads[1]; +} MDRawThreadList; /* MINIDUMP_THREAD_LIST */ + +static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList, + threads[0]); + + +typedef struct { + uint64_t base_of_image; + uint32_t size_of_image; + uint32_t checksum; /* 0 if unknown */ + uint32_t time_date_stamp; /* time_t */ + MDRVA module_name_rva; /* MDString, pathname or filename */ + MDVSFixedFileInfo version_info; + + /* The next field stores a CodeView record and is populated when a module's + * debug information resides in a PDB file. It identifies the PDB file. */ + MDLocationDescriptor cv_record; + + /* The next field is populated when a module's debug information resides + * in a DBG file. It identifies the DBG file. This field is effectively + * obsolete with modules built by recent toolchains. */ + MDLocationDescriptor misc_record; + + /* Alignment problem: reserved0 and reserved1 are defined by the platform + * SDK as 64-bit quantities. However, that results in a structure whose + * alignment is unpredictable on different CPUs and ABIs. If the ABI + * specifies full alignment of 64-bit quantities in structures (as ppc + * does), there will be padding between miscRecord and reserved0. If + * 64-bit quantities can be aligned on 32-bit boundaries (as on x86), + * this padding will not exist. (Note that the structure up to this point + * contains 1 64-bit member followed by 21 32-bit members.) + * As a workaround, reserved0 and reserved1 are instead defined here as + * four 32-bit quantities. This should be harmless, as there are + * currently no known uses for these fields. */ + uint32_t reserved0[2]; + uint32_t reserved1[2]; +} MDRawModule; /* MINIDUMP_MODULE */ + +/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to + * be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC). + * This doesn't occur on systems that don't tail-pad in this manner. Define + * this macro to be the usable size of the MDRawModule struct, and use it in + * place of sizeof(MDRawModule). */ +#define MD_MODULE_SIZE 108 + + +/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70. + * Ref.: http://www.debuginfo.com/articles/debuginfomatch.html + * MDCVInfoPDB70 is the expected structure type with recent toolchains. */ + +typedef struct { + uint32_t signature; + uint32_t offset; /* Offset to debug data (expect 0 in minidump) */ +} MDCVHeader; + +typedef struct { + MDCVHeader cv_header; + uint32_t signature; /* time_t debug information created */ + uint32_t age; /* revision of PDB file */ + uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file */ +} MDCVInfoPDB20; + +static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20, + pdb_file_name[0]); + +#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */ + +typedef struct { + uint32_t cv_signature; + MDGUID signature; /* GUID, identifies PDB file */ + uint32_t age; /* Identifies incremental changes to PDB file */ + uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file, + * 0-terminated 8-bit character data (UTF-8?) */ +} MDCVInfoPDB70; + +static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70, + pdb_file_name[0]); + +#define MD_CVINFOPDB70_SIGNATURE 0x53445352 /* cvSignature = 'SDSR' */ + +typedef struct { + uint32_t data1[2]; + uint32_t data2; + uint32_t data3; + uint32_t data4; + uint32_t data5[3]; + uint8_t extra[2]; +} MDCVInfoELF; + +/* In addition to the two CodeView record formats above, used for linking + * to external pdb files, it is possible for debugging data to be carried + * directly in the CodeView record itself. These signature values will + * be found in the first 4 bytes of the CodeView record. Additional values + * not commonly experienced in the wild are given by "Microsoft Symbol and + * Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section + * 7.2. An in-depth description of the CodeView 4.1 format is given by + * "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/ + * Microsoft Symbol File Internals/CodeView Subsections, + * http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf + */ +#define MD_CVINFOCV41_SIGNATURE 0x3930424e /* '90BN', CodeView 4.10. */ +#define MD_CVINFOCV50_SIGNATURE 0x3131424e /* '11BN', CodeView 5.0, + * MS C7-format (/Z7). */ + +#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff /* An unlikely value. */ + +/* (MDRawModule).miscRecord can reference MDImageDebugMisc. The Windows + * structure is actually defined in WinNT.h. This structure is effectively + * obsolete with modules built by recent toolchains. */ + +typedef struct { + uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because + * this debug record type is mostly obsolete. */ + uint32_t length; /* Length of entire MDImageDebugMisc structure */ + uint8_t unicode; /* True if data is multibyte */ + uint8_t reserved[3]; + uint8_t data[1]; +} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */ + +static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc, + data[0]); + + +typedef struct { + uint32_t number_of_modules; + MDRawModule modules[1]; +} MDRawModuleList; /* MINIDUMP_MODULE_LIST */ + +static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList, + modules[0]); + + +typedef struct { + uint32_t number_of_memory_ranges; + MDMemoryDescriptor memory_ranges[1]; +} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */ + +static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList, + memory_ranges[0]); + + +#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15 + +typedef struct { + uint32_t exception_code; /* Windows: MDExceptionCodeWin, + * Mac OS X: MDExceptionMac, + * Linux: MDExceptionCodeLinux. */ + uint32_t exception_flags; /* Windows: 1 if noncontinuable, + Mac OS X: MDExceptionCodeMac. */ + uint64_t exception_record; /* Address (in the minidump-producing host's + * memory) of another MDException, for + * nested exceptions. */ + uint64_t exception_address; /* The address that caused the exception. + * Mac OS X: exception subcode (which is + * typically the address). */ + uint32_t number_parameters; /* Number of valid elements in + * exception_information. */ + uint32_t __align; + uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS]; +} MDException; /* MINIDUMP_EXCEPTION */ + +#include "minidump_exception_linux.h" +#include "minidump_exception_mac.h" +#include "minidump_exception_ps3.h" +#include "minidump_exception_solaris.h" +#include "minidump_exception_win32.h" + +typedef struct { + uint32_t thread_id; /* Thread in which the exception + * occurred. Corresponds to + * (MDRawThread).thread_id. */ + uint32_t __align; + MDException exception_record; + MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ +} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */ + + +typedef union { + struct { + uint32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */ + uint32_t version_information; /* cpuid 1: eax */ + uint32_t feature_information; /* cpuid 1: edx */ + uint32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */ + } x86_cpu_info; + struct { + uint32_t cpuid; + uint32_t elf_hwcaps; /* linux specific, 0 otherwise */ + } arm_cpu_info; + struct { + uint64_t processor_features[2]; + } other_cpu_info; +} MDCPUInformation; /* CPU_INFORMATION */ + +/* For (MDCPUInformation).arm_cpu_info.elf_hwcaps. + * This matches the Linux kernel definitions from */ +typedef enum { + MD_CPU_ARM_ELF_HWCAP_SWP = (1 << 0), + MD_CPU_ARM_ELF_HWCAP_HALF = (1 << 1), + MD_CPU_ARM_ELF_HWCAP_THUMB = (1 << 2), + MD_CPU_ARM_ELF_HWCAP_26BIT = (1 << 3), + MD_CPU_ARM_ELF_HWCAP_FAST_MULT = (1 << 4), + MD_CPU_ARM_ELF_HWCAP_FPA = (1 << 5), + MD_CPU_ARM_ELF_HWCAP_VFP = (1 << 6), + MD_CPU_ARM_ELF_HWCAP_EDSP = (1 << 7), + MD_CPU_ARM_ELF_HWCAP_JAVA = (1 << 8), + MD_CPU_ARM_ELF_HWCAP_IWMMXT = (1 << 9), + MD_CPU_ARM_ELF_HWCAP_CRUNCH = (1 << 10), + MD_CPU_ARM_ELF_HWCAP_THUMBEE = (1 << 11), + MD_CPU_ARM_ELF_HWCAP_NEON = (1 << 12), + MD_CPU_ARM_ELF_HWCAP_VFPv3 = (1 << 13), + MD_CPU_ARM_ELF_HWCAP_VFPv3D16 = (1 << 14), + MD_CPU_ARM_ELF_HWCAP_TLS = (1 << 15), + MD_CPU_ARM_ELF_HWCAP_VFPv4 = (1 << 16), + MD_CPU_ARM_ELF_HWCAP_IDIVA = (1 << 17), + MD_CPU_ARM_ELF_HWCAP_IDIVT = (1 << 18), +} MDCPUInformationARMElfHwCaps; + +typedef struct { + /* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO + * structure as returned by GetSystemInfo */ + uint16_t processor_architecture; + uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */ + /* ARM: 6 = ARMv6, 7 = ARMv7 ... */ + uint16_t processor_revision; /* x86: 0xMMSS, where MM=model, + * SS=stepping */ + /* ARM: 0 */ + + uint8_t number_of_processors; + uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */ + + /* The next 5 fields are from the OSVERSIONINFO structure as returned + * by GetVersionEx */ + uint32_t major_version; + uint32_t minor_version; + uint32_t build_number; + uint32_t platform_id; + MDRVA csd_version_rva; /* MDString further identifying the + * host OS. + * Windows: name of the installed OS + * service pack. + * Mac OS X: the Apple OS build number + * (sw_vers -buildVersion). + * Linux: uname -srvmo */ + + uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */ + uint16_t reserved2; + + MDCPUInformation cpu; +} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */ + +/* For (MDRawSystemInfo).processor_architecture: */ +typedef enum { + MD_CPU_ARCHITECTURE_X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */ + MD_CPU_ARCHITECTURE_MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */ + MD_CPU_ARCHITECTURE_ALPHA = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */ + MD_CPU_ARCHITECTURE_PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */ + MD_CPU_ARCHITECTURE_SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX + * (Super-H) */ + MD_CPU_ARCHITECTURE_ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */ + MD_CPU_ARCHITECTURE_IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */ + MD_CPU_ARCHITECTURE_ALPHA64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */ + MD_CPU_ARCHITECTURE_MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL + * (Microsoft Intermediate Language) */ + MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ + MD_CPU_ARCHITECTURE_X86_WIN64 = 10, + /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ + MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */ + MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ + MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ +} MDCPUArchitecture; + +/* For (MDRawSystemInfo).platform_id: */ +typedef enum { + MD_OS_WIN32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */ + MD_OS_WIN32_WINDOWS = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */ + MD_OS_WIN32_NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */ + MD_OS_WIN32_CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH + * (Windows CE, Windows Mobile, "Handheld") */ + + /* The following values are Breakpad-defined. */ + MD_OS_UNIX = 0x8000, /* Generic Unix-ish */ + MD_OS_MAC_OS_X = 0x8101, /* Mac OS X/Darwin */ + MD_OS_IOS = 0x8102, /* iOS */ + MD_OS_LINUX = 0x8201, /* Linux */ + MD_OS_SOLARIS = 0x8202, /* Solaris */ + MD_OS_ANDROID = 0x8203, /* Android */ + MD_OS_PS3 = 0x8204, /* PS3 */ + MD_OS_NACL = 0x8205 /* Native Client (NaCl) */ +} MDOSPlatform; + +typedef struct { + uint16_t year; + uint16_t month; + uint16_t day_of_week; + uint16_t day; + uint16_t hour; + uint16_t minute; + uint16_t second; + uint16_t milliseconds; +} MDSystemTime; /* SYSTEMTIME */ + +typedef struct { + /* Required field. The bias is the difference, in minutes, between + * Coordinated Universal Time (UTC) and local time. + * Formula: UTC = local time + bias */ + int32_t bias; + /* A description for standard time. For example, "EST" could indicate Eastern + * Standard Time. In practice this contains the full time zone names. This + * string can be empty. */ + uint16_t standard_name[32]; /* UTF-16-encoded, 0-terminated */ + /* A MDSystemTime structure that contains a date and local time when the + * transition from daylight saving time to standard time occurs on this + * operating system. If the time zone does not support daylight saving time, + * the month member in the MDSystemTime structure is zero. */ + MDSystemTime standard_date; + /* The bias value to be used during local time translations that occur during + * standard time. */ + int32_t standard_bias; + /* A description for daylight saving time. For example, "PDT" could indicate + * Pacific Daylight Time. In practice this contains the full time zone names. + * This string can be empty. */ + uint16_t daylight_name[32]; /* UTF-16-encoded, 0-terminated */ + /* A MDSystemTime structure that contains a date and local time when the + * transition from standard time to daylight saving time occurs on this + * operating system. If the time zone does not support daylight saving time, + * the month member in the MDSystemTime structure is zero.*/ + MDSystemTime daylight_date; + /* The bias value to be used during local time translations that occur during + * daylight saving time. */ + int32_t daylight_bias; +} MDTimeZoneInformation; /* TIME_ZONE_INFORMATION */ + +/* MAX_PATH from windef.h */ +#define MD_MAX_PATH 260 + +/* The miscellaneous information stream contains a variety + * of small pieces of information. A member is valid if + * it's within the available size and its corresponding + * bit is set. */ +typedef struct { + uint32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */ + uint32_t flags1; + + /* The next field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_ID. */ + uint32_t process_id; + + /* The next 3 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_TIMES. */ + uint32_t process_create_time; /* time_t process started */ + uint32_t process_user_time; /* seconds of user CPU time */ + uint32_t process_kernel_time; /* seconds of kernel CPU time */ + + /* The following fields are not present in MINIDUMP_MISC_INFO but are + * in MINIDUMP_MISC_INFO_2. When this struct is populated, these value + * may not be set. Use flags1 or size_of_info to determine whether these + * values are present. These are only valid when flags1 contains + * MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */ + uint32_t processor_max_mhz; + uint32_t processor_current_mhz; + uint32_t processor_mhz_limit; + uint32_t processor_max_idle_state; + uint32_t processor_current_idle_state; + + /* The following fields are not present in MINIDUMP_MISC_INFO_2 but are + * in MINIDUMP_MISC_INFO_3. When this struct is populated, these value + * may not be set. Use flags1 or size_of_info to determine whether these + * values are present. */ + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY. */ + uint32_t process_integrity_level; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS. */ + uint32_t process_execute_flags; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROTECTED_PROCESS. */ + uint32_t protected_process; + + /* The following 2 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_TIMEZONE. */ + uint32_t time_zone_id; + MDTimeZoneInformation time_zone; + + /* The following fields are not present in MINIDUMP_MISC_INFO_3 but are + * in MINIDUMP_MISC_INFO_4. When this struct is populated, these value + * may not be set. Use size_of_info to determine whether these values are + * present. */ + + /* The following 2 fields are only valid if + * size_of_info is >= MD_MISCINFO4_SIZE */ + uint16_t build_string[MD_MAX_PATH]; /* UTF-16-encoded, 0-terminated */ + uint16_t dbg_bld_str[40]; /* UTF-16-encoded, 0-terminated */ +} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2, + * MINIDUMP_MISC_INFO3, MINIDUMP_MISC_INFO4 */ + +static const size_t MD_MISCINFO_SIZE = + offsetof(MDRawMiscInfo, processor_max_mhz); +static const size_t MD_MISCINFO2_SIZE = + offsetof(MDRawMiscInfo, process_integrity_level); +static const size_t MD_MISCINFO3_SIZE = + offsetof(MDRawMiscInfo, build_string[0]); +static const size_t MD_MISCINFO4_SIZE = sizeof(MDRawMiscInfo); + +/* For (MDRawMiscInfo).flags1. These values indicate which fields in the + * MDRawMiscInfoStructure are valid. */ +typedef enum { + MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001, + /* MINIDUMP_MISC1_PROCESS_ID */ + MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002, + /* MINIDUMP_MISC1_PROCESS_TIMES */ + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004, + /* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */ + MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY = 0x00000010, + /* MINIDUMP_MISC3_PROCESS_INTEGRITY */ + MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS = 0x00000020, + /* MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS */ + MD_MISCINFO_FLAGS1_TIMEZONE = 0x00000040, + /* MINIDUMP_MISC3_TIMEZONE */ + MD_MISCINFO_FLAGS1_PROTECTED_PROCESS = 0x00000080, + /* MINIDUMP_MISC3_PROTECTED_PROCESS */ +} MDMiscInfoFlags1; + +/* + * Around DbgHelp version 6.0, the style of new LIST structures changed + * from including an array of length 1 at the end of the struct to + * represent the variable-length data to including explicit + * "size of header", "size of entry" and "number of entries" fields + * in the header, presumably to allow backwards-compatibly-extending + * the structures in the future. The actual list entries follow the + * header data directly in this case. + */ + +typedef struct { + uint32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */ + uint32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */ + uint64_t number_of_entries; +} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */ + +typedef struct { + uint64_t base_address; /* Base address of a region of pages */ + uint64_t allocation_base; /* Base address of a range of pages + * within this region. */ + uint32_t allocation_protection; /* Memory protection when this region + * was originally allocated: + * MDMemoryProtection */ + uint32_t __alignment1; + uint64_t region_size; + uint32_t state; /* MDMemoryState */ + uint32_t protection; /* MDMemoryProtection */ + uint32_t type; /* MDMemoryType */ + uint32_t __alignment2; +} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */ + +/* For (MDRawMemoryInfo).state */ +typedef enum { + MD_MEMORY_STATE_COMMIT = 0x1000, /* physical storage has been allocated */ + MD_MEMORY_STATE_RESERVE = 0x2000, /* reserved, but no physical storage */ + MD_MEMORY_STATE_FREE = 0x10000 /* available to be allocated */ +} MDMemoryState; + +/* For (MDRawMemoryInfo).allocation_protection and .protection */ +typedef enum { + MD_MEMORY_PROTECT_NOACCESS = 0x01, /* PAGE_NOACCESS */ + MD_MEMORY_PROTECT_READONLY = 0x02, /* PAGE_READONLY */ + MD_MEMORY_PROTECT_READWRITE = 0x04, /* PAGE_READWRITE */ + MD_MEMORY_PROTECT_WRITECOPY = 0x08, /* PAGE_WRITECOPY */ + MD_MEMORY_PROTECT_EXECUTE = 0x10, /* PAGE_EXECUTE */ + MD_MEMORY_PROTECT_EXECUTE_READ = 0x20, /* PAGE_EXECUTE_READ */ + MD_MEMORY_PROTECT_EXECUTE_READWRITE = 0x40, /* PAGE_EXECUTE_READWRITE */ + MD_MEMORY_PROTECT_EXECUTE_WRITECOPY = 0x80, /* PAGE_EXECUTE_WRITECOPY */ + /* These options can be combined with the previous flags. */ + MD_MEMORY_PROTECT_GUARD = 0x100, /* PAGE_GUARD */ + MD_MEMORY_PROTECT_NOCACHE = 0x200, /* PAGE_NOCACHE */ + MD_MEMORY_PROTECT_WRITECOMBINE = 0x400, /* PAGE_WRITECOMBINE */ +} MDMemoryProtection; + +/* Used to mask the mutually exclusive options from the combinable flags. */ +const uint32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF; + +/* For (MDRawMemoryInfo).type */ +typedef enum { + MD_MEMORY_TYPE_PRIVATE = 0x20000, /* not shared by other processes */ + MD_MEMORY_TYPE_MAPPED = 0x40000, /* mapped into the view of a section */ + MD_MEMORY_TYPE_IMAGE = 0x1000000 /* mapped into the view of an image */ +} MDMemoryType; + +/* + * Breakpad extension types + */ + + +typedef struct { + /* validity is a bitmask with values from MDBreakpadInfoValidity, indicating + * which of the other fields in the structure are valid. */ + uint32_t validity; + + /* Thread ID of the handler thread. dump_thread_id should correspond to + * the thread_id of an MDRawThread in the minidump's MDRawThreadList if + * a dedicated thread in that list was used to produce the minidump. If + * the MDRawThreadList does not contain a dedicated thread used to produce + * the minidump, this field should be set to 0 and the validity field + * must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */ + uint32_t dump_thread_id; + + /* Thread ID of the thread that requested the minidump be produced. As + * with dump_thread_id, requesting_thread_id should correspond to the + * thread_id of an MDRawThread in the minidump's MDRawThreadList. For + * minidumps produced as a result of an exception, requesting_thread_id + * will be the same as the MDRawExceptionStream's thread_id field. For + * minidumps produced "manually" at the program's request, + * requesting_thread_id will indicate which thread caused the dump to be + * written. If the minidump was produced at the request of something + * other than a thread in the MDRawThreadList, this field should be set + * to 0 and the validity field must not contain + * MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */ + uint32_t requesting_thread_id; +} MDRawBreakpadInfo; + +/* For (MDRawBreakpadInfo).validity: */ +typedef enum { + /* When set, the dump_thread_id field is valid. */ + MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID = 1 << 0, + + /* When set, the requesting_thread_id field is valid. */ + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1 +} MDBreakpadInfoValidity; + +typedef struct { + /* expression, function, and file are 0-terminated UTF-16 strings. They + * may be truncated if necessary, but should always be 0-terminated when + * written to a file. + * Fixed-length strings are used because MiniDumpWriteDump doesn't offer + * a way for user streams to point to arbitrary RVAs for strings. */ + uint16_t expression[128]; /* Assertion that failed... */ + uint16_t function[128]; /* ...within this function... */ + uint16_t file[128]; /* ...in this file... */ + uint32_t line; /* ...at this line. */ + uint32_t type; +} MDRawAssertionInfo; + +/* For (MDRawAssertionInfo).type: */ +typedef enum { + MD_ASSERTION_INFO_TYPE_UNKNOWN = 0, + + /* Used for assertions that would be raised by the MSVC CRT but are + * directed to an invalid parameter handler instead. */ + MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER, + + /* Used for assertions that would be raised by the MSVC CRT but are + * directed to a pure virtual call handler instead. */ + MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL +} MDAssertionInfoData; + +/* These structs are used to store the DSO debug data in Linux minidumps, + * which is necessary for converting minidumps to usable coredumps. */ +typedef struct { + void* addr; + MDRVA name; + void* ld; +} MDRawLinkMap; + +typedef struct { + uint32_t version; + MDRVA map; + uint32_t dso_count; + void* brk; + void* ldbase; + void* dynamic; +} MDRawDebug; + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /* _MSC_VER */ + + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */ diff --git a/breakpad/google_breakpad/common/minidump_size.h b/breakpad/google_breakpad/common/minidump_size.h new file mode 100644 index 0000000000..918544b662 --- /dev/null +++ b/breakpad/google_breakpad/common/minidump_size.h @@ -0,0 +1,107 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +// minidump_size.h: Provides a C++ template for programmatic access to +// the sizes of various types defined in minidump_format.h. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ + +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +template +class minidump_size { + public: + static size_t size() { return sizeof(T); } +}; + +// Explicit specializations for variable-length types. The size returned +// for these should be the size for an object without its variable-length +// section. + +template<> +class minidump_size { + public: + static size_t size() { return MDString_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawThreadList_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB20_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB70_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDImageDebugMisc_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawModuleList_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawMemoryList_minsize; } +}; + +// Explicit specialization for MDRawModule, for which sizeof may include +// tail-padding on some architectures but not others. + +template<> +class minidump_size { + public: + static size_t size() { return MD_MODULE_SIZE; } +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ diff --git a/breakpad/lib32/breakpad_common.lib b/breakpad/lib32/breakpad_common.lib new file mode 100644 index 0000000000..483050de44 Binary files /dev/null and b/breakpad/lib32/breakpad_common.lib differ diff --git a/breakpad/lib32/crash_generation_client.lib b/breakpad/lib32/crash_generation_client.lib new file mode 100644 index 0000000000..a094b4d92f Binary files /dev/null and b/breakpad/lib32/crash_generation_client.lib differ diff --git a/breakpad/lib32/crash_generation_server.lib b/breakpad/lib32/crash_generation_server.lib new file mode 100644 index 0000000000..f1822fb65b Binary files /dev/null and b/breakpad/lib32/crash_generation_server.lib differ diff --git a/breakpad/lib32/exception_handler.lib b/breakpad/lib32/exception_handler.lib new file mode 100644 index 0000000000..bc71243ed5 Binary files /dev/null and b/breakpad/lib32/exception_handler.lib differ diff --git a/breakpad/lib64/breakpad_common.lib b/breakpad/lib64/breakpad_common.lib new file mode 100644 index 0000000000..cab742cd7a Binary files /dev/null and b/breakpad/lib64/breakpad_common.lib differ diff --git a/breakpad/lib64/crash_generation_client.lib b/breakpad/lib64/crash_generation_client.lib new file mode 100644 index 0000000000..6ac2122c96 Binary files /dev/null and b/breakpad/lib64/crash_generation_client.lib differ diff --git a/breakpad/lib64/crash_generation_server.lib b/breakpad/lib64/crash_generation_server.lib new file mode 100644 index 0000000000..7748182cce Binary files /dev/null and b/breakpad/lib64/crash_generation_server.lib differ diff --git a/breakpad/lib64/exception_handler.lib b/breakpad/lib64/exception_handler.lib new file mode 100644 index 0000000000..133813d2c6 Binary files /dev/null and b/breakpad/lib64/exception_handler.lib differ diff --git a/breakpad/makesym.sh b/breakpad/makesym.sh new file mode 100644 index 0000000000..d4873d31d5 --- /dev/null +++ b/breakpad/makesym.sh @@ -0,0 +1,2 @@ +#!/bin/bash +./dump_syms.exe $1 > ${1%.*}.sym diff --git a/breakpad/symup.sh b/breakpad/symup.sh new file mode 100644 index 0000000000..6c60ea6f5c --- /dev/null +++ b/breakpad/symup.sh @@ -0,0 +1,2 @@ +#!/bin/bash +curl --form "key=PolyRADSymbolUpload" --form "sym=@$2" $1/symupload diff --git a/dist.sh b/dist.sh new file mode 100644 index 0000000000..a1782dfafe --- /dev/null +++ b/dist.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +AUTOBUILD=1 + +if [ $# -ne 1 ] || [ $1 != "autobuild" ]; then + AUTOBUILD=0 + echo "Have you rebuilt the documentation?" + + read; + + echo "Have you marked git commit hash in AssemblyInfo.cs and resource.h (run hash_version.sh)?" + echo "If this is an OFFICIAL build only, mark that in the assembly info and resource.h and bump their versions." + + read; +fi + +rm -rf dist +mkdir -p dist/Release{32,64} +cp -R x64/Release/* dist/Release64/ +cp -R Win32/Release/* dist/Release32/ +cp LICENSE.md Documentation/*.chm dist/Release64/ +cp LICENSE.md Documentation/*.chm dist/Release32/ +cp -R dist/Release64 dist/ReleasePDBs64 +cp -R dist/Release32 dist/ReleasePDBs32 +find dist/Release32/ -iname '*.pdb' -exec rm '{}' \; +find dist/Release64/ -iname '*.pdb' -exec rm '{}' \; +rm dist/Release32/*.{exp,lib,metagen,xml} dist/Release32/*.vshost.* +rm dist/Release64/*.{exp,lib,metagen,xml} dist/Release64/*.vshost.* +mkdir -p dist/Release64/x86 +rm -rf dist/Release32/pdblocate/x64 dist/ReleasePDBs32/pdblocate/x64 +cp -R dist/Release32/{renderdoc.dll,renderdoccmd.exe,pdblocate} dist/Release64/x86/ +mkdir -p dist/ReleasePDBs64/x86 +cp -R dist/ReleasePDBs32/{renderdoc.dll,renderdoc.pdb,renderdoccmd.exe,renderdoccmd.pdb,pdblocate} dist/ReleasePDBs64/x86/ + +if [[ $AUTOBUILD -eq 1 ]]; then + exit; +fi + +echo "Ready to make installer MSIs - make sure to bump version numbers on package." + +read; + +/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.8/bin/candle.exe -o dist/Installer32.wixobj installer/Installer32.wxs +/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.8/bin/light.exe -ext WixUIExtension -sw1076 -o dist/Installer32.msi dist/Installer32.wixobj + +/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.8/bin/candle.exe -o dist/Installer64.wixobj installer/Installer64.wxs +/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.8/bin/light.exe -ext WixUIExtension -sw1076 -o dist/Installer64.msi dist/Installer64.wixobj + +rm dist/*.wixobj dist/*.wixpdb diff --git a/docs/Credits.aml b/docs/Credits.aml new file mode 100644 index 0000000000..2c0ffe9b7e --- /dev/null +++ b/docs/Credits.aml @@ -0,0 +1,135 @@ + + + + + RenderDoc wouldn't have been possible without both the tools and libraries that were + used in its construction, as well as the many people who helped and contributed to make it + the program it is today. + +
+ 3rd Party Credits + + The following libraries and components are incorporated into RenderDoc, listed here in + no particular order. Thanks go out to the developers and contributors behind each of these + libraries who generously donated their work to other free projects! + + + + + +mhook +mhook DLL hooking library, used to inject RenderDoc into applications. +http://codefromthe70s.org/mhook23.aspx + + + + + +TreeView with Columns +TreeView with Columns, an invaluable control filling a much needed niche in .NET winforms. +http://www.codeproject.com/Articles/23746/TreeView-with-Columns + + + + + +Dock Panel Suite +Dock Panel Suite, a mature and stable library that adds the docking and flexibility of RenderDoc's UI. +http://dockpanelsuite.com/ + + + + + +famfamfam Silk Icon set +Lending an air of professionalism and artistic quality to the UI, the Silk icon set is used throughout RenderDoc. +http://www.famfamfam.com/lab/icons/silk/ + + + + + +ScintillaNET +ScintillaNET and by extension Scintilla provide a powerful text editor for the shader viewers. +http://scintillanet.codeplex.com/ + + + + + +Google Breakpad +Google Breakpad provides a rock-solid crash handling and reporting base that help keep RenderDoc stable. +https://code.google.com/p/google-breakpad/ + + + + + +miniz +miniz public domain zip library is used to compress the crash reports for sending. +https://code.google.com/p/miniz/ + + + + + +ILM's half implementation +Used for decoding half data for display. +https://github.com/openexr/openexr/tree/master/IlmBase/Half + + + + + +jpeg-compressor +Used to compress screenshots into jpg format for thumbnail previews. +https://code.google.com/p/jpeg-compressor/ + + + + + +lz4 +lz4 compresses large data transfers (textures and buffers) when going across network connections. +https://code.google.com/p/lz4/ + + + + + +Sandcastle Help File Builder +Sandcastle Help File Builder for creating this documentation that you're reading! +http://shfb.codeplex.com/ + + + + + + +
+
+ Thanks + + There have been many people who have helped in the creation of RenderDoc. Whether + testing, feedback or contributing artwork and design critique everyone listed here and + many more besides have been invaluable in taking RenderDoc from an idea on paper to its + current state. Greets fly out to the following people, listed in no particular order. + + + Chris Bunner, Charlie Cole, James Chilvers, Andrew Khan, Benjamin Hill, Jake Turner, Alex Weighell and the rest + of the Crytek UK R&D team. + Colin Bonstead, Marco Corbetta, Pascal Eggert, Marcel Hatam, Sascha Hoba, Theodor Mader, Mathieu Pinard, Chris Raine, Nicolas Schulz, Tiago Sousa, Sean Tracy, Carsten Wenzel, + and everyone else at the rest of the Crytek Studios. + Daniel Sexton + Jason Mendel + Jacob Kapostins + Iain Cantlay + Luke Lambert + Gareth Thomas + George Ilenei + + + +
+
+
diff --git a/docs/FAQ.aml b/docs/FAQ.aml new file mode 100644 index 0000000000..9e92caac0f --- /dev/null +++ b/docs/FAQ.aml @@ -0,0 +1,224 @@ + + + + + + + Here is a list of commonly asked questions about RenderDoc. + Feel free to contact me if you have another question that isn't covered here + or in this document. + + +
+ How do I do some particular task? + + + Many specific tasks or functions are detailed in the "How Do I... ?" sections. + These sections each take a feature or element of a workflow and explain how it + fits into the program as a whole as well as any details of how it works. + + + If the task you have in mind isn't listed there you might find something similar, + or you might find a related feature which can be used to do what you want. If + the feature you want doesn't seem to exist at all you might want to check the + + to see if it's coming soon - if it's not on that list please feel free to contact + me and request it! Baldur Contact. It has often been that simple features + are very quick to implement and the prioritisation and scheduling of features is fairly + fluid at this stage in development. + + +
+
+ Why did you make RenderDoc? + + + Although several tools do already exist for graphics debugging, none of them quite + suited the functionality I desired and I would often find myself wishing for a feature of + one in another and vice versa. + + + In addition to this, although the functionality overlaps to some degree many of these + tools were primarily designed around the profiling of applications rather than debugging. + While being able to inspect the state and contents of resources does often suffice for + debugging, it's not necessarily the ideal workflow and often it can become cumbersome. + + + In principle I didn't see any reason why I couldn't write a home-brew graphics debugger + with some fairly simple operating principles. While there were a whole lot of caveats + and little stumbling blocks along the way, the original design has pretty much stayed + consistent since the project was started back in July 2012. If you're interested you might + want to read about . + + +
+
+ Where did the name come from? + + + All of the good names were taken :-(. + + +
+
+ Who can I contact about bugs, feature requests, other queries? + + + At the moment there's just me at the wheel - feel free to contact me at + Baldur Contact if you have anything you'd like to ask or suggest. + I use a +github repository +Issues on github +https://github.com/baldurk/renderdoc/issues + for tracking bugs and feature requests so that's the best place to + file an issue. + + + I work on RenderDoc in my spare time but I will do my best to get back to you and + work with you if you have any issues that need attention. If you + have a question or something to discuss you can also post on the +forums +Forums on CryDev.net +http://www.crydev.net/viewforum.php?f=379 +. + + +
+
+ How can I associate RenderDoc's file extensions with the program? + + + If you installed RenderDoc via the installer package rather than the zip folder, the option + is available there to associate RenderDoc's file extensions with the program. Otherwise you + can set them up from the . + + + + RenderDoc will elevate itself to set up these file associations, but otherwise will not hold + on to administrator permissions. + + + RenderDoc associates .rdc and .cap with itself when desired. The .rdc files are the logfiles + output when you capture inside an application. .cap files describe the set up of a + particular capture, and can be used to quickly re-launch a capture preset. + + + If .rdc files are associated with RenderDoc a thumbnail handler is set up, so that in explorer + you'll get thumbnail previews for your captures. + + + + Note that if you move the directory that RenderDoc is you will need to re-configure the + file associations as the registry entries contain absolute paths. + + + + +
+
+ What APIs does RenderDoc support? + + + Currently RenderDoc only supports D3D11 (including the D3D11.1 extensions where available). + + + In future API support is planned for at least OpenGL and D3D9 as soon as time and scheduling + allows - OpenGL support is under development. Support for Mantle would be nice but I can't + promise it just yet until the API is + public. + + Other APIs could be supported once the source is open as I've tried to structure + things such that different back-ends can be slotted in without significant code changes. + + +
+
+ How can I backup or restore my settings? + + + Everything RenderDoc relies upon is stored in %APPDATA%\RenderDoc. You can back up and restore + this directory at will as nothing stored in there is machine specific aside from things like + recent file lists. + + + Deleting this folder will also reset RenderDoc to the defaults - if you uninstall RenderDoc this + folder will not be deleted. + + RenderDoc doesn't install any registry keys aside from those to set up file associations. + + +
+
+ Which network ports does RenderDoc use? + + + RenderDoc uses TCP and UDP ports 38920-38927 consecutively for remote access and control (ie. + capturing remotely) for each new program that is opened on a machine. Note that even if you + initiate a capture locally these ports are still opened for listening. These are the ports + that are probed on a remote host to see if a connection exists. + + + RenderDoc also uses TCP and UDP ports 39920 for remote replay connections, for when a remote + host is used to replay and analyse the log. + + +
+
+ When will RenderDoc be open-sourced? + + + RenderDoc is licensed under the MIT license so that it can very naturally be open-sourced at + a later date. + + + Currently the precise timescale is not defined, but if you'd like more information you can + always get in contact to find out how things are looking. In general the source will be + opened up once the codebase has stabilised and is more feature complete. Currently it's + not in final shape and still changing a lot on a day-to-day basis so it isn't really in a + condition where patches could practically be accepted. + + +
+
+ What are the requirements for RenderDoc? + + + Currently RenderDoc only supports Feature Level 11.0 and above for D3D11. Lower levels + may capture successfully but if uou can't create a FL11.0 device they will not replay. + + +
+
+ Why does my capture say "Failed to capture frame: Uncapped command list"? + + + At the moment RenderDoc only begins capturing deferred command lists at the point that you + trigger a capture. If you replay command lists from before this, RenderDoc will fail to capture + the frame and try again next frame (and eventually give up after a few retries). + + + To change this behaviour, enable the Capture + all cmd lists option - see that page for more details. This will capture all command lists + from the start of the program, ready for when you decide to capture a frame. This currently has a + fair overhead but it's something I want to improve in future + + +
+
+ Why does my capture say "Failed to capture frame: Uncapped Map()/Unmap()"? + + + If you start a Map() before a Present() call then call Unmap() after the Present() during the frame + RenderDoc wants to capture, RenderDoc won't have intercepted this call and so will fail to capture + this frame and try again next time. This usually only invalidates the first frame you try to capture, + but if you Map() many resources, and Unmap() them one by one in subsequent frames, you could hit this + failed capture scenario many times in a row. + + + Currently the only solution to this is to change the pattern of Map()/Unmap() such that they are + contained within a frame. + + +
+
+
diff --git a/docs/Features.aml b/docs/Features.aml new file mode 100644 index 0000000000..5682b238ba --- /dev/null +++ b/docs/Features.aml @@ -0,0 +1,88 @@ + + + + + + This page documents the current feature set of RenderDoc. This gives an overview of + what RenderDoc is capable of, and where it is in its development. You might also + be interested in the . + + + Currently RenderDoc is limited to Windows and D3D11 only. The plan is to increase this scope + as soon as possible, to include OpenGL and D3D9 and possibly other platforms. + + +
+ Current Windows+D3D11 Feature set + + + + Support for D3D11 and D3D11.1, Windows Vista and above. + Trimming capture - capture file only contains data necessary + for replaying the frame in question, not all textures & buffers ever created + in the lifetime of the app. + Optional network support. The main use case is capture & replay on + the same machine, but you can also attach over the network, and replay on a remote host. + Multiple frame capture with ability to open side-by-side to compare. + Event browsing, with standard perfmarker style tree. + Full D3D11 Pipeline display. + + Resources bound to the pipeline are trimmed to what is actually in use, + e.g. if a shader only references SRV slot 0, only SRV slot 0 will be displayed, even if + something is bound to slot 1. + Where available D3D11 debug names are displayed, along with reflection + data with the shader to clarify usage. + Structured buffers have their total element count displayed, and UAVs + also show the current structure count. + + + Shader source display (where possible - i.e. debug info available). + Timeline bar of the scene hierarchy. + + Displays scene left-to-right in time, event hierarchy top-to-bottom. + Not scaled based on time of each drawcall + Individual draw events are shown as dots when the tree is full expanded. + The currently selected resource in the texture viewer is highlighted below + individual drawcalls visible that use it - e.g. purple for 'used for write', green for 'used for read' + + + For each drawcall, a list of all API calls (state/resource setting) is available, with + each call optionally having a complete callstack to locate where it came from in-app. + Mesh buffer inspection and visualisation before/after vertex shader and at the end of the geometry + pipeline (after GS or DS, whichever is later). All views have arcball + and flycam controls, Projected data is not limited to the 2D viewport, RenderDoc attempts to unproject to allow viewing in + world-space. + 'Raw' buffer inspection, e.g. for UAVs, VBs or other buffers. Custom format can be set with + HLSL-lite syntax. + Buffer export to CSV or raw binary blob and texture saving to DDS. + Texture/render target viewer. + + List of textures/RTs in the frame, and filtering system. + Standard visualisation controls - zoom/fit to window, mip/face/slice selection. + RGBA channels or depth/stencil selection as appropriate for the type of resource. + Flexible 'range' selection tool, to set custom black/white points (default to 0 and 1). + Currently set RT/textures thumbnail strip - updates as you move through the frame. Follows the + currently selected pipeline slot as it changes, rather than remaining on the given texture. + Tabbed view for locking a view of a particular resource over time. + Pixel value picking. + Several debug overlays for render targets - Wireframe, Depth pass/fail, Stencil pass/fail, + Clipping (below black/above white points), NaN/-ve/INF highlight. + + + Custom visualisation shader support - e.g. decode custom packed formats or gbuffers. + Vertex, Pixel and Compute shader debugging. + Hot shader editing and replacement. + Auto-range fitting to min/max values in texture data, and histogram display. + Simple per-drawcall timings. + + + + Most of these should be intuitive if you've used a graphics debugger before. + + +
+ + + +
+
diff --git a/docs/Gotchas.aml b/docs/Gotchas.aml new file mode 100644 index 0000000000..e70ded81ce --- /dev/null +++ b/docs/Gotchas.aml @@ -0,0 +1,118 @@ + + + + + + + This page (hopefully) keeps up to date with any known issues, bugs, unimplemented + or partially unimplemented features. + + +
+ Things to Note + + + + + RenderDoc doesn't serialise out the initial contents of large graphics resources when it believes + that they will not be used in replay. e.g. a G-Buffer render target will not be saved out as it + is initialised and written to in-frame. This detection will go wrong if a render target is partially + written to but partially re-used, as RenderDoc will count this as initialised in-frame. This could + happen e.g. with an accumulating texture that is written to in the frame over the top of previous + results. + + You can override this behaviour by selecting 'Save All Initials' in the capture options before + capturing, as this will force RenderDoc to serialise out all initial contents regardless, at the cost + of larger logfiles and slightly slower replay app analysis. + + + + When capturing, only one swapchain is captured at any given time. + The in-app overlay renders to all swapchains but only one is considered "active" at + any given time - this can be cycled with the F11 key. The capture key will trigger + a capture at the next swap of the currently active swapchain. + + + RenderDoc relies on saving out the graphics command stream and replaying it + back at inspection time. This means if a bug is timing, machine or driver specific it is + in no way guaranteed to reproduce the bug on a different machine or driver. + RenderDoc has no dependencies on Visual Studio or the DirectX or Windows SDK, + and should run anywhere that a normal DirectX application will run - i.e. on + Artist or QA machines. The only requirement is the DirectX runtime to ensure D3DCompiler.dll + is available. + Currently RenderDoc also requires feature level 11+ hardware for the replay app, although + it can capture lower level applications. + + + If capturing callstacks from the app, ensure that dbghelp.dll is not loaded or + used by the application as this can easily interfere with RenderDoc's use and cause + undefined or empty results. More information on this can be found in + . + + + + RenderDoc can have a significant memory overhead, especially when a lot of resources are allocated + as shadow copies in main memory are created. + + If running in 32bit, it's possible that an application can run out of memory - particularly when + capturing, as this causes a significant spike in memory use. Improvements in memory management are planned + but for now it's recommended to use 64bit, or to limit captures to simple scenes wherever possible. + + + + + +
+
+ Partially Implemented Features + + + + + Deferred context & command list support will probably run into problems with non-trivial + use-cases. Let me know if you find a use-case that breaks, as I don't have many test programs! + + + + In the mesh viewer the Solid Shading option will only apply to the vertex input tab. + (or to the vertex output tab when tessellating). + + Similarly the options to draw "only this draw" or "since last clear" only work for the + vertex output/geometry output tabs. + + + + The "since last clear" option is likely to be slow when there are a lot of vertices being drawn. Use with care! + + + + + There is no pixel history at present. When pixel debugging you must select the + exact drawcall that you are interested in debugging. + + + + If a debugged pixel is overdrawn multiple times by the same drawcall RenderDoc will attempt + to pick the pixel that last passed the depth test, but this may not necessarily be entirely + accurate and in the case of blending there's no way currently to pick other pixels that passed + the depth test. + + + + The instruction set for shader debugging is not complete, and some instructions may be + unimplemented leading to incorrect results when debugging. + + + + The API Inspector shows essentially the raw serialised form of the commands in the log + file and so is not always very useful beyond showing which functions were called. There isn't + a way yet to see what views a particular ID corresponds to, and some of the parameters are + a little different from their official function signature. + + + + + +
+
+
diff --git a/docs/HowRenderDocWorks.aml b/docs/HowRenderDocWorks.aml new file mode 100644 index 0000000000..415bd6425b --- /dev/null +++ b/docs/HowRenderDocWorks.aml @@ -0,0 +1,104 @@ + + + + + RenderDoc works on very simple operating principles. This page outlines the basic + idea behind its functioning to give people a better idea of what's going on. + +
+ Capturing Logs + + Leaving aside the relatively uninteresting matter of injecting the RenderDoc DLL + and calling functions to configure it in the target process, we begin by looking at + how RenderDoc captures a logfile. + We will use D3D11 as an example of a driver for RenderDoc - the driver layer is + responsible both for faithfully capturing the logfile's API usage, as well as then + replaying and analysing it later. Essentially anything built on top of a driver layer + can be used agnostically of the API the application in question is using. + When the driver initialises it will hook into every entry point into the API + such that when application uses the API it passes through the driver wrapper. + In the case of D3D11 this is the D3D11CreateDevice and CreateDXGIFactory functions. + After this point all accesses to the API remain wrapped and the driver essentially + "man-in-the-middle"s between the application and the real API. + The driver initialises in an idle logging state. In this state it's up to the specific + implementation about what it serialises. As a general rule, creation and deletion type actions + are always serialised, and data-upload calls can sometimes be serialised. In some cases + the driver might choose to optimise out some of the data-upload calls and lazy initialise + the contents of some resources to save on idle overhead. + This serialised data is stored in-memory in a chunk-based representation. + Although it's up to the driver implementation it is generally refcounted such that + resources which end up becoming unbound and destroyed will have their memory overhead + deleted. + When the capture button is hit the driver will enter active logging upon the beginning + of the next frame. In this state every API call is serialised out in order and any initial + contents and states are saved. + Once the frame completes this frame capture is serialised to disk along with the in-memory + data for any resources that are referenced - by default resources which are not referenced are + not included in the log. + +
+
+ Replaying & Analysing Logs + + The replay process is ostensibly simple, but as with the capturing the devil is in the + details. + When replaying, the initial section of the log (up to the beginning of the frame) is read + and executed verbatim. Each resource created is mapped to the live version and vice versa so + later parts of the log can obtain the replayed representation of the original resource. + RenderDoc then does an initial pass over the captured frame. This allows us to build up a + list of all the 'drawcall' events, analyse dependencies and check which resources are used + at each drawcall for read, write, and so on. An internal tree is built up similar to what you + see in the Event Browser & API Viewer, as well as a linked list with the linear sequence + of drawcalls, since both representations are useful for iterating over the frame. + After this point most work is done in response to user actions. The basic building block + is replaying a partial frame. Most analysis tools are built out of either replaying up to the + current event, replaying up to the event - not including the current drawcall - and replaying + only the current drawcall. + Care is taken to minimise this as much as possible as this tends to be the slowest operation + given the overheads of serialisation and decoding the command stream. + When replaying from the beginning of a frame (and not a partial subset of the frame) the + initial states of all resources are applied, and the initial pipeline state is restored. Resources + which did not have a serialised initial state (e.g. gbuffer textures) have an initial state saved + before the first replay of the frame, and this is restored. That way you don't get effects 'leaking' + from later in a frame into an earlier point. + For example, let's assume the user has the 'depth test' overlay enabled, and selects a + new event. This is the order of events that occur for the Texture Viewer - other viewers follow + similar patterns, with a certain degree of sharing to reduce redundant replays: + + + + The log is replayed up to, but not including, the selected drawcall. After doing this + the current pipeline state and contents of all resources exactly match the state at the point + of this drawcall. + + + We then save a copy of the pristine depth buffer, save the current pipeline state, and + set the reversed depth test. Replacing the pixel shader with one that just writes red, we repeat + the drawcall to draw all the areas that fail the depth test. + + + Restoring the depth buffer and + repeating this with a pixel shader which writes green, we fill in the overlay. Both of these + renders happen to an off-screen buffer. + + + After restoring the pipeline state we finally replay the original drawcall to get the final + image. + + + When we want to re-paint the viewed texture (either regular painting, or if the user changed + a visualisation option which is just a constant buffer value) we bind the current render target as + a resource and render it to the texture viewer control, then render the overlay texture on top of + that. + + + + It's also worth mentioning that there is a bit of special handling for deferred contexts. + When you select an event in a command list, RenderDoc will replay as normal up to just before the + Execute() call, then it will replay all of the commands in the command list up to the currently + selected event on the immediate context. + + +
+
+
diff --git a/docs/HowTo/HowToCallstacks.aml b/docs/HowTo/HowToCallstacks.aml new file mode 100644 index 0000000000..1b44d81b1d --- /dev/null +++ b/docs/HowTo/HowToCallstacks.aml @@ -0,0 +1,80 @@ + + + + + This page gives an overview of the callstack-capturing capability in RenderDoc, + with details and important information about how to enable this. + +
+ Overview + + It can be useful when tracking down problems to have an idea of where each + API call came from. In any non-trivial program it's not necessarily obvious where + every single call was made, and giving a code-side callstack up to the API entry + point can pinpoint errant calls that are causing problems. + + + The callstack gathering uses dbghelp.dll. If you're using this + dll for some other debugging functionality in your app it is highly recommended that + you disable it, otherwise it can conflict and break RenderDoc's callstack capture. + + + + Callstack gathering has a reasonable overhead during capture and can slow things + down as well as cause more memory overhead. This can be mitigated with the 'only drawcall + callstacks' option that only lists callstacks for each drawcall event. + + + +
+
+ Launching Capture + + When launching a capture (as in ) + you should enable 'collect callstacks'. This will set RenderDoc to collect callstacks at every + API entry point that will be serialised into the log. + +Option enabled on the capture dialog. + + + If you wish to save some time & overhead you can then enable 'Only drawcall stacks'. + This will only collect callstacks when a drawcall-type API call is made. This can be a good-enough + trade off that still gets you the information you need, at a lower cost. After this point you can + run the program and capture as usual. + +
+
+ Replaying the capture + + When the capture is loaded in RenderDoc the callstacks will be available in the API + inspector. The bottom section of the dialog is a panel that can be expanded to show the + callstack. Initially this section will indicate that symbols need to be resolved. + +The callstack section expanded in API inspector. + + + To resolve the symbols referenced in the capture, go to the Tools menu and + select Resolve Symbols. If this menu option isn't available the callstacks + did not successfully capture in the logfile. + The resolving symbols process may take some time the first few instances you use it, + as it may have to download symbols from the Microsoft symbol server. Each module that is loaded + in the application at the time of capture will be saved and its symbols searched for. + By default a symbol server will be used, as well as a few default locations such as the + location indicated in the PE metadata (i.e. the original build location). If a pdb cannot be found + you will be prompted for the location of the pdb, and this new location will then be remembered + for subsequent pdbs. + +Prompt to locate a PDB that cannot be found. + + + If a PDB cannot be located then you have the option of permanently ignoring that PDB. + This can be useful for third party libraries for which no PDB will ever be available. If + you don't ignore the PDB you will be prompted to locate it the next time you open a log + that references it. + Once the symbols have been successfully resolved the callstack section of the API + inspector will contain any callstack that was collected for the given drawcall or API + call. You can select and copy any levels and paste them elsewhere if you wish. + +
+
+
diff --git a/docs/HowTo/HowToCaptureLog.aml b/docs/HowTo/HowToCaptureLog.aml new file mode 100644 index 0000000000..4e47d1b7d3 --- /dev/null +++ b/docs/HowTo/HowToCaptureLog.aml @@ -0,0 +1,88 @@ + + + + + Capturing logfiles is the starting point to using RenderDoc. Although the + basic use is very simple, there are various customisations and more advanced uses. + More information on these can be found in the details of the + window. + +
+ Capturing logs + + The basic process of capturing logs is fairly straightforward. + Opening the capture window from the menus via File -> Capture Log, the + typical capture setup simply requires you to enter the executable location. + By default the working directory remains empty and defaults to the directory + that contains the executable location. + +Capturing a logfile specifying its executable path and command line. + + + Likewise, the default options generally work well for most situations, however + there are a few common options to customise: + + + Allow Fullscreen/Allow VSync aid in debugging by preventing the app from switching + into fullscreen (or vsynced) display modes, which makes them easier to attach to from a debugger + on the same computer. + Seconds attach delay causes RenderDoc to pause for a certain number of seconds after + launching the process to allow you to attach in the debugger - so that the debugger can be present + to catch any problems from the beginning of the application, in case there is an issue very early + in initialisation. + Collect callstacks allows you to get callstacks at the site of each API. There are + more details available in . + + + +
+
+ Attaching to a Process + + It is possible to attach to an already running process. By selecting the "Attach to Process" + entry in the File menu, the capture dialog will modify to list the running processes rather than + asking for an executable and command line parameters. + This can be useful if launching your application from a single exe is non-trivial and it's + easier to attach to the process after it has been launched. + +Attaching to a selected existing process. + + + + + The important thing to note about attaching is that RenderDoc can only attach to processes that + have not initialised or used the target API. If this is the case RenderDoc can + insert its hooks before any use of the API and work as normal. If the API has been used or initialised + the results are undefined and likely RenderDoc will simply not function as it's too late to hook in. + + + + If RenderDoc is not running as administrator, it cannot attach to processes that are running with + elevated permissions. In this case you can either run RenderDoc as administrator (not recommended unless + necessary), or re-run the process as the normal user running RenderDoc. + + + +
+
+ Capture setting files + + Commonly in development, the capture parameters don't change. In fact most likely the + same application or couple of applications are launched in exactly the same way repeatedly + as development iterates. + To make this process easier RenderDoc supports saving and loading configuration sets to a + file. While on the capture dialog, click 'Save' to save to a .cap file which contains both the + executable, working directory and command line - as well as the options that are selected. + This .cap file can be executed when RenderDoc's file associations are set up, and RenderDoc will + load this file and present you with the capture dialog on startup. + You can also use the "Auto start" option - when this option is enabled then a .cap file + will immediately launch the program when it is loaded. This can allow you to configure a .cap + which will open RenderDoc and launch the target application with the pre-configured settings + in one click. If you wish to disable this, just uncheck the option and re-save to the same .cap file. + +
+ + + +
+
\ No newline at end of file diff --git a/docs/HowTo/HowToCustomShader.aml b/docs/HowTo/HowToCustomShader.aml new file mode 100644 index 0000000000..34c3592835 --- /dev/null +++ b/docs/HowTo/HowToCustomShader.aml @@ -0,0 +1,169 @@ + + + + + This page details how to set up a custom shader for visualisation. This can be used + in the to unpack or decode complex + formats, or simply apply a custom complex transformation to the image beyond the default controls. + +
+ Introduction + + The basic process of setting up the custom shader involves writing a .hlsl file that + will be compiled and used by RenderDoc. + There are several special global variables that can be specified and will + be filled in with values by RenderDoc. + Your pixel shader defines an operation that transforms the raw value from the input + texture into a value that will then be displayed by the texture viewer. The usual texture + viewer controls for range adaption and channels will still be available on the resulting + texture. + Multisampled textures will be resolved before being passed to your function. + Depth and stencil textures will be bound separately and passed as multisampled resources. + To set up your shader, it's recommended that you use the UI defined in the documentation for the + , but you can manually create a .hlsl file in + %APPDATA%\RenderDoc\. The file must contain an hlsl function main() that + returns float4, and uses any of the below inputs. These shaders are loaded when RenderDoc + loads a logfile, and RenderDoc watches for any changes to the files (either externally or in + the shader editor in RenderDoc) and automatically reloads them. + +
+
+ Predefined inputs + + There are several pre-defined inputs that can either be taken as parameters to + the shader entry point, or defined as global variables with a particular name that will + then be filled in. There are also definitions for the different type of input textures. + + + Type and capitalisation is important for these variables, so ensure you use the right + declaration! + + + + + + Input + Explanation + + + + UV co-ordinates + + +float4 main(float4 pos : SV_Position, float4 uv : TEXCOORD0) : SV_Target0 +{ + return 1; +} + +This input is defined as two parameters to the shader entry point. The first defines the usual +SV_Position system semantic, and the first two components of the second TEXCOORD0 parameter gives UV +co-ordinates from 0 to 1 in each dimension over the size of the texture (or texture slice). + + + You must bind these parameters like this in this order to ensure the linkage with the + vertex shader matches. + + + + + Texture dimensions + + +uint4 RENDERDOC_TexDim; + +This variable will be filled out with the following values: + + + .x = Width + .y = Height (if 2D or 3D) + .z = Depth if 3D or array size if an array + .w = Number of mip levels + + + + + + Selected Mip level + + +uint RENDERDOC_SelectedMip; + +This variable will be filled out with the selected mip level in the UI. + + + Current texture type + + +uint RENDERDOC_TextureType; + +This variable will be set to a given integer value, depending on the type of + the current texture being displayed. This can be used to sample from the correct resource. + + + 1D texture + 2D texture + 3D texture + Depth + Depth + Stencil + Depth (Multisampled) + Depth + Stencil (Multisampled) + + + + + + Samplers + + +SamplerState pointSampler : register(s0); +SamplerState linearSampler : register(s1); + +These samplers are provided to allow you to sample from the resource + as opposed to doing straight loads. They are bound by slot and not by variable name - + so this means you can name them as you wish but you must specify the register binding + explicitly. + + + Resources + + +Texture1DArray<float4> texDisplayTex1DArray : register(t1); +Texture2DArray<float4> texDisplayTex2DArray : register(t2); +Texture3D<float4> texDisplayTex3D : register(t3); +Texture2DArray<float2> texDisplayTexDepthArray : register(t4); +Texture2DArray<uint2> texDisplayTexStencilArray : register(t5); +Texture2DMSArray<float2> texDisplayTexDepthMSArray : register(t6); +Texture2DMSArray<uint2> texDisplayTexStencilMSArray : register(t7); +Texture2DArray<float4> texDisplayTexCubeArray : register(t8); + +Texture1DArray<uint4> texDisplayUIntTex1DArray : register(t11); +Texture2DArray<uint4> texDisplayUIntTex2DArray : register(t12); +Texture3D<uint4> texDisplayUIntTex3D : register(t13); + +Texture1DArray<int4> texDisplayIntTex1DArray : register(t21); +Texture2DArray<int4> texDisplayIntTex2DArray : register(t22); +Texture3D<int4> texDisplayIntTex3D : register(t23); + +These resources are bound sparsely with the appropriate type for the + current texture. With a couple of exceptions there will only be one texture bound + at any one time. + When a cubemap texture is bound, it is bound both to the 2D Array as well + as the Cube Array. If a depth-stencil texture has both components, the relevant depth and + stencil resources will both be bound at once. + To determine which resource to sample from you can use the RENDERDOC_TexType variable + above. + Usually the float textures are used, but for unsigned and signed integer formats, + the relevant integer resources are used. + As with the samplers, these textures are bound by slot and not by name, so while + you are free to name the variables as you wish, you must bind them explicitly to the + slots listed here. + +
+ +
+
+ + + +
+
diff --git a/docs/HowTo/HowToDebugShader.aml b/docs/HowTo/HowToDebugShader.aml new file mode 100644 index 0000000000..a13ead830f --- /dev/null +++ b/docs/HowTo/HowToDebugShader.aml @@ -0,0 +1,157 @@ + + + + + This page goes into detail about how to set up your captures for debugging + shaders, as well as how to debug a shader and what controls are available. + +
+ Including debug info in shaders + + For the most part at least some debug information is included with shaders unless + it is being explicitly stripped out at some point. There is usually an option to also + include additional debug information - such as original source code in a high-level language. + The exact process varies by API, but for D3D11 the flag /Zi to fxc or the equivalent + flag to D3DCompile() will include additional debugging information, and /Qstrip_debug + and /Qstrip_reflection will remove reflection information that can be useful - such as + the names of variables in constant buffers. + +
+
+ Debugging a vertex + + Vertex debugging is invoked from the mesh viewer. With the mesh viewer open you can + select the input vertex you wish to debug. + When a vertex is selected in the mesh data for the vertex input it will be highlighted + along with the primitive it is part of in the mesh display, provided the display is in + vertex input mode. + Either right click and choose debug vertex + from the context menu, or click on the debug icon in the toolbar. + +Launching vertex debugging from the mesh viewer. + + + From here the debugger will open with the vertex shader in the shader debugger. + The inputs are automatically filled in from the mesh data. + + + Geometry and tessellation shaders are not yet debuggable. + + + +
+
+ Debugging a Pixel + + Pixel debugging is launched from the texture viewer. For more details on selecting + the pixel to debug see . + When a given pixel is selected you can either choose the debug icon on the + toolbar, + or click the debug button underneath the pixel context. Each of these will + launch the shader viewer with the selected pixel being debugged. The + inputs to the pixel will be automatically filled in. + There are currently several things to note while pixel debugging: + + + There is no pixel history at the moment, so the drawcall that you wish to debug + must be selected as the current even when you attempt to debug the pixel. + If a drawcall overdraws the same pixel several times then the results of debugging + may not be accurate - RenderDoc attempts to pick the fragment that last passed the depth test but this + isn't guaranteed and may not be perfect. There's also no way to choose a different fragment in the case + of blending being used, or sample-frequency rendering. + + + +
+
+ Debugging a Compute thread + + To debug a compute thread simply go to the compute shader section of the pipeline state + viewer and enter the group and thread ID of the thread you would like to debug. This thread + will be debugged in isolation as with any other shader invocation. + This means there can be no synchronisation with any other compute thread running and + the debugging will run from start to finish as if no other thread had run. + + This feature is highly experimental and is provided with no guarantees + yet! It may work on simple shaders which is why it is available. + + + +
+
+ Debugging Controls + + When debugging, at the moment the controls are fairly basic. + +Controls for stepping through shaders. + + + The toolbar at the top gives controls for the program flow through the + shader. Run and + Run Backward simply + run from the current position all the way + through to the end or start of the program respectively. + The keyboard shortcuts for these controls are F5 and + Shift-F5 respectively. + You can set a breakpoint by pressing F9 (this will also remove a breakpoint that is + already there). When running in each direction or to cursor (see below) if execution hits + a breakpoint it will stop. + The other controls allow for single stepping and limited running. + Step forward + will execute the current instruction and continue to the next - this includes following + any flow control statements such as jumps, loops, etc. + Step backwards + will jump back to whichever instruction lead to the current instruction. + This does not necessarily mean the previous instruction in the program as it could be + the destination of a jump. Stepping forwards and stepping backwards will always reverse + each other. The shortcuts for these commands are F10 and Shift-F10 + The final control is to + Run to the cursor. + This will perform in a similar fashion + to the "Run" command, but when it reaches the line that the cursor highlights it will stop + and pause execution. It will also stop if it reaches the end of the shader. + + + The highlighted instruction at any given point indicates the next + instruction to be executed - not the instruction that was just executed. + + + There is also a toggle available to control the 'default' interpretation of temporary + register values - float or int. Since registers are typeless typically they are interpreted as + float values, but with this toggle you can toggle them to be interpreted as integers. + +
+
+ Debugging Displays + + Currently there is only a very basic display when debugging shaders. + There are two windows that display different types of registers. The constants window + will display input and constant buffer registers that are immutable throughout execution. + This will also list registers for resources and samplers (with basic format information). + +Constant, input and resource registers. + + + The other window will contain variable/mutable registers. These contain temporaries that + are typically allocated up front and will update as you step through the execution of the shader. + This window also contains the output registers. + +Variable registers - temporaries and outputs. + + + The final window is initially empty but can be filled out as needed. This shows custom watch + expressions and their values. Here you can write any expression involving an input, temporary or + output register along with a swizzle and typecast. + Swizzles follow the standard hlsl rules - .[xyzw] or .[rgba] in any permutation or repetition + will show those channels. + The custom typecast can be any of ,x ,i ,d ,f ,u to display the register as hex, signed integer, + double, float or unsigned respectively. + +Watch window - custom register expressions evaluated. + + + +
+ +
+
\ No newline at end of file diff --git a/docs/HowTo/HowToEditShader.aml b/docs/HowTo/HowToEditShader.aml new file mode 100644 index 0000000000..2db57e1573 --- /dev/null +++ b/docs/HowTo/HowToEditShader.aml @@ -0,0 +1,73 @@ + + + + + This page details how to edit shaders. This applies both to + custom visualisation shaders for the + , but can also be used to temporarily replace or + edit a shader used in the actual scene. + +
+ How to edit a custom shader + + Custom visualisation shaders allow you to define + your own transformation on any texture you're viewing before it is displayed. Mostly this is useful for decoding + packed or custom-format data, or displaying some data in a more visually intuitive fashion. + These shaders live as .hlsl files in %APPDATA%\RenderDoc\, and can be edited in your + editor of choice, any changes saved will be reloaded. Note however that there is currently no way to see the + compile warnings or errors produced. This is probably best for when you have an existing shader to drop-in. + To edit a shader inside RenderDoc simply click the edit button + when you have selected your custom shader + for use. This will launch a new window with the custom shader and any changes you make to this shader will be + saved to the .hlsl file and compiled and reflected in the texture viewer as long as you have that custom shader + selected. + +
+
+ How to edit a scene shader + + RenderDoc allows you to edit a shader used in the capture and make changes to it and see the effects in real-time. + To launch the shader editor, go to the pipeline stage you wish to change in the + windows, and click on the edit button + next to the shader. + Note: this feature is intended to be used when shader debug info is available and the hlsl source can be used. + If the hlsl isn't available, RenderDoc will generate a stub function with the input and output signatures available from + the reflection data that you can fill in if you wish. + Any changes to the shader will affect any drawcall using this shader, not just the currently-selected drawcall. + The changes will persist until the edit window is closed. + + + One unfortunate artifact of how the shader debug info works, not all #included hlsl files will come along with the debug info, + only those files that contain compiled code. RenderDoc automatically replaces any #includes + to missing files with just an empty comment, but unfortunately this can lead to compile errors in unused code. + This can also interact badly with another artifact - macro definitions passed directly to the compiler are not + included in the debug info and so RenderDoc can't include them when recompiling. If you rely on any defines, you + will need to add them manually to the top of your root hlsl file. + + + +
+
+ Using the built-in shader editor + + When you have launched the shader editor, the main window will be filled with the hlsl of your shader. + In here you can make edits and changes with the basic controls and syntax highlighting available with the + Scintilla editor. + To compile the shader and apply your changes, either click the save button in the toolbar or press + Ctrl-S. This will compile the shader and apply it, any warnings and errors will be added to the box below + the main source. + Custom shaders are built with a simple set of flags, any shaders from the scene will be compiled with + the flags that were originally passed to the compiler. + + + If there are errors compiling a visualisation shader, it will be removed from the texture viewer and normal RGB display + will be used until you fix the error. + + + In addition, when editing visualisation shaders a button will be available to insert several useful snippets + for custom shaders with the pre-defined variables that can be bound. For more detail, see + + +
+
+
\ No newline at end of file diff --git a/docs/HowTo/HowToFindTexture.aml b/docs/HowTo/HowToFindTexture.aml new file mode 100644 index 0000000000..bf67ed96d8 --- /dev/null +++ b/docs/HowTo/HowToFindTexture.aml @@ -0,0 +1,85 @@ + + + + + This page documents how to annotate your resources with user-friendly names + to make it easier to follow use of them throughout the frame, as well as the functions + for finding and following textures by name rather than by usage. + +
+ Annotating resources with names + + It is much easier to browse and debug frames when the resources are + given meaningful names - along with including + debugging information in shaders and + marking up the frame with + hierarchical user-defined regions. + The way this is done varies by API. In D3D11 the resource is named in this way: + + +// Creating an example resource - a 2D Texture. +ID3D11Texture2D *tex2d = NULL; +d3dDevice->CreateTexture2D(&descriptor, NULL, &tex2d); + +// Give the buffer a useful name +tex2d->SetPrivateData(WKPDID_D3DDebugObjectName, "Example Texture", sizeof("Example Texture")); + + + When this texture is bound to the pipeline it will be listed like so: + +The example texture bound with name displayed. + + + + In a similar way any other resource can be named and this will be useful throughout + the rest of the analysis. + +
+
+ Texture list in Texture Viewer + + In the texture viewer you can open a filterable list of all textures in the capture. + This can be opened with the texture list icon + . When clicked on + this will open a sidebar on the texture viewer that lists all textures. + +The sidebar showing the list of textures + + + This list of textures can be filtered by a custom string which will narrow the list + of textures displayed, or simply by their creation flags as either a render target or + a texture. + When selecting and opening one of the textures from here, a new tab is opened in + the texture viewer that follows that texture. + +
+
+ Locked tab of a Texture + + By default the tab open in the texture viewer follows whichever pipeline slot is currently + selected. When a new event is selected this tab can display a new texture if the contents of that + slot has changed. + If you want to follow a particular texture even as it becomes unbound or moves from output + to input and vice versa, you can open a new locked tab that will stay consistently on this texture. + +Default tab following pipeline slot vs Locked tab. + + + This can be done by locating the texture by name as above, then clicking on the entry + in the list. This will open up a new tab for this texture which will not change regardless of + the current pipeline state, or current event. + Opening a texture from the pipeline state viewer + () + will also open a new locked tab for the texture in question. You can also open a new locked tab by + right clicking on the texture thumbnail while it is currently bound. + +Opening a new locked tab for a texture. + + + +
+ + + +
+
diff --git a/docs/HowTo/HowToInspectPixel.aml b/docs/HowTo/HowToInspectPixel.aml new file mode 100644 index 0000000000..709fa95925 --- /dev/null +++ b/docs/HowTo/HowToInspectPixel.aml @@ -0,0 +1,67 @@ + + + + + When in the texture viewer you can inspect the pixel values to obtain the exact + contents of any pixel in the texture. + +
+ Selecting appropriate subresource + + More details can be found in the + page, but the first step is to select the appropriate subresource - array element, cubemap face + or mip slice. + The values that are picked out of the texture are always exact values, and will not be + affected by the currently selected channels or range adaption control. + +
+
+ Picking a Pixel Value + + At any point while hovering over the texture the status bar contains the current + pixel location that the cursor is hovering over, as well as a basic colour swatch to give + some indication of where you are. + +The status bar showing position and colour + + + When the right mouse button is pressed, the currently hovered pixel value will be displayed + with the current float precision settings - for more information on how to tune these look at + the window reference for the . + For depth textures the depth and stencil values will be displayed separately. The stencil + value (as with any integer formatted texture) will be displayed as an integer. + +The value of a pixel that has been picked + + + If the right mouse button is just clicked, the picked pixel value will remain with the same + value as the mouse moves. If you hold the right mouse button and drag, it will update as the mouse + moves to allow some amount of refinement. + To make fine adjustments by a single pixel at a time, it's easiest to use the arrow keys + on the keyboard. Pressing these will shift the picked location by a single pixel in each + direction. + +
+
+ Pixel Context Display + + Whenever a pixel is picked, the pixel context display is updated to surround the currently + selected pixel. This dialog is by default docked in the bottom right of the texture viewer, adjacent + to the thumbnail strip. + +The zoomed in context around the pixel currently selected + + + This context display shows a zoomed in view of the texture around the area that you've selected + so that it's easier to make small adjustments without zooming in and losing a sense of the whole + texture. + The pixel context viewer can also allow you to launch pixel debugging. Once a pixel is picked + the button below the context is activated which will launch the shader debugger. More information + about this is available: . + +
+ + + +
+
\ No newline at end of file diff --git a/docs/HowTo/HowToViewDetails.aml b/docs/HowTo/HowToViewDetails.aml new file mode 100644 index 0000000000..83273cf594 --- /dev/null +++ b/docs/HowTo/HowToViewDetails.aml @@ -0,0 +1,95 @@ + + + + + + The pipeline state viewer allows you to view more details of given resources + that are bound to the pipeline. The go arrow + is a sign that more + details for this resource are available. + +
+ Viewing Shaders + + Each shader stage that is active on the pipeline can be expanded to see both the + high-level shader language and the low-level disassembly. At the top of the pipeline + stage there is a box showing the currently bound shader - by its entry point if known. + +Box showing the currently used shader. + + + Much of the information that is available from the shader is only available + when debugging information is made available. + More details are available + + Each file passed to the compiler for this the shader is shown with simple syntax + highlighting, as well as the disassembly generated from the bytecode itself. + If available, the reflection data from the shader debugging information will be used + in other areas of the pipeline state viewer. It will be used for naming texture slots, + showing which resources that are bound are to be used in the shader, as well as showing + the names of any constants that are used in the shader. + When this shader reflection information is available it will be integrated into + the disassembly to make it easier to read. + Note from here you can also live-edit a shader by clicking the edit button + . If debug info + isn't available to provide HLSL, a basic stub function with the input & output + signatures but no body will be created. + +
+
+ Viewing Textures + + The is the primary way of + viewing details of textures, so this section concerns itself with how textures are displayed + in other parts of the UI, and how to open a texture in the texture viewer. More details can + be found in . + A texture that is bound to the pipeline as a resource or output the relevant section + of the pipeline will display their dimensions and format. In each place the go arrow + will indicate that a new + locked tab can be opened up in the texture viewer. + In addition to opening a new view of the texture, the timeline bar will also show + the usage of this texture - a green triangle will indicate a place where the texture is + read from, and a purple triangle indicates a writing operation. These triangles don't necessarily + correspond 1:1 with the event - more details are available on the + page. + +
+
+ Viewing Buffers + + More details on this section are available on the + page. + When opened either from the input layouts or from the 'Window' menu, the buffer viewer + opens up in the mesh viewer mode. This is a specialisation of the buffer viewer which will + show a 3D display of the mesh represented, as well as viewing the mesh buffers at different + points in the pipeline. + In the general case, buffers bound to the pipeline can be opened as a raw buffer viewer. + This will open up a view of the buffer similar to the mesh viewer, but with a completely + customisable buffer layout. + By default if the buffer is bound to the pipeline with a pre-existing structure that can + be reflected from the shader then this will be the default, otherwise the default layout will be + 4 32bit unsigned integers per element. + This layout can be customised by entering a format in a simple style that mimics defining + a structure that outlines a single element in the buffer. + +Customising the layout of the buffer by defining a structure. + + + +
+
+ Viewing Constant Buffers + + Constant buffers can be viewed by clicking on their Go Arrow + . This will open up a new docked section + to the right of the pipeline state viewer that tracks that constant buffer slot. + Whenever this shader slot has a constant buffer in it, + both the constant names and types as well as values will be displayed. + +An updating preview of the contents of this constant buffer. + + + +
+
+
\ No newline at end of file diff --git a/docs/Introduction.aml b/docs/Introduction.aml new file mode 100644 index 0000000000..441f32403d --- /dev/null +++ b/docs/Introduction.aml @@ -0,0 +1,126 @@ + + + + + + + Welcome to RenderDoc - a graphics debugger, currently available for + D3D11 development on windows. + + + + + This document serves primarily as reference guide, introductory document + and explanation of which features are available in RenderDoc and how to + best use them. + + +
+ License + + + RenderDoc is released under the MIT license, so there are no restrictions on your use of it either + commercial or non-commercial. + + + This license will also not change when the source is released, so any source modifications will be + equally unrestricted. + + + Details of the licenses of third party software used in RenderDoc are included in the LICENSE file + in the RenderDoc directory as well as in the . + + +
+
+ How to browse this documentation + + + If you just want to dive straight in and learn how to get started using + RenderDoc consider looking at the + section which gives a simple introduction on how to get started. Afterwards + there are reference pages on each of the windows available in RenderDoc which + can be referred to as you use the program, or skimmed to get a feel for the functionality + available. + + + Those of you familiar with other graphics debuggers will likely find much + of RenderDoc recognisable, you might want to check out the + , + , + + or browse the How Do I... ? sections which detail how + some common tasks are accomplished. + + + Regardless of your experience or patience for documentation it's recommended + that you read the + as this details known bugs and current limitations of the program. + + +
+
+ Important notes + + + + RenderDoc is not yet bug free! It is pretty stable but you will still likely encounter + bugs depending on your use case. I am always happy to spend time + to fix them and I can work with you even if you cannot share any details about your project. Get + in touch (see below) and I will actively fix your bug! + On the other side of the coin, please do give feedback when RenderDoc works for you and + request features that would make your life easier or improve your workflow. + There are a few common issues you might run into, so if you have any problems check the + , or the +issues page on github +Issues on github +https://github.com/baldurk/renderdoc/issues + to see if it's been reported. + + + +
+
+ Contact info, Feedback, Bug reports + + + If you want to get in touch with any feature requests, suggestions, comments etc + then feel free to contact me: Baldur Contact. + + + Bug reports can be submitted directly via email, or also on the +github repository +Issues on github +https://github.com/baldurk/renderdoc/issues + + + + There are also +forums +Forums on CryDev.net +http://www.crydev.net/viewforum.php?f=379 + + where you can post on and get help from others who are using + RenderDoc. + + +
+ + + RenderDoc Homepage + Go to the RenderDoc Homepage + http://renderdoc.org/ + + + Forums on CryDev.net + Go to the forums on CryDev.net + http://www.crydev.net/viewforum.php?f=379 + + + + +
+
diff --git a/docs/Layout.content b/docs/Layout.content new file mode 100644 index 0000000000..81bf97750e --- /dev/null +++ b/docs/Layout.content @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/QuickStart.aml b/docs/QuickStart.aml new file mode 100644 index 0000000000..799f8cd2c7 --- /dev/null +++ b/docs/QuickStart.aml @@ -0,0 +1,254 @@ + + + + + + + This document serves as a brief introduction to how to use RenderDoc to capture and + analyse your application. It doesn't go into much detail about exactly what functionality + is available for digging into things, as this can be found elsewhere. Instead it focuses + on just the workflow from start to finish and roughly where to look for different things. + + + For this tutorial we will be using a slightly modified version of the CascadedShadowMaps + sample from the Microsoft DirectX SDK (June 2010). + + +
+ Capturing a log + + To capture a log, begin by opening the File menu and selecting Capture Log. By default + this will open a new docked window where you can configure different settings that will be + used when capturing. + + The defaults work pretty well in most situations, so you can just either + browse to or drag in your exe into the Executable box. If the working directory box is + empty then the Executable's directory will be used. Enter any command line you may need + and click 'Capture' to launch the application with RenderDoc. + More details of the specific options and their functionality can be found in + the details page for the Capture Window. + + + It's best to choose the edition of RenderDoc to match your OS - 64-bit for Windows x64 and vice-versa + You can only capture a 64-bit process with a 64-bit + build of RenderDoc. A 32-bit process can be captured by any build of RenderDoc. + + +
+
+ RenderDoc in-app + + + RenderDoc has a fairly minimal in-app overlay, just to indicate that RenderDoc has successfully + loaded and is ready to capture a frame. + + + When ready, press the Capture Key (F12 or Print Screen) + and the next frame after the keypress will be captured, and this will show up on the overlay + to let you know that a frame has been successfully saved. + + + + When the application exits, if you captured a log it will automatically start to open in + the RenderDoc UI. If you didn't capture a log then nothing will happen and the RenderDoc UI will be + back as it was when you clicked Capture. + + + If you made multiple captures you will see a thumbnail list that allows you to open (in the current + instance or a new instance to compare side-by-side), save and delete them as you wish. You can + also access this view while the program is still running, see for more information on taking + multiple frame captures. Note however that for the simple use-case, you don't need to worry about this! + + +
+
+ RenderDoc layout + + + RenderDoc's layout can be customised fairly heavily so this section will only cover the default layout. + We'll go over the windows that are open by default and how each can be used in analysing your + program. + + + Each of these windows has a section that is much more in depth and gives details about every + function and feature, for the more complex windows such as the texture viewer you may well wish to + skim these to get an idea of what is available and use them as reference in the future. + + +
+ Texture Viewer + + + More details can be found on the page. + The texture viewer does pretty much what you'd expect - it allows you to inspect textures + and render targets in your application. + There are various visualisation controls that allow you to select different channels, mip levels + or other aspects of the texture, and more detail is available in the above page. Here we'll just + touch on the highlights: + + + The thumbnail strip (by default to the right) lists either the output targets, or + shader inputs bound and used at present. Selecting each of these (the red outline on the thumbnail indicating + which is selected) will follow whatever resource is bound to that slot as you browse through the scene. + E.g. if you select render target 0 then the texture display will update to show the currently bound render + target 0 regardless of which texture that is. If the slot you are following becomes unbound or unused, the previous + texture will still be displayed up until you select a different pipeline slot, or the slot is bound again. + Unbound texture slots show up with Unbound listed under their thumbnail. + To open a specific texture and watch it even as it changes slots or becomes unbound, you can open it in a new + locked tab. Right click on the thumbnail and 'open in new locked tab', or + open it by name + + The format and dimensions of the texture are displayed on the status bar just below the texture + display itself. + Also on this status bar you can see the current pixel co-ordinate that you are hovering over, as well as + the 'picked' pixel value which can be inspected by right clicking anywhere on the texture display. + + Further to this, there is a small zoomed section of context around the last picked pixel available + in the bottom right of the texture viewer window. From here you can also launch the pixel debugger, with the provisos + detailed in . + + The last thing we will highlight is the range control. This is a fairly flexible tool that allows + you to adjust the visible range in the image. This is particular useful when viewing HDR images with a range outside + of [0, 1]. + To use the range control you can drag the white and black points to make fine adjustments or type values to change the values + of the white and black points (by default 0 and 1 respectively). There are also some useful controls to the right of + the range control itself, which are detailed again in the page. + + + + + + +
+ +
+ Event Browser + + + More details can be found on the page. + The Event Browser is the primary method of stepping through the frame and browsing + the events that occurred within. The first column EID (Event ID) indicates which event or API call this was + in the frame, chronologically. Events which are listed here are generally output/draw type events, including + Clears. Copy and Map type calls are not included and are available in the API Calls view (see below). + The columns can be customised and reordered, the + select columns button (or right-click) + will allow you to choose which columns are displayed. + Standard performance markers are available and create the hierarchy/labels as you would expect. + These can be expanded or collapsed and keyboard browsing is available through normal controls - + left and right go higher or lower in the hierarchy, and up and down goes up and down through siblings. + The 'current' event - i.e. the event at which we are inspecting the graphics state - is highlighted + with a green Flag and the row is highlighted. + As any row is selected it immediately becomes the new current event. + While the Event Browser is selected, you can press the shortcut keys CTRL-F or + CTRL-G to find + or jump to a given EID + respectively. + +
+ +
+ API Inspector + + + More details can be found on the page. + The API Calls window updates as a new event is selected. It shows the individual API calls + and their parameters (in some fashion) between the previous and current event. The bottom entry + in this list always corresponds to the event that is currently selected, and each row can be expanded + to show the parameters that were passed to that API call. + At the bottom of the window is an optional expandable section which shows the callstack (if + available and recorded) from the application code into the API function. + In order to view these callstacks you must first resolve the symbols recorded with the log. + To do this click on Resolve Symbols under the Tools menu. More + details on this process can be found in the guide: + +
+ +
+ Timeline Bar + + + More details can be found on the page. + The timeline bar is essentially an alternate view of the frame, with the horizontal axis + being time in the frame. The scale however is non-linear and is weighted to try and show each + section of the frame equally and visibly, rather than scaling by duration. + The frame marker hierarchy is top-down in this case, and can be expanded or collapsed by + clicking on each section. In this image, Cascades and Cascade 1 are both expanded, but the other + sections remain collapsed. Each drawcall is rendered as a blue circle underneath the section of + the hierarchy that it is a child of. The current drawcall (if visible) is rendered as a green + circle and there are two vertical bars - red for the current mouse highlight, and light grey for + the current drawcall, so it is visible regardless of the hierarchy expansion. + When the currently selected texture is used in the frame, each drawcall that references + it draws a marker below the bar. A purple marker indicates that the drawcall at that point is + writing to the texture, and a green marker indicates that it is reading. If the markers are + too close together they will space themselves to be readable and will not necessarily line up + to a particular drawcall unless you zoom in. + This can be a very useful tool to trace data through a frame, as well as highlighting potential + redundancy or errors if a target is being written to where it should not. + +
+ +
+ Pipeline State + + + More details can be found on the page. + The Pipeline State window is perhaps the most detailed but also the simplest to understand. + This window simply lists every stateful aspect of the graphics pipeline and what value or object + is present at the current event. + By default the pipeline will not contain empty or unused entries - i.e. if a shader only reads + from resources 0 and 1, even if something is bound to slot 2 it will not be displayed. Likewise say + slots 3-128 are empty - they will also not + be displayed. This behaviour can be modified by the Show Disabled Items and + Show Empty Items toggles on the toolbar. Show Disabled will show slot 2 even if + the shader does not read from it. Show Empty will show slots 3-128. + The most important thing to note is that most things in the sections for each pipeline stage + can be expanded to view in more detail. Look for the Go Icon + to indicate that a more detailed + view is available. Typically this will mean for shaders the shader source/disassembly will be opened, for + texture-type resources the texture viewer will open a new tab for that resource, and for buffers it will + open either the Mesh Output window, a raw view of that buffer, or a popup with the constant contents - + depending on where the buffer is bound. + + For more details, check out the how-to: + +
+ +
+ Mesh Output + + + More details can be found on the page. + Mesh Output allows you to inspect the geometry data as it passes through the pipeline. + Both raw data in a grid view and 3D inspection is possible. The tabs in the preview window allow you to + choose at which part of the pipeline you'd like to visualise the data. + When in the VS Input tab (or VS Output if tessellating), you can select to solid shader the object with + either flat shading or a UV Co-ordinate/Colour shading, which can be useful for visually inspecting + the geometry data. + When in the VS/GS/DS Output tabs there is the option to show the context leading up to this + drawcall by showing everything since the last clear. The default view (which you can reset to with the + reset button ) shows the camera at the + view origin looking out through the viewport. By default the output attempts to guess a perspective matrix + from the output data, but this can be refined or changed to an orthographic view by opening up the options + and entering more accurate or corrected values. + +
+
+
+
+ +
+ Closing Notes + + + Obviously what you accomplish in the program will vary a lot by what you need to investigate, but + hopefully this gives you an overview of the functionality available. There are many more detailed + features that are available, and the rest of this help will aid you in finding those. + + + It is probably a good idea to check out the + page which lists several useful notes that aren't obvious but might save you a lot of time. + + +
+
+
diff --git a/docs/Resources.items b/docs/Resources.items new file mode 100644 index 0000000000..d64955b475 --- /dev/null +++ b/docs/Resources.items @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/TheFuture.aml b/docs/TheFuture.aml new file mode 100644 index 0000000000..d8de49f476 --- /dev/null +++ b/docs/TheFuture.aml @@ -0,0 +1,61 @@ + + + + + + This is a list of all features that are planned to be added at some point. + Probably none of them have timelines or estimates yet, and they are in no particular order. + I just would like to add them eventually. It's mostly here for interest, + and for reference if you have a new feature request - it might be on here already! + + + Also note that none of these features are guaranteed. In an ideal world they would all + happen but since work hasn't started on any of them some may turn out to be impractical + or delayed indefinitely. + + +
+ Source Code Release + + + At current the source is not available, but the plan is to release the code onto github + at some point in the future, hopefully soon. Primarily it will be once RenderDoc has stabilised + and there is a good feature set available, as opposed to the very basic features currently + available. + + +
+
+ Planned Features + + + + + Debugging of all shader stages. + HLSL Debugging. + Mesh display after HS stage. + Perfkit/PerfHUD integration for vendor-specific detailed + performance timers. + Multiple frames in a single capture/logfile. + D3D9 support. + OpenGL support. + Linux/OS X support. + Diffing events in a given frame. + Modifying the pipeline on the fly to change state. + Highlighting redundant state-setting. + Tracking the dependencies or dependants of a given drawcall. + Exposing an API to applications so they can give more details or annotation, + more tightly integrating with the app itself. + A low-resource mode so RenderDoc can be left on by default whenever running + an app, so it's always available if a bug appears. + Attaching to an already-running application. + + + + +
+ + + +
+
\ No newline at end of file diff --git a/docs/TipsNTricks.aml b/docs/TipsNTricks.aml new file mode 100644 index 0000000000..b8781c1fda --- /dev/null +++ b/docs/TipsNTricks.aml @@ -0,0 +1,70 @@ + + + + + + This page is a random hodge-podge of different tips and tricks that might not be obvious + and aren't practical to make clear in the UI - e.g. keyboard shortcuts, edge cases + and suchlike. + + +
+ Tips & Tricks + + + + File associations for .rdc and .cap files can be set up in the installer or in the + . These allow automatic + opening of capture logs or capture settings files directly from files. + + + These associations must be re-created if RenderDoc is moved to another folder. + + + If a .cap file is saved with the "auto-start" option enabled, launching RenderDoc + by opening this file will cause RenderDoc to automatically trigger a capture with the given options. + This is useful for saving a common path & set of options that you regularly re-run. + For more information check out the + page. + If you'd like to see the geometry data with each component separated out and formatted, + either open "Mesh Output" under the window menu, or click the Go Arrow + on the input layouts in the . + Right clicking on one of the channel buttons in the texture viewer + (R, G, B, A) will either select only that channel, or if it's already the only one + selected it will select all of the others. This is useful e.g. to toggle between viewing + RGB and alpha, or for looking at individual channels in a packed texture or render target. + Similarly, right-clicking on the 'auto-fit' button + will auto-fit whenever the texture + or event changes, so that the visible range is maintained as you move through the frame. This can be useful + if jumping between places where the visible range is very different. + You can double click on a thumbnail in the texture viewer to open a + locked texture tab + You can close tabs by middle clicking on them. + You can trigger a capture from code. renderdoc.dll exports a function for this + purpose: + +typedef void (__cdecl *pRENDERDOC_TriggerCapture)(); + +// At init +HMODULE renderdoc = GetModuleHandle(_T("renderdoc.dll")); +pRENDERDOC_TriggerCapture triggerFunc = + (pRENDERDOC_TriggerCapture)GetProcAddress(renderdoc, "RENDERDOC_TriggerCapture"); + +// When you wish to trigger the capture +triggerFunc(); + + + The next Swap() after this call will begin the captured frame, + and the Swap() after that will end it (barring complications) + + When you have right clicked to select a pixel in the texture viewer, you can + perform precise refinements with the arrow keys to nudge the selection in each direction. + To get API debug or error messages, enable "Create Debug Device" when capturing + then check out the window. + More coming soon hopefully :). + + + +
+
+
diff --git a/docs/Tokens.tokens b/docs/Tokens.tokens new file mode 100644 index 0000000000..aff743623e --- /dev/null +++ b/docs/Tokens.tokens @@ -0,0 +1,8 @@ + + + + RenderDoc Contact + RenderDoc @ Crytek + mailto:renderdoc@crytek.com?subject=RenderDoc%20feedback + + \ No newline at end of file diff --git a/docs/Windows/APIInspector.aml b/docs/Windows/APIInspector.aml new file mode 100644 index 0000000000..dc5b8f0a27 --- /dev/null +++ b/docs/Windows/APIInspector.aml @@ -0,0 +1,55 @@ + + + + + + Although not the most complex part of the RenderDoc's UI, this page details + the features and functionality of the API Inspector. + +
+ UI Elements + + The API Inspector is divided into two sections - the top section is the most common, + detailing all of the API calls leading up to and including the current drawcall. + The special case for this is the end of the frame where there may not be a final drawcall + but the API Inspector lists the API calls that preceded the final flip of the backbuffer + that marks the end of RenderDoc's captured frame. + The bottom section is less common but shows the callstack from user code into the + API entry point, if such a callstack is available and the symbols are resolved. For more + information check out the page on . + +
+
+ API Calls + + This section lists the series of API calls made between the preceding drawcall + and the currently selected drawcall. The current drawcall is always the last element + in this list and is highlighted in bold. By default it is also the selected element. + Each API call can be expanded to see the parameters that were passed to it, in the + form that they were serialised out to the log file. + +A list of API calls made up to the current draw. + + + +
+
+ Callstack + + The callstack section can be expanded by double clicking on the separator and + collapsed in the same way. Once open its size can be adjusted by clicking and dragging + on the separator. + This section will either show "No callstack available" or "Need to resolve symbols" + as appropriate when the callstacks aren't ready for display. + The callstack follows the currently selected API call in the other section, and will + update both as that selected call change and as the current event changes (as this implicitly + changes the API call selected to whichever the current drawcall is). + For more information see + +The callstack in user code where this API call was made. + + + +
+
+
\ No newline at end of file diff --git a/docs/Windows/BufferViewer.aml b/docs/Windows/BufferViewer.aml new file mode 100644 index 0000000000..0acf51dc73 --- /dev/null +++ b/docs/Windows/BufferViewer.aml @@ -0,0 +1,122 @@ + + + + + The buffer viewer has two reasonably distinct modes - the first rather + specialised to show meshes and mesh data as it passes through the pipeline. + The other shows a raw arbitrary buffer with a custom (and arbitrary) formatting. + +
+ Mesh Viewer + + The Mesh Viewer shows both the mesh data as well as a visual representation + of the mesh at different stages - pre VS, post VS, etc. + Each distinct point has a display that shows the mesh data, the format of which + is pulled from the relevant stage of the pipeline - shader input or output, or input + layout. You can choose to sync these views + as well as specify an offset which will stay consistent, so that you can see the same + row as you move between different events. + Below this is a 3D view which will show one stage at any given time, and can be + switched with the tabs above it. There are two control schemes for viewing the 3D mesh - + Arcball which is the default for pre-transform (VS in), and WASD controls which is the + default for post-transform (VS out). You can switch between these at any time with + the dropdown on the toolbar above the mesh view. + + + When tessellation is active, VS out behaves similarly to VS in as they are both + considered input data (rather than post-transform data). + + + You can reset the camera to its default location with the reset button + . For VS Input this + resets to an arcball at some radius from the object. For VS Output this resets to a view + from the projected eye. + You can also auto-fit the camera to the mesh for the VS Input mesh. The auto-fit + button will fit the + camera to the axis-aligned bounding box of the mesh. + To be able to view the post-transform mesh in view-space, RenderDoc attempts to + guess the projection matrix and unprojects the output data. + By default the projection matrix is guessed as a standard perspective matrix. + Using the post-projection w and z values and the aspect ratio of the output targets + a reasonable approximation can be estimated. The FOV must be specified though - the + default is 90 but this can be refined by opening the options. + Opening the options + you can specify the FOV used in the projection matrix. If you used an orthographic + matrix instead you can specify this - although this requires manual tuning of the + matrix parameters. + +The options pop-out of the buffer viewer. + + + Also available in the options is a simple speed multiplier for the WASD controls, + to fine-tune how fast it moves to the dimensions of the mesh. + In the vertex input preview, you have the option to display the mesh with some solid + shading modes, not just as a wireframe mesh. When solid shading you can toggle the wireframe + on and off. + + + Solid Colour simply displays a solid colour for each triangle. + Flat Shaded will perform basic flat lighting calculations based on triangle normals to give a better idea of the topology of the mesh. + TEXCOORD0 and COLOR0 will display the relevant input element, if detected in the mesh. + + +Previewing the uv co-ordinates as colour on the mesh. + + + +
+
+ Raw Buffer Viewer + + When opening a buffer as a raw display, sometimes a default layout will be specified + e.g. if available from shader reflection data. If not, the layout will default to 4 + 32bit unsigned integers. + This format can be refined and customised by entering a structure-like definition + into the text box at the bottom of the window. The given types are listed below, and + can be combined in hlsl-like fashion specifying n-wide vector elements. + In addition to this, you can specify a row offset which is useful in remaining + at the same row while watching the change in a buffer between different events, as well + as a byte offset to shift the data along from the start of the buffer (e.g. if what you + are interested in starts only part-way through the buffer but is not aligned along the + data stride you enter). + + +Specifying a custom buffer format. + + + + Below are listed the basic types. You can append a number to each of these to make an N-wide + vector (e.g. ushort4 or float3). You can also specify matrices as float3x4. By default matrices + are column major, but you can change this by prepending row_major as you would in hlsl. + + + uint - unsigned 32bit integer + bool - unsigned 32bit integer (this is the format for hlsl bools) + int - signed 32bit integer + ushort - unsigned 16bit integer + short - signed 16bit integer + ubyte - unsigned 8bit integer + byte - signed 8bit integer + double - 64bit floating point + float - 32bit floating point + half - 16bit floating point + + + There are also some non-hlsl types for displaying other formats which don't have a corresponding native + hlsl type + + + unormb - 8bit unsigned normalised value + unormh - 16bit unsigned normalised value + unormf - 32bit unsigned normalised value + snormb - 8bit signed normalised value + snormh - 16bit signed normalised value + snormf - 32bit signed normalised value + uintten - 4 component unsigned integer format, packed as 10:10:10:2 + unormten - 4 component unsigned normalised format, packed as 10:10:10:2 + + + +
+
+
diff --git a/docs/Windows/CaptureDialog.aml b/docs/Windows/CaptureDialog.aml new file mode 100644 index 0000000000..146c494f35 --- /dev/null +++ b/docs/Windows/CaptureDialog.aml @@ -0,0 +1,219 @@ + + + + + + The Capture Dialog (which doubles as the attach-to-process dialog) is the + single point where programs are launched and logfiles are captured to disk. + After launching a capture a connection dialog will open to allow you to manage + and open any captures you take. See for more details. + + + NOTE: The Load Settings and Save Settings buttons on this dialog refer to loading and saving the set + of settings and options configured on this dialog. They do not refer to loading + and saving the logs produced from capturing - that is done from the File menu. + + + +
+ Capturing + + To capture a program you simply need to provide the details of the application + to be launched. + The Program section of the dialog prompts for the executable to be launched, + the working directory, and any command-line arguments to be passed to the program. + +Configuring and launching an exe directly from RenderDoc. + + + The "..." buttons next to the executable path and working directory can be used to + browse through the file system. By default if the working directory box is left empty + then the directory containing the executable will be used as the working directory. + When you are ready to capture simply click the Capture button in the bottom right. + If you wish to save these particular settings you can click Save to save them to a .cap file. + This .cap file can either be loaded in manually, accessed through the Recent Captures menu. + The .cap file can be associated with RenderDoc, and if so launching RenderDoc from this file will automatically load + the capture settings. If "Auto start" is checked then double clicking on the .cap file will immediately trigger + a capture with the given settings. + + + The process will be launched with the same permissions and by the same user as RenderDoc was launched. + If your process requires specific permissions (such as administrator permissions) you will need to + launch RenderDoc with these permissions. + + + +
+
+ Inject into Process + + When invoked through Inject into Process the capture dialog modifies itself + to give a list of processes running on the target system. + A list of processes is fetched once when the dialog is opened, but this can be refreshed + by clicking on the refresh button below the list. Select the process you would like to attach to + and click Attach. + +Attaching to an already-running process via RenderDoc. + + + + + The process must not have invoked or initialised the API to be used, + as this will be too late for RenderDoc to hook and capture it. At best RenderDoc will not capture, at worst + it may cause crashes or undefined behaviour. Only attach to processes you can guarantee are early + enough in their initialisation that they have not used the graphics API. + + +
+ +
+ Capture Options + + Several capture options are available to configure how RenderDoc works while injected into + the target application, as well as affecting the resultant captures. Most of these will work + fine with the defaults, but some may need to be configured to your tastes. + Some of these options are API-specific and will not apply when using other APIs than + they are intended, although most are generic in some fashion - the exact implementation may + vary by API. + + + + Name + Explanation + Default Setting + + + + Allow Fullscreen + Allow Fullscreen simply means that RenderDoc will not interfere with any attempt + by the application to switch into an exclusive fullscreen video mode. While debugging sometimes + this can be awkward as you may wish to quickly switch to your debugger or another program. + If this option is unchecked, RenderDoc will attempt to modify any such attempt to an equivalent + windowed mode. + Enabled + + + Allow VSync + Allow VSync functions very similarly to Allow Fullscreen. When disabled, RenderDoc + will prevent any attempt to VSync by the application. This can be useful given that there is a + certain degree of inevitable overhead from running with RenderDoc and VSync can amplify that. + Enabled + + + Seconds Delay + This option causes RenderDoc to stall for a defined number of seconds immediately after + launching the process. Most commonly this is used so that you can launch a program in RenderDoc + and immediately attach a traditional debugger before any significant code is executed. + This can be useful e.g. when early initialisation needs to be debugged. + 0 Seconds (Disabled) + + + Collect Callstacks + This option will cause RenderDoc to save a callstack from user code into the API at every + API call during the frame being captured. This can then be resolved later and used to determine where + the application is calling each API call. More details can be found in: + . + Disabled + + + Only Drawcall Callstacks + This option modifies the above capturing of callstacks to only be saved for drawcall-type + API calls. This can reduce the CPU load, as well as file-size and memory overhead of capturing callstacks + for every API call which may not be desired. Only valid if Collect Callstacks is enabled. + Disabled + + + Create Debug Device + Create Debug Device causes RenderDoc to enable the API's built-in debugging, and where + possible serialise this out and include it in the logfile for later inspection. e.g. on D3D11 this will + activate the D3D debug layer and save out any messages, which can later be viewed in the + window. + The overhead from enabling this option is largely the same as the overhead of enabling the + debug device without RenderDoc involved. + Disabled + + + Cache State Objects + In D3D11 creating a state object with the same descriptor as one that already exists + will simply return a pointer to the existing state object, with a reference count added. Given that + creation and destruction in RenderDoc has a certain overhead, when this option is enabled RenderDoc will + hold onto a reference to freed state objects in case they are likely to be re-allocated soon after. + This will reduce churn and overhead with minimal impact to the application, and it's recommended to + leave this enabled unless you have specific problems or want to remove this optimisation. + Enabled + + + Hook into Children + This option causes RenderDoc to hook into CreateProcess and intercept any calls to it from + the target application. When this option is enabled those child processes will be injected with RenderDoc + in the same way as the parent - which can be useful if you must launch your program through a launcher + or level of indirection and still wish to use RenderDoc with one of the child processes. + Disabled + + + Save All Initials + RenderDoc will attempt to save overhead and particularly logfile size by omitting the initial + contents of 2D textures that it believes will be unnecessary. Typically these textures are render targets + or depth buffers that will be written to and fully covered in the course of the frame before they are + ever read, and so saving their initial contents is unnecessary. + In some cases this detection will be wrong, such as targets that are partially written such as pools, + or if a target is accumulated to via blend modes. When this is the case, enabling Save All Initials will + force RenderDoc to save these textures regardless of any auto-detection. + + + Multisampled textures will not have their initial contents saved regardless of the value of + this option. + + + + Disabled + + + Ref All Resources + One method RenderDoc uses to keep logfile sizes down is to only include the referenced + dependencies of a frame within a capture. This means that even if 100 textures are allocated and present, + if 50 of them are never bound to the pipeline or otherwise referenced then they will not be included + in the logfile. Enabling this option will cause RenderDoc to include all live resources at the time of + capture regardless of whether they are used or not. + Disabled + + + Capture All Cmd Lists + By default RenderDoc only begins capturing when you hit the capture key - any commands issued + before this point are not available and so if a deferred command list was created before you hit capture + and replayed after, it would not be available and RenderDoc would have to fall back and capture again in the + hopes that next frame everything will be available. + If the application creates a command list early and replays it indefinitely without recreating it, + RenderDoc will essentially have missed its chance to capture it by the time you hit the capture key. Enabling + this option will cause RenderDoc to pre-emptively capture all command lists just in case they are used. + + + This may have a significant performance hit. + + + Disabled + + + Auto start + This option is slightly different from the others in that it doesn't change anything for an + immediate capture. When a .cap settings file is saved with the details of a particular capture, if this + option is enabled then loading a .cap file from the command line (i.e. most commonly from a file association) + will trigger a capture as soon as RenderDoc loads. This is useful for saving a common capture setting and + running it with just one click. + Disabled + + + Queue Capture of Frame + This option allows you to queue up a precise capture of a given frame number after the program has started. + Disabled + +
+ +
+
+ + + + +
+
diff --git a/docs/Windows/DebugMessages.aml b/docs/Windows/DebugMessages.aml new file mode 100644 index 0000000000..a703c33cf8 --- /dev/null +++ b/docs/Windows/DebugMessages.aml @@ -0,0 +1,28 @@ + + + + + The Debug Messages window shows messages from the API including warnings about performance + issues or concerns about potential hazards, as well as errors on invalid use of the API. + +
+ Capturing with debug messages included + + To include these debug messages in a log, check on the "Create Debug Device" option in + the capture options. For more information see . + +
+
+ Debug Messages + + This window is fairly simple. Each message retrieved from the api will be listed on + its own row showing the event ID that triggered the message, along with a severity and category. + Double clicking on any row will take you to the corresponding event ID in the event browser. + +The Debug Messages window showing some API messages. + + + +
+
+
\ No newline at end of file diff --git a/docs/Windows/EventBrowser.aml b/docs/Windows/EventBrowser.aml new file mode 100644 index 0000000000..ed940cfcaf --- /dev/null +++ b/docs/Windows/EventBrowser.aml @@ -0,0 +1,129 @@ + + + + + The Event Browser is the primary method of browsing the frame and selecting + different drawcalls. It displays the user-annotated hierarchical display of + sections. + +
+ Annotating your frame + + The Event Browser becomes most useful when the application has user-defined + annotations of sections and subsections of the frames, to allow for a more logical + and ordered browsing of the frame. + Doing this is API and platform specific. Example code for D3D11 is included + below, using the D3DPERF library that is defined in d3d9.lib, which can still be used + in D3D11. (The newer ID3DUserDefinedAnnotation API is also supported). + + +D3DPERF_BeginEvent(0xffffffff, L"Start of example"); + +D3DPERF_BeginEvent(0xff00ff00, L"Sub section"); +// events inside the subsection +D3DPERF_EndEvent(); + +// events outside the subsection +D3DPERF_EndEvent(); + + + This will generate a section of the frame with a subsection that includes some events, + and then some further events that are siblings of the subsection. + +
+
+ Selecting available columns + + By default, the columns in the event browser are EID and Name. Name cannot be removed as + it contains the tree, but otherwise the columns can be customised both to hide/display or + reorder and resize. + To select which columns should be visible, right click the header or click the + select columns button. + To rearrange the columns simply click and drag on the header. + + + Note that when timing drawcalls the duration column will automatically be added to display the data. + + + +
+
+ Timing drawcalls + + To time the GPU duration of each drawcall, click the timer button + This will automatically run a process to get the time of each drawcall and display it in the duration column, + which will be added if necessary. + You can configure which time unit is used for the duration column on the fly in the + + +
+
+ Browsing the frame + + The event browser is primarily intended as a tool to browse through the frame. Events + are listed as entries in the browser and the hierarchical labels mentioned above become + tree nodes. + The currently selected event is highlighted and indicated with a green flag + . This is the event + that RenderDoc is inspecting and is reflected in all the other windows of the UI. + +The Event browser showing several sections and the current event. + + + The EID column indicates the event ID of the drawcall listed. Event IDs are + assigned starting from 1 and increase every time an API call is made - for this + reason drawcall EIDs are not necessarily contiguous. + Simply clicking on a different event will select it as current, and selecting + a parent node with some child events will act as if the final child is selected - + in other words selecting a node with several children will show the results of all + children having happened. + You can also use keyboard shortcuts to browse through the frame. Pressing up or + down arrow key will move up and down through the visible elements, skipping over any + sections which are collapsed. These keys will move into and out of a sub-section into + the next sibling afterwards - essentially going straight up and down as if there is + not a tree and it is a straight list. + The left and right arrows go into and out of hierarchy levels. When within a level + pressing left will jump to the parent node of the current level. Pressing left again + will collapse that node, and so on. Pressing right will (if on a node with children) + expand that node. + +
+
+ Searching and Jumping + + There are two other controls available in the Event Browser to aid in navigating + the frame. + Pressing Ctrl-F will open the find-event toolbar + . This toolbar + allows you to type in a partial text filter that will be matched against both labels + and drawcall events. The find will be executed when you press enter, although you can then + adjust the text and re-search if you wish. + If the event found lies inside an unexpanded section, the sections will be + expanded until the matching event is visible. + Matching events will be highlighted with a find icon + , and pressing + enter repeatedly will jump between matching events. + The find toolbar isn't dismissed until you press escape in the text box, or click the close button + . + You can also jump up and down between find results with the + previous + and next + buttons. + +The results of a find are highlighted with an icon. + + + Pressing Ctrl-G will open the jump to EID toolbar. This allows + you to type in an EID and jump straight there, expanding nodes as necessary. If the EID + typed doesn't exist in the list of drawcalls, the closest matching EID will be jumped + to. + When you hit enter to jump to an EID, the toolbar closes and if you wish to jump again + you must press Ctrl-G again + +The jump-to-EID toolbar prompting for an event. + + + +
+
+
diff --git a/docs/Windows/LiveCapture.aml b/docs/Windows/LiveCapture.aml new file mode 100644 index 0000000000..93ad2a2fdf --- /dev/null +++ b/docs/Windows/LiveCapture.aml @@ -0,0 +1,108 @@ + + + + + + The Live capture window opens up when you launch a capture of a program, as well as when + you attach to an existing program. + +
+ Attaching to an existing instance + + + After you've launched a program through RenderDoc and its hooks are added you can freely disconnect + (by closing the live capture window) or close the main UI. You can then connect to this again later, + either from the same computer or another computer connecting over the network. + + + To connect to an existing hooked program, select Attach to Running Instance from the File menu. This opens up + the attach window that allows you to select a remote host to connect to. By default localhost is already + in the list, but you can add and remove other hosts. + + + + Please note that none of the connections RenderDoc makes or uses are encrypted or protected, so if this is a + concern you should look into securing the connections by hand. + + + +Attaching to a running instance either locally or remotely. + + + + + When the window opens, when you add a new host or when you click refresh then the hosts will be queried + across the network to see if a connection exists. While this is in progress the host will be listed in + italics and with a busy icon. + + + Once a host has been scanned, if any instances are found then that host can be expanded to see the list, and + details are listed about each instance. The name is OS-dependent but is usually the executable name. The API + name is listed, as well as the username of any user that is already connected. + + + When you click connect, a live capture window will be opened up - just the same as the window that is automatically + opened when you start a program. Any captures that have already been made before you connect will then populate. + + + + If you connect to a running instance, any existing user will be kicked off. Just seeing the instances running on + a host will not. + + + +
+
+ Capture Connection window + + + + When a capture is launched (or attached to) the connection window is opened in the main UI. If you + end up only taking one capture and closing the program afterwards the connection window will automatically + close - likewise if you take no captures at all. These cases don't need the management options the connection + window provides. + + + + In addition to managing captures that have been taken, you can also trigger a capture (optionally with a + countdown timer). + + + +Viewing multiple captures taken in a program. + + + + + In this example we have a connection window open to the CascadedShadowMaps11 sample from the DirectX SDK. + Two captures have been made and we can see their thumbnails to help distinguish between them. This is visible + at any point, regardless of whether you have close the program or not - you can simply switch back to RenderDoc + while it's running. + + + + Note, if you have remotely connected you will need to wait while the captures copy across the network + to your PC, after which point everything behaves the same as a local capture. + + + + From here you can save these captures out - as currently they are only temporary copies that will be + cleaned up on close. You can also manually delete any capture you wish to discard. + + + + Double clicking on any capture will close any current open capture in the RenderDoc UI, and open up that + capture for inspection. You may also right click or use the drop-down menu on the open button to + launch a new instance of RenderDoc for viewing the log. This is mostly useful if you want to compare two + captures side-by-side easily. + + + +Launch new RenderDoc instance to open this capture. + + + + +
+
+
\ No newline at end of file diff --git a/docs/Windows/Options.aml b/docs/Windows/Options.aml new file mode 100644 index 0000000000..b093520a06 --- /dev/null +++ b/docs/Windows/Options.aml @@ -0,0 +1,173 @@ + + + + + + The options window contains various advanced or niche settings that configure + the analysis UI. + +
+ Options + + Below each tab of the options window is detailed with explanations of the + given settings. + Some settings may not be saved until the application is closed, although + most will come into immediate effect. + The settings are contained in %APPDATA%\RenderDoc\UI.config if you wish to + back up or reset these settings. + +
+
+ General options + + + + + Name + Explanation + Default Setting + + + + Associate .rdc with RenderDoc + This button will elevate RenderDoc to administrator privileges temporarily, and + associate the .rdc file extension with RenderDoc. After doing this double clicking any .rdc file + will open it in a new instance of RenderDoc. + + + + Associate .cap with RenderDoc + This button will elevate RenderDoc to administrator privileges temporarily, and + associate the .cap file extension with RenderDoc. After doing this double clicking any .cap file + will open a new instance of RenderDoc and show the capture dialog with the settings contained inside. + If the setting "Auto Start" is enabled, RenderDoc will then immediately trigger a capture of + the target executable. + + + + Minimum decimal places on float values + Defines the smallest number of decimal places to display on a float, padding with + 0s. + Examples: + With a value of 2, 0.1234f will be displayed as 0.1234 + With a value of 2, 1.0f will be displayed as 1.00 + With a value of 6, 0.1234f will be displayed as 0.123400 + With a value of 6, 1.0f will be displayed as 1.000000 + 2 + + + Maximum significant figures on decimals + Defines the most significant figures to display after the decimal place on + floating point numbers. + Examples: + With a value of 5, 0.123456789f will be displayed as 0.12345 + With a value of 5, 1.0f will be displayed as 1.00 + With a value of 10, 0.123456789f will be displayed as 0.123456789 + With a value of 10, 1.0f will be displayed as 1.00 + 5 + + + Negative exponential cutoff value + Any floating point numbers that are below E-v for this value v + will be displayed in scientific notation rather than as a fixed point decimal. + Examples: + With a value of 5, 0.1234f will be displayed as 0.1234 + With a value of 5, 0.000001f will be displayed as 1.0E-6 + With a value of 10, 0.1234f will be displayed as 0.1234 + With a value of 10, 0.000001f will be displayed as 0.000001 + 5 + + + Positive exponential cutoff value + Any floating point numbers that are larger than E+v for this value v + will be displayed in scientific notation rather than as a fixed point decimal. + Examples: + With a value of 7, 8000.5f will be displayed as 8005.5 + With a value of 7, 123456789.0f will be displayed as 1.2345E8 + With a value of 2, 8000.5f will be displayed as 8.0055E3 + With a value of 2, 123456789.0f will be displayed as 1.2345E8 + 7 + + + Allow periodic anonymous update checks + Every couple of days RenderDoc will send a single web request to a server to see if a new version + is available and let you know about it. The only information transmitted is the version of RenderDoc that is running. + If you would prefer RenderDoc does not ever contact an external server, disable this checkbox. If you do this it's + recommended that you manually check for updates as new versions will be made available regularly with bugfixes. + Enabled + +
+ +
+
+
+ Texture Viewer options + + + + + Name + Explanation + Default Setting + + + + Reset Range on changing selection + When changing texture from one to another, when this option is enabled the range + control will reset itself to [0, 1]. This will happen between any two textures, and going back + and forth between two textures will also reset the range. + Disabled + +
+
+
+
+ Shader Viewer options + + + + + Name + Explanation + Default Setting + + + + Rename disassembly registers + This option tries to make the disassembly of shaders easier to read by substituting + variable names where available in for constant register names. + Enabled + +
+
+
+
+ Event Browser options + + + + + Name + Explanation + Default Setting + + + + Time unit used for event browser timings + This option allows you to select the unit that will be shown in the duration column + in the event browser when you time individual drawcalls. + Seconds through to nanoseconds are supported. + Enabled + + + Hide empty marker sections + Marker sections that contain no API calls or drawcalls will be completely removed. + This also applies to the Timeline Bar. + This option only applies itself the next time you load a log. + Disabled + +
+
+
+
+
diff --git a/docs/Windows/PipelineState.aml b/docs/Windows/PipelineState.aml new file mode 100644 index 0000000000..9fde06143a --- /dev/null +++ b/docs/Windows/PipelineState.aml @@ -0,0 +1,55 @@ + + + + + The Pipeline Viewer is an information dense but simple window + in RenderDoc. It shows all of the stateful settings of the graphics pipeline, including + bound resources, rasterizer settings, etc. + +
+ Pipeline flowchart + + At the top of the Pipeline Viewer is the pipeline flowchart - this shows the + high-level block level diagram of the graphics pipeline. + Each block is a separate page which contains the relevant state and contents + for that piece of the graphics pipeline, with specific details varying by API + and the type of data to be displayed. + The currently selected block is outlined with red, and the page in view reflects + the contents of that section of the pipeline. Light grey parts of the pipeline are + those which are currently active and participating in this drawcall. Dark grey parts + of the pipeline are not present and can be considered pass-through/do-nothing. + +Pictured here, the high-level parts of the D3D11 Pipeline. + + + + + In D3D11, the Stream-Out stage is available under the Geometry Shader block, with the buffers + being used for stream-out shown. + + + +
+
+ Pipeline Section Display + + The pipeline state viewer always displays the state of the pipeline after the execution of the + drawcall, as with the other viewers in RenderDoc. + Any resources that are bound to the pipeline can be opened in more detailed viewers, such as + vertex buffers, constant buffers and textures. More details of this process can be found in the page + . + The pipeline view attempts to only show what is relevant, and not all possible stateful data. + To do this (when available) it uses shader reflection data to only display slots which are actually + in use by the shaders, and omit any that are unused. This can be overridden with the Show Disabled + Items button. + Likewise it will omit any slots which are completely empty (and also unused), and this behaviour + can be overridden with the Show Empty Items button. + When showing disabled or empty entries, they will either be in italics + or on a dark red background respectively. + +
+ + + +
+
\ No newline at end of file diff --git a/docs/Windows/TextureViewer.aml b/docs/Windows/TextureViewer.aml new file mode 100644 index 0000000000..3f254d6220 --- /dev/null +++ b/docs/Windows/TextureViewer.aml @@ -0,0 +1,337 @@ + + + + + + The texture viewer is likely the most intuitive window in RenderDoc and commonly + the most regularly used. It displays the contents of any texture in its current state + at the given event, as well as providing controls to adjust and inspect it in different + ways. + +
+ Overview + + The texture viewer consists of a couple of different sections, which will be + outlined here. + Several specific techniques or features used within the texture viewer have their + own separate pages that go into more detail. You might find more useful information there + if they cover what you are looking for: + , + , + + + +A labelled diagram showing the different parts of the texture viewer. + + + +
+
+ Main Texture Display + + The main texture display takes up the largest portion of the window, and is simply a container for the + textures to display. + It is a tabbed control and although one tab is always present showing the currently followed texture + bound to the pipeline, other locked tabs can be opened up showing a single resource. More details are available + on the page . + The mouse wheel can be used to zoom in and out of the texture. When zoomed in, holding the left mouse + button and dragging will pan the image from side to side. + While over the image the status bar will show the current pixel that the mouse + is over. Clicking or holding the right mouse button will pick this pixel and show its information in the status + bar. More information is available on the page . + +
+
+ Information Status Bar + + The status bar below the main texture display contains information on the currently visible texture. + + + The name (if available - if not a default name will be used). + Dimensions - Width, height, depth and array size as applicable. + Mip Count. + MSAA sample count and quality, if applicable. + Format - e.g. RGB8. The exact phrasing of this will vary by API. + + + After this information there are a few displays that are pixel-based. The pixel that is under the cursor + is displayed as a colour swatch, followed by its co-ordinates. Then any + picked pixel is displayed afterwards with its + numeric value displayed. + +Detailed information about the current pixel. + + + + +
+
+ Thumbnail Strips + + There are several thumbnail strip panels available, by default they are docked in the same + location such that they are tabbed together, but they can be displayed side by side. + These strips display thumbnails of the resources bound to their respective parts of the + pipeline, to give some context and allow quick preview without having to switch the main + display between these textures. + The texture that the following tab is currently displaying is highlighted in red, and + each thumbnail shows both the slot number and the name of the texture bound at that point. + To follow a given slot simply left click on it. + If the currently followed texture slot is empty (i.e. it was following a texture and then + that slot was unbound) it will show up simply named "Unbound" and with no name or slot number. + Each thumbnail has a context menu available via right click. This menu allows you to open + a locked tab (More information), + as well as containing a list of all the uses of this texture - as read-only resource and writable + output. This is similar to the resource display strip on the . + Clicking on any of these entries will jump to the first of the events in the event range listed. + +Thumbnail context menu with several options. + + + There are also two general options - show disabled and show empty. These behave the same as the + options in the window - temporarily overriding + the default behaviour in RenderDoc to only show texture slots that are referenced in the shader. + +
+
+ Pixel Context Display + + The Pixel context display is a small panel by default in the bottom right of the texture viewer. + Whenever a pixel is picked small area of the texture around it is rendered at maximum zoom to this + panel. This gives you some context for the pixels nearby to the one you're picking and allows fine refinement + without needing to zoom in and lose your place in the overall image. + +Pixel context displaying the surrounds of the picked pixel. + + + +
+
+ Visible Range Control + + The visible range or range adaption control is very useful in easing display and inspection of + images with a very narrow range of values, and is necessary for viewing any HDR images as it can be + used to map a larger range down to LDR for display. + +The range control narrowing the visible range mapped to [0,1] on output. + + + The primary controls are the black point and white point. These are shown in two text boxes at + either side of the main range control. These are the current absolute black and white values - these values + in the input texture are mapped to 0 and 1 respectively on output. + The range control itself has a black point and a white point that can be adjusted simply by clicking and + dragging. These allow finer and more interactive adjustments. These handle only allow you to adjust the extremes + within the range defined by the absolute black and white points in the text box. + There are four other buttons available for control of the range: + + + + Zoom in - + This button will zoom the extreme values in to whichever fine values have been selected by the draggable handles. + This is primarily useful when starting from some large range and using the handles to drag down to a more reasonable + range, you can click zoom to then reduce the range down to just the one selected, so you can again get fine control. + +The range control before zooming. + + + +The range control after zooming. + + + + Autofit - + This button automatically fits the range control to the min and max values in any visible channels in the texture. + Oftentimes this is a good starting point for a range, although with some extreme textures it may adjust badly. + Right clicking on this button will cause it to always auto-fit until you disable this. ie. when you move + to another event or another texture, the range will be auto-fit again. This is useful if jumping between events + or textures where the visible ranges are very different. + Reset - + Simply resets the range back to the default of [0, 1] - useful for resetting after changing to a new texture where the + range settings aren't applicable. + Histogram - + This is a toggle switch. When enabled it will change the thin bar of the range control into a thicker bar + that contains a range-value histogram, showing the distribution of values. + The histogram is based on the straight numerical mean of all visible channels, and will update as the + white and black points move. + +A histogram showing the range distribution of values in the image. + + + + + +
+
+ Toolbar + + The toolbar contains most of the tools for selecting which mip, slice, face of + a texture to view as well as how to display it and if any transformations or overlays + should be applied. + + + The visible range/range adaption control is detailed in the section above and will not be covered here. + + + + + + Control + Explanation + + + + + Channels selector + RGBM mode + + + + + + Custom Shader + + This selector switches between displaying standard RGBA channels, RGBM encoding with a custom + multiplier and using a custom visualiser shader. + When in RGBA mode, by default only the RGB channels are displayed and alpha is forced to fully opaque. + Each of the channels can be toggled off independently and any combination can be used. Any RGB channel which + is disabled is forced to fully black in the output. When Alpha is enabled, the background will be rendered + with a solid colour or checkerboard pattern to indicate semi-transparent areas. + Also note that when a single channel is displayed solo, the image is rendered as grayscale in that channel + rather than displaying a monochromatic coloured image. + + + Right clicking on one of the channel buttons in the texture viewer + (R, G, B, A) will either select only that channel, or if it's already the only one + selected it will select all of the others. This is useful e.g. to toggle between viewing + RGB and alpha, or for looking at individual channels in a packed texture or render target. + + + When RGBM is selected, the RGB value will be multiplied by the specified multiplier and then by + the alpha value. This is a common encoding used to pack a larger range into an 8-bit RGB image. + With Custom selected a dropdown will be populated with any .hlsl files in the + %APPDATA%\renderdoc folder. When choosing a custom shader the raw image will be + passed through this shader before being displayed with the usual controls on the main display. + You can create a new custom shader with the button, + edit a shader with the button, + and delete an one with the button. + + + + + + + Alpha Background + + + When displaying a texture with alpha channel, the background of the main display changes to make + the semi-transparent sections more obvious. With these two controls you can either choose a checkerboard pattern + or open a colour picker to choose a solid + colour . + + The currently enabled mode will be highlighted. + + + + Subresource selection + + The main display of the texture viewer can only display at most a single 2D image at once. + For textures with mip-maps this control allows you to select the mip level to display - the overall size + of the image will remain the same but will be point sampled from the given mip level. + For 3D textures and 2D arrays you can select the slice to display here from the drop-down, and for cubemaps + you can select the face. For cubemap arrays these two controls are combined to show a list of the faces for the first + cubemap, then the second, etc. + + + + + Save Texture + + This allows you to save the currently visible texture. Currently only .dds format is supported, and + there are some limitations in the formats that can be saved - e.g. there is no standard way to support multisampled + dds files, so this will fail. Most common formats can be saved to disk in this way. + + + + + Debug a Pixel + + This button is only enabled after a + pixel has been picked. + This will do exactly the same as the button underneath the pixel context display - it will + launch a pixel debugger for the currently picked pixel. + + + + + Open Texture List + + This button opens the texture list of all textures present in the capture. More details can + be seen in + + + + + Zoom controls + + The zoom controls are fairly self explanatory - a pre-existing zoom value can be chosen + from the drop down or a custom value (clamped to the minimum and maximum zoom) can be entered as a + percentage. + To automatically fit the texture to the space available in the window, regardless of its + dimensions, you can click the Fit + button. + + + As noted above, the mouse scroll wheel in the main display also changes the zoom level. + + + + + + + Render Overlay + + This is a powerful tool for quickly diagnosing issues and can be very useful for locating + what you're looking for. Several overlays are available that can be rendered over any texture, although + most of them are only meaningful for currently bound render targets. + + + Highlight Drawcall will do pretty much as it says. It darkens everything except + the current drawcall which is highlighted in flat colour. This makes whatever is being drawn stand out and can be useful + for seeing where the current object is on screen, especially if rapidly browsing through the frame. + Wireframe Mesh will render a wireframe mesh of the current drawcall + over the top of the image. + Depth Test will render an overlay over the drawcall, with red sections covering + any part of the drawcall that never passed the depth test, and green sections covering areas that did pass the + depth test. Note that if the drawcall overdraws itself then as long as at least one pass over a pixel passes the depth test + then that pixel will be green. + Stencil Test performs similarly to the depth test, but for the stencil test. + Viewport/Scissor shows a coloured overlay on the image that corresponds to the viewport + and scissor regions. + NaN/Inf/-ve display will render the image in grayscale (using the typical luminance + calculation - dot(col.xyz, float3(0.2126, 0.7152, 0.0722)).xxx) with red pixels highlighting any + NaNs found, green pixels highlighting any infinities, and blue pixels for any negative values. Note that in any case + where only one or some channels in a multi-channel texture pass, that pixel will still be highlighted (so + {0.5, -1.0, 0.0} would highlight blue). + Clipping will simply highlight in red any values that are below the current + black point (as defined by the range control - see above), and in green any values above the white point. This can + be useful in identifying invalid ranges if the range control is adjusted correctly, or in combination with a custom + shader visualiser. + + + + These overlays are all rendered after most image controls are applied. For this reason the range control, + channel controls and custom shaders do not affect the overlays. + + + + +
+ +
+
+ + + + + +
+
diff --git a/docs/Windows/TimelineBar.aml b/docs/Windows/TimelineBar.aml new file mode 100644 index 0000000000..3d8de06c08 --- /dev/null +++ b/docs/Windows/TimelineBar.aml @@ -0,0 +1,81 @@ + + + + + + The timeline bar shows an alternate view of the scene to the + . Displaying the scene with + time running as the horizontal axis, although it does not show each section in size + relative to its timing. + +
+ Introduction + + The timeline bar shows the scene horizontally with the hierarchical frame + markers being expandable from top to bottom. + This alternate view can be a useful way to get an overview of the whole frame, + allowing you to jump around very different parts of the frame. + Given that the timeline bar shows the whole frame it also provides a secondary + function of showing dependencies in a global way. For whichever texture is currently + selected in the texture viewer, the timeline bar shows reads and writes to that texture + throughout the frame. This can be especially useful for render targets that are used + in both ways, as well as simply to see where a given texture is used in a frame + without laboriously searching. + +The timeline bar showing a birds-eye view of a typical application. + + + +
+
+ Timeline Display + + By default the timeline bar views the whole frame, but with the mouse wheel + you can zoom in and out. When zoomed in, you can scroll through the frame with + the horizontal scroll bar. + The timeline bar sizes the sections that it contains to try and make the + frame markers as visible as possible. This attempts to keep the frame browsable + for as long as possible, such that small sections (in time or number of events) + are still visible rather than being crushed to tiny bars. + For this reason the timeline can resize itself when bars are expanded, + as this can reveal new sections which must be allocated enough room. When there + is slack space to be allocated it is given to the sections which have more events + than others. + Underneath expanded sections, a blue pip is rendered for each drawcall-type + event. The currently selected event is shown as a green pip, as well as there being + a light grey vertical line to indicate the current position, such that this is visible + even when the relevant section is not expanded. + Clicking on any section will toggle it between expanded and unexpanded, and + any sections underneath a section which is collapsed will remain in their previous state + but will not be visible. + Left clicking on the timeline will jump to the event underneath that point + on the horizontal display. + +
+
+ Resource usage Display + + The timeline bar also shows the usage of the currently displayed texture. + Whichever texture is currently displayed in the + (whether that be a currently bound texture, or a locked tab) will have its usage + laid out across the frame on the timeline bar. + If your textures have their names annotated you will see which texture is being + inspected in the label for the usage bar. + A green arrow will be drawn under each pip that reads from the texture. If the pips + are too close together to resolve the arrow, the arrows will stay distinct and lose the + 1:1 association with event pips. + Similarly, a purple arrow will be drawn under pips where the event writes to the + texture. In the case that a resource is bound such that it can be read or written, + the arrow will be half-green, half-purple. + Clear calls will be shown with a light grey. + In cases where the arrows are too close together to show distinctly, they + will not all draw. To see exactly what usage is happening you can zoom into the context + around that area of the frame. + +The usage bar showing reads and writes to a texture. + + + +
+
+
diff --git a/docs/dummy/IgnoreMe.csproj b/docs/dummy/IgnoreMe.csproj new file mode 100644 index 0000000000..0113a98436 --- /dev/null +++ b/docs/dummy/IgnoreMe.csproj @@ -0,0 +1,80 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {8FB56D2F-58D9-425D-A46E-E3EA111A2F68} + WinExe + Properties + IgnoreMe + IgnoreMe + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\IgnoreMe.xml + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + \ No newline at end of file diff --git a/docs/dummy/IgnoreMe.sln b/docs/dummy/IgnoreMe.sln new file mode 100644 index 0000000000..93414e3d1e --- /dev/null +++ b/docs/dummy/IgnoreMe.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IgnoreMe", "IgnoreMe.csproj", "{8FB56D2F-58D9-425D-A46E-E3EA111A2F68}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FB56D2F-58D9-425D-A46E-E3EA111A2F68}.Debug|x86.ActiveCfg = Debug|x86 + {8FB56D2F-58D9-425D-A46E-E3EA111A2F68}.Debug|x86.Build.0 = Debug|x86 + {8FB56D2F-58D9-425D-A46E-E3EA111A2F68}.Release|x86.ActiveCfg = Release|x86 + {8FB56D2F-58D9-425D-A46E-E3EA111A2F68}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/docs/dummy/Program.cs b/docs/dummy/Program.cs new file mode 100644 index 0000000000..60b3e83670 --- /dev/null +++ b/docs/dummy/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace IgnoreMe +{ + /// + /// Ignore me! This is a dummy section of documentation to satisfy Sandcastle :). + /// + public class IgnoreMe + { + /// + /// Ignore me! This is a dummy section of documentation to satisfy Sandcastle :). + /// + [STAThread] + static void Main() + { + } + } +} diff --git a/docs/dummy/Properties/AssemblyInfo.cs b/docs/dummy/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..90056aea20 --- /dev/null +++ b/docs/dummy/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("dummydocs")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("dummydocs")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e27b8253-434f-4a51-8ea8-a19bc79e0d45")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/docs/dummy/Properties/Resources.Designer.cs b/docs/dummy/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..10299ba8c5 --- /dev/null +++ b/docs/dummy/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18052 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace IgnoreMe.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("IgnoreMe.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/docs/dummy/Properties/Resources.resx b/docs/dummy/Properties/Resources.resx new file mode 100644 index 0000000000..af7dbebbac --- /dev/null +++ b/docs/dummy/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/docs/dummy/Properties/Settings.Designer.cs b/docs/dummy/Properties/Settings.Designer.cs new file mode 100644 index 0000000000..3b98caca34 --- /dev/null +++ b/docs/dummy/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18052 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace IgnoreMe.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/docs/dummy/Properties/Settings.settings b/docs/dummy/Properties/Settings.settings new file mode 100644 index 0000000000..39645652af --- /dev/null +++ b/docs/dummy/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/imgs/QuickStart/QuickStart1.png b/docs/imgs/QuickStart/QuickStart1.png new file mode 100644 index 0000000000..28c6ba03f5 Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart1.png differ diff --git a/docs/imgs/QuickStart/QuickStart2.png b/docs/imgs/QuickStart/QuickStart2.png new file mode 100644 index 0000000000..7cd25e18af Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart2.png differ diff --git a/docs/imgs/QuickStart/QuickStart3.png b/docs/imgs/QuickStart/QuickStart3.png new file mode 100644 index 0000000000..1a7e117f3a Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart3.png differ diff --git a/docs/imgs/QuickStart/QuickStart4.png b/docs/imgs/QuickStart/QuickStart4.png new file mode 100644 index 0000000000..37ad6c4c03 Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart4.png differ diff --git a/docs/imgs/QuickStart/QuickStart5.png b/docs/imgs/QuickStart/QuickStart5.png new file mode 100644 index 0000000000..a2f15d2040 Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart5.png differ diff --git a/docs/imgs/QuickStart/QuickStart6.png b/docs/imgs/QuickStart/QuickStart6.png new file mode 100644 index 0000000000..4b349b6f6b Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart6.png differ diff --git a/docs/imgs/QuickStart/QuickStart7.png b/docs/imgs/QuickStart/QuickStart7.png new file mode 100644 index 0000000000..c85035c8a7 Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart7.png differ diff --git a/docs/imgs/QuickStart/QuickStart8.png b/docs/imgs/QuickStart/QuickStart8.png new file mode 100644 index 0000000000..89c8f2a81f Binary files /dev/null and b/docs/imgs/QuickStart/QuickStart8.png differ diff --git a/docs/imgs/Screenshots/APIList.png b/docs/imgs/Screenshots/APIList.png new file mode 100644 index 0000000000..9611ca59d0 Binary files /dev/null and b/docs/imgs/Screenshots/APIList.png differ diff --git a/docs/imgs/Screenshots/AfterRangeZoom.png b/docs/imgs/Screenshots/AfterRangeZoom.png new file mode 100644 index 0000000000..aea3dcdd98 Binary files /dev/null and b/docs/imgs/Screenshots/AfterRangeZoom.png differ diff --git a/docs/imgs/Screenshots/AttachInstance.png b/docs/imgs/Screenshots/AttachInstance.png new file mode 100644 index 0000000000..f874fbd4f8 Binary files /dev/null and b/docs/imgs/Screenshots/AttachInstance.png differ diff --git a/docs/imgs/Screenshots/Attaching.png b/docs/imgs/Screenshots/Attaching.png new file mode 100644 index 0000000000..609363e7fc Binary files /dev/null and b/docs/imgs/Screenshots/Attaching.png differ diff --git a/docs/imgs/Screenshots/BeforeRangeZoom.png b/docs/imgs/Screenshots/BeforeRangeZoom.png new file mode 100644 index 0000000000..8b5d0dba2f Binary files /dev/null and b/docs/imgs/Screenshots/BeforeRangeZoom.png differ diff --git a/docs/imgs/Screenshots/BufferOptions.png b/docs/imgs/Screenshots/BufferOptions.png new file mode 100644 index 0000000000..5d06ee6edf Binary files /dev/null and b/docs/imgs/Screenshots/BufferOptions.png differ diff --git a/docs/imgs/Screenshots/CBuffer.png b/docs/imgs/Screenshots/CBuffer.png new file mode 100644 index 0000000000..e4e575b0a8 Binary files /dev/null and b/docs/imgs/Screenshots/CBuffer.png differ diff --git a/docs/imgs/Screenshots/CallstackPanel.png b/docs/imgs/Screenshots/CallstackPanel.png new file mode 100644 index 0000000000..af65e96495 Binary files /dev/null and b/docs/imgs/Screenshots/CallstackPanel.png differ diff --git a/docs/imgs/Screenshots/Callstacks.png b/docs/imgs/Screenshots/Callstacks.png new file mode 100644 index 0000000000..36031733f8 Binary files /dev/null and b/docs/imgs/Screenshots/Callstacks.png differ diff --git a/docs/imgs/Screenshots/CapturePathCmdline.png b/docs/imgs/Screenshots/CapturePathCmdline.png new file mode 100644 index 0000000000..335b928cb8 Binary files /dev/null and b/docs/imgs/Screenshots/CapturePathCmdline.png differ diff --git a/docs/imgs/Screenshots/CurrentShader.png b/docs/imgs/Screenshots/CurrentShader.png new file mode 100644 index 0000000000..705862c26a Binary files /dev/null and b/docs/imgs/Screenshots/CurrentShader.png differ diff --git a/docs/imgs/Screenshots/CurrentVsLockedTab.png b/docs/imgs/Screenshots/CurrentVsLockedTab.png new file mode 100644 index 0000000000..9ed71d1cc3 Binary files /dev/null and b/docs/imgs/Screenshots/CurrentVsLockedTab.png differ diff --git a/docs/imgs/Screenshots/CustomDisplay.png b/docs/imgs/Screenshots/CustomDisplay.png new file mode 100644 index 0000000000..757e4c003e Binary files /dev/null and b/docs/imgs/Screenshots/CustomDisplay.png differ diff --git a/docs/imgs/Screenshots/DebugMessages.png b/docs/imgs/Screenshots/DebugMessages.png new file mode 100644 index 0000000000..639ee6a874 Binary files /dev/null and b/docs/imgs/Screenshots/DebugMessages.png differ diff --git a/docs/imgs/Screenshots/FindResults.png b/docs/imgs/Screenshots/FindResults.png new file mode 100644 index 0000000000..9112318f2c Binary files /dev/null and b/docs/imgs/Screenshots/FindResults.png differ diff --git a/docs/imgs/Screenshots/HoverStatus.png b/docs/imgs/Screenshots/HoverStatus.png new file mode 100644 index 0000000000..afc718fd32 Binary files /dev/null and b/docs/imgs/Screenshots/HoverStatus.png differ diff --git a/docs/imgs/Screenshots/JumpEID.png b/docs/imgs/Screenshots/JumpEID.png new file mode 100644 index 0000000000..f9534f18fe Binary files /dev/null and b/docs/imgs/Screenshots/JumpEID.png differ diff --git a/docs/imgs/Screenshots/LabelledTexViewer.png b/docs/imgs/Screenshots/LabelledTexViewer.png new file mode 100644 index 0000000000..c290264317 Binary files /dev/null and b/docs/imgs/Screenshots/LabelledTexViewer.png differ diff --git a/docs/imgs/Screenshots/MultipleCaptures.png b/docs/imgs/Screenshots/MultipleCaptures.png new file mode 100644 index 0000000000..68439324cd Binary files /dev/null and b/docs/imgs/Screenshots/MultipleCaptures.png differ diff --git a/docs/imgs/Screenshots/NamedTex.png b/docs/imgs/Screenshots/NamedTex.png new file mode 100644 index 0000000000..a571f471b2 Binary files /dev/null and b/docs/imgs/Screenshots/NamedTex.png differ diff --git a/docs/imgs/Screenshots/NeedPDB.png b/docs/imgs/Screenshots/NeedPDB.png new file mode 100644 index 0000000000..396ba4cb36 Binary files /dev/null and b/docs/imgs/Screenshots/NeedPDB.png differ diff --git a/docs/imgs/Screenshots/NeedResolve.png b/docs/imgs/Screenshots/NeedResolve.png new file mode 100644 index 0000000000..29168aa8f1 Binary files /dev/null and b/docs/imgs/Screenshots/NeedResolve.png differ diff --git a/docs/imgs/Screenshots/OpenCapNewInstance.png b/docs/imgs/Screenshots/OpenCapNewInstance.png new file mode 100644 index 0000000000..6823876430 Binary files /dev/null and b/docs/imgs/Screenshots/OpenCapNewInstance.png differ diff --git a/docs/imgs/Screenshots/OpenLockedTab.png b/docs/imgs/Screenshots/OpenLockedTab.png new file mode 100644 index 0000000000..09e9268199 Binary files /dev/null and b/docs/imgs/Screenshots/OpenLockedTab.png differ diff --git a/docs/imgs/Screenshots/OverlaySelect.png b/docs/imgs/Screenshots/OverlaySelect.png new file mode 100644 index 0000000000..89eb871a3d Binary files /dev/null and b/docs/imgs/Screenshots/OverlaySelect.png differ diff --git a/docs/imgs/Screenshots/PipelineBar.png b/docs/imgs/Screenshots/PipelineBar.png new file mode 100644 index 0000000000..5e766808c7 Binary files /dev/null and b/docs/imgs/Screenshots/PipelineBar.png differ diff --git a/docs/imgs/Screenshots/PixelContext.png b/docs/imgs/Screenshots/PixelContext.png new file mode 100644 index 0000000000..1c3b883387 Binary files /dev/null and b/docs/imgs/Screenshots/PixelContext.png differ diff --git a/docs/imgs/Screenshots/RGBAChannels.png b/docs/imgs/Screenshots/RGBAChannels.png new file mode 100644 index 0000000000..485548aa16 Binary files /dev/null and b/docs/imgs/Screenshots/RGBAChannels.png differ diff --git a/docs/imgs/Screenshots/RGBMChannels.png b/docs/imgs/Screenshots/RGBMChannels.png new file mode 100644 index 0000000000..46fdb3b396 Binary files /dev/null and b/docs/imgs/Screenshots/RGBMChannels.png differ diff --git a/docs/imgs/Screenshots/RMBStatus.png b/docs/imgs/Screenshots/RMBStatus.png new file mode 100644 index 0000000000..9e4c8f8f99 Binary files /dev/null and b/docs/imgs/Screenshots/RMBStatus.png differ diff --git a/docs/imgs/Screenshots/RangeControl.png b/docs/imgs/Screenshots/RangeControl.png new file mode 100644 index 0000000000..b62f544047 Binary files /dev/null and b/docs/imgs/Screenshots/RangeControl.png differ diff --git a/docs/imgs/Screenshots/RangeHistogram.png b/docs/imgs/Screenshots/RangeHistogram.png new file mode 100644 index 0000000000..a73f61d76d Binary files /dev/null and b/docs/imgs/Screenshots/RangeHistogram.png differ diff --git a/docs/imgs/Screenshots/RawBuffer.png b/docs/imgs/Screenshots/RawBuffer.png new file mode 100644 index 0000000000..df70b8acfc Binary files /dev/null and b/docs/imgs/Screenshots/RawBuffer.png differ diff --git a/docs/imgs/Screenshots/ResourceUsage.png b/docs/imgs/Screenshots/ResourceUsage.png new file mode 100644 index 0000000000..e75bd3b241 Binary files /dev/null and b/docs/imgs/Screenshots/ResourceUsage.png differ diff --git a/docs/imgs/Screenshots/ShaderConsts.png b/docs/imgs/Screenshots/ShaderConsts.png new file mode 100644 index 0000000000..7ae731a0a3 Binary files /dev/null and b/docs/imgs/Screenshots/ShaderConsts.png differ diff --git a/docs/imgs/Screenshots/ShaderControls.png b/docs/imgs/Screenshots/ShaderControls.png new file mode 100644 index 0000000000..2c12c3d99a Binary files /dev/null and b/docs/imgs/Screenshots/ShaderControls.png differ diff --git a/docs/imgs/Screenshots/ShaderRegs.png b/docs/imgs/Screenshots/ShaderRegs.png new file mode 100644 index 0000000000..893c20704d Binary files /dev/null and b/docs/imgs/Screenshots/ShaderRegs.png differ diff --git a/docs/imgs/Screenshots/ShaderWatch.png b/docs/imgs/Screenshots/ShaderWatch.png new file mode 100644 index 0000000000..a34b30679b Binary files /dev/null and b/docs/imgs/Screenshots/ShaderWatch.png differ diff --git a/docs/imgs/Screenshots/SolidPreview.png b/docs/imgs/Screenshots/SolidPreview.png new file mode 100644 index 0000000000..8141ed5502 Binary files /dev/null and b/docs/imgs/Screenshots/SolidPreview.png differ diff --git a/docs/imgs/Screenshots/SubresourceSelect.png b/docs/imgs/Screenshots/SubresourceSelect.png new file mode 100644 index 0000000000..d51ae8d088 Binary files /dev/null and b/docs/imgs/Screenshots/SubresourceSelect.png differ diff --git a/docs/imgs/Screenshots/TexList.png b/docs/imgs/Screenshots/TexList.png new file mode 100644 index 0000000000..cd4edb68ec Binary files /dev/null and b/docs/imgs/Screenshots/TexList.png differ diff --git a/docs/imgs/Screenshots/TimelineBar.png b/docs/imgs/Screenshots/TimelineBar.png new file mode 100644 index 0000000000..098e7ca38b Binary files /dev/null and b/docs/imgs/Screenshots/TimelineBar.png differ diff --git a/docs/imgs/Screenshots/VertexDebug.png b/docs/imgs/Screenshots/VertexDebug.png new file mode 100644 index 0000000000..e10844d80c Binary files /dev/null and b/docs/imgs/Screenshots/VertexDebug.png differ diff --git a/docs/imgs/Screenshots/ZoomControls.png b/docs/imgs/Screenshots/ZoomControls.png new file mode 100644 index 0000000000..80c1b759fd Binary files /dev/null and b/docs/imgs/Screenshots/ZoomControls.png differ diff --git a/docs/imgs/icons/GoArrow.png b/docs/imgs/icons/GoArrow.png new file mode 100644 index 0000000000..b244731cbe Binary files /dev/null and b/docs/imgs/icons/GoArrow.png differ diff --git a/docs/imgs/icons/UndoArrow.png b/docs/imgs/icons/UndoArrow.png new file mode 100644 index 0000000000..6972c5e594 Binary files /dev/null and b/docs/imgs/icons/UndoArrow.png differ diff --git a/docs/imgs/icons/add.png b/docs/imgs/icons/add.png new file mode 100644 index 0000000000..6332fefea4 Binary files /dev/null and b/docs/imgs/icons/add.png differ diff --git a/docs/imgs/icons/arrow_join.png b/docs/imgs/icons/arrow_join.png new file mode 100644 index 0000000000..a128413d88 Binary files /dev/null and b/docs/imgs/icons/arrow_join.png differ diff --git a/docs/imgs/icons/arrow_undo.png b/docs/imgs/icons/arrow_undo.png new file mode 100644 index 0000000000..6972c5e594 Binary files /dev/null and b/docs/imgs/icons/arrow_undo.png differ diff --git a/docs/imgs/icons/chart_curve.png b/docs/imgs/icons/chart_curve.png new file mode 100644 index 0000000000..01e933a619 Binary files /dev/null and b/docs/imgs/icons/chart_curve.png differ diff --git a/docs/imgs/icons/cog.png b/docs/imgs/icons/cog.png new file mode 100644 index 0000000000..67de2c6ccb Binary files /dev/null and b/docs/imgs/icons/cog.png differ diff --git a/docs/imgs/icons/color_wheel.png b/docs/imgs/icons/color_wheel.png new file mode 100644 index 0000000000..809fb00e5a Binary files /dev/null and b/docs/imgs/icons/color_wheel.png differ diff --git a/docs/imgs/icons/cross.png b/docs/imgs/icons/cross.png new file mode 100644 index 0000000000..1514d51a3c Binary files /dev/null and b/docs/imgs/icons/cross.png differ diff --git a/docs/imgs/icons/crosshatch.png b/docs/imgs/icons/crosshatch.png new file mode 100644 index 0000000000..09275f9c09 Binary files /dev/null and b/docs/imgs/icons/crosshatch.png differ diff --git a/docs/imgs/icons/delete.png b/docs/imgs/icons/delete.png new file mode 100644 index 0000000000..08f249365a Binary files /dev/null and b/docs/imgs/icons/delete.png differ diff --git a/docs/imgs/icons/find.png b/docs/imgs/icons/find.png new file mode 100644 index 0000000000..1547479646 Binary files /dev/null and b/docs/imgs/icons/find.png differ diff --git a/docs/imgs/icons/fit_window.png b/docs/imgs/icons/fit_window.png new file mode 100644 index 0000000000..2e9bc42bec Binary files /dev/null and b/docs/imgs/icons/fit_window.png differ diff --git a/docs/imgs/icons/flag_green.png b/docs/imgs/icons/flag_green.png new file mode 100644 index 0000000000..e4bc611f87 Binary files /dev/null and b/docs/imgs/icons/flag_green.png differ diff --git a/docs/imgs/icons/new_window.png b/docs/imgs/icons/new_window.png new file mode 100644 index 0000000000..2e945076cf Binary files /dev/null and b/docs/imgs/icons/new_window.png differ diff --git a/docs/imgs/icons/page_white_database.png b/docs/imgs/icons/page_white_database.png new file mode 100644 index 0000000000..bddba1f98c Binary files /dev/null and b/docs/imgs/icons/page_white_database.png differ diff --git a/docs/imgs/icons/page_white_delete.png b/docs/imgs/icons/page_white_delete.png new file mode 100644 index 0000000000..af1ecaf298 Binary files /dev/null and b/docs/imgs/icons/page_white_delete.png differ diff --git a/docs/imgs/icons/page_white_edit.png b/docs/imgs/icons/page_white_edit.png new file mode 100644 index 0000000000..b93e77600d Binary files /dev/null and b/docs/imgs/icons/page_white_edit.png differ diff --git a/docs/imgs/icons/page_white_link.png b/docs/imgs/icons/page_white_link.png new file mode 100644 index 0000000000..bf7bd1c9bf Binary files /dev/null and b/docs/imgs/icons/page_white_link.png differ diff --git a/docs/imgs/icons/red_x_16.png b/docs/imgs/icons/red_x_16.png new file mode 100644 index 0000000000..8277651a33 Binary files /dev/null and b/docs/imgs/icons/red_x_16.png differ diff --git a/docs/imgs/icons/runback.png b/docs/imgs/icons/runback.png new file mode 100644 index 0000000000..5dc696781e Binary files /dev/null and b/docs/imgs/icons/runback.png differ diff --git a/docs/imgs/icons/runcursor.png b/docs/imgs/icons/runcursor.png new file mode 100644 index 0000000000..e3e14c5a69 Binary files /dev/null and b/docs/imgs/icons/runcursor.png differ diff --git a/docs/imgs/icons/runfwd.png b/docs/imgs/icons/runfwd.png new file mode 100644 index 0000000000..b1a1819238 Binary files /dev/null and b/docs/imgs/icons/runfwd.png differ diff --git a/docs/imgs/icons/save.png b/docs/imgs/icons/save.png new file mode 100644 index 0000000000..5ca4d10623 Binary files /dev/null and b/docs/imgs/icons/save.png differ diff --git a/docs/imgs/icons/stepnext.png b/docs/imgs/icons/stepnext.png new file mode 100644 index 0000000000..d29136c465 Binary files /dev/null and b/docs/imgs/icons/stepnext.png differ diff --git a/docs/imgs/icons/stepprev.png b/docs/imgs/icons/stepprev.png new file mode 100644 index 0000000000..24f8bbe299 Binary files /dev/null and b/docs/imgs/icons/stepprev.png differ diff --git a/docs/imgs/icons/time.png b/docs/imgs/icons/time.png new file mode 100644 index 0000000000..911da3f1d3 Binary files /dev/null and b/docs/imgs/icons/time.png differ diff --git a/docs/imgs/icons/timeline_marker.png b/docs/imgs/icons/timeline_marker.png new file mode 100644 index 0000000000..a3fbddf88b Binary files /dev/null and b/docs/imgs/icons/timeline_marker.png differ diff --git a/docs/imgs/icons/wand.png b/docs/imgs/icons/wand.png new file mode 100644 index 0000000000..44ccbf8128 Binary files /dev/null and b/docs/imgs/icons/wand.png differ diff --git a/docs/imgs/icons/wrench.png b/docs/imgs/icons/wrench.png new file mode 100644 index 0000000000..5c8213fef5 Binary files /dev/null and b/docs/imgs/icons/wrench.png differ diff --git a/docs/imgs/icons/zoom.png b/docs/imgs/icons/zoom.png new file mode 100644 index 0000000000..908612e394 Binary files /dev/null and b/docs/imgs/icons/zoom.png differ diff --git a/docs/imgs/logo.png b/docs/imgs/logo.png new file mode 100644 index 0000000000..048b422937 Binary files /dev/null and b/docs/imgs/logo.png differ diff --git a/docs/renderdoc.shfbproj b/docs/renderdoc.shfbproj new file mode 100644 index 0000000000..23faf2537c --- /dev/null +++ b/docs/renderdoc.shfbproj @@ -0,0 +1,500 @@ + + + + + Debug + AnyCPU + 2.0 + {d6d6e2b1-866b-497e-b691-ff8026647d16} + 1.9.5.0 + + Documentation + Documentation + Documentation + + .NET Framework 1.1 + ..\Documentation\ + renderdoc + en-US + None + Blank + False + VS2005 + False + Guid + RenderDoc Documentation + + + AboveNamespaces + + + + None + None + False + False + OnlyWarningsAndErrors + HtmlHelp1 + False + False + False + False + True + None + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DebugMessages + Debug Messages Window + + + ShaderWatch + Shader Watch + + + OpenCapNewInstance + Open capture in new instance + + + MultipleCaptures + Viewing multiple captures + + + AttachInstance + Attaching to a running instance + + + time + time + time + + + cross + cross + cross + + + timeline_marker + timeline marker + timeline_marker + + + page_white_edit + page white edit + page_white_edit + page_white_edit + + + add + add + add + add + + + delete + delete + + + TimelineBar + Timeline Bar + Timeline Bar + TimelineBar + + + ResourceUsage + Showing resource frame usage + + + PipelineBar + Pipeline Bar + Pipeline state flow + PipelineBar + + + JumpEID + JumpEID + Jumping to an EID + JumpEID + + + FindResults + Highlighted find results + + + SolidPreview + Solid Preview + Solid-shaded mesh preview + SolidPreview + + + BufferOptions + Options for Buffer Viewer preview + + + BeforeRangeZoom + Before Range Zoom + Before zooming range + BeforeRangeZoom + + + AfterRangeZoom + After zooming range + + + ZoomControls + Zoom controls + + + SubresourceSelect + Subresource selection + + + RGBMChannels + RGBM display + + + RGBAChannels + RGBA channels + + + RangeHistogram + Visible range histogram + + + RangeControl + Visible range control + + + OverlaySelect + Selecting render overlay + + + CustomDisplay + Custom shader display + + + LabelledTexViewer + Labelled Tex Viewer + Texture viewer with labels + LabelledTexViewer + + + CallstackPanel + Callstack Panel + Callstack Panel + CallstackPanel + + + APIList + List of API calls + + + Callstacks + Callstacks + Enabling callstack collection + Callstacks + + + NeedResolve + Symbols need to be resolved + + + NeedPDB + PDB prompt + + + CBuffer + CBuffer + Displaying the cotents of a constant buffer + CBuffer + + + RawBuffer + Specifying raw buffer format + + + CurrentShader + The currently bound shader + + + CurrentVsLockedTab + Current Vs Locked Tab + Current tab and a locked tab + CurrentVsLockedTab + + + TexList + Texture list + + + OpenLockedTab + Opening a new locked tab + + + NamedTex + Showing an annotated texture + + + Attaching + Attaching + Attaching to a process + Attaching + + + PixelContext + Pixel context display + + + RMBStatus + Status bar - picked pixel + + + HoverStatus + Status bar - hovering + + + CapturePathCmdline + Capturing a program with command line + + + ShaderRegs + Shader Regs + Shader variable registers + ShaderRegs + + + ShaderControls + Shader debugging controls + + + ShaderConsts + Shader constant registers + + + VertexDebug + Vertex Debug + Debugging from a vertex + VertexDebug + + + stepprev + stepprev + + + stepnext + stepnext + + + runfwd + runfwd + + + runcursor + runcursor + + + runback + runback + + + color_wheel + color wheel + + + crosshatch + crosshatch + + + fit_window + fit window + + + find + find + + + chart_curve + chart curve + + + arrow_undo + arrow undo + + + arrow_join + arrow join + + + zoom + zoom + + + wrench + wrench + + + wand + wand + + + save + save + + + red_x_16 + red x 16 + + + page_white_delete + page white delete + + + page_white_database + page white database + + + new_window + new window + + + page_white_link + page white link + + + flag_green + flag green + GreenFlag + + + cog + cog + cog + + + UndoArrow + Undo Arrow + UndoArrow + + + GoArrow + Go Arrow + GoArrow + + + QuickStart8 + Mesh Output Viewer + QuickStart8 + + + QuickStart7 + The Pipeline State Viewer + QuickStart7 + + + QuickStart6 + The Timeline Bar + + + QuickStart5 + The API Calls + Callstack Panel + + + QuickStart4 + The Event Browser + + + QuickStart3 + The Texture Viewer + + + QuickStart2 + The in-application RenderDoc Overlay + QuickStart2 + + + QuickStart1 + Capturing a Log + + + logo + RenderDoc + + + + + \ No newline at end of file diff --git a/hash_version.sh b/hash_version.sh new file mode 100644 index 0000000000..699f9d959b --- /dev/null +++ b/hash_version.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +GIT_HASH=`git rev-parse HEAD`; + +rm -f ver +sed -b "s/NO_GIT_COMMIT_HASH_DEFINED/$GIT_HASH/" renderdoc/data/resource.h > ver && mv ver renderdoc/data/resource.h +sed -b "s/NO_GIT_COMMIT_HASH_DEFINED/$GIT_HASH/" renderdocui/Properties/AssemblyInfo.cs > ver && mv ver renderdocui/Properties/AssemblyInfo.cs +rm -f ver diff --git a/installer/Installer32.wxs b/installer/Installer32.wxs new file mode 100644 index 0000000000..0c4a367a04 --- /dev/null +++ b/installer/Installer32.wxs @@ -0,0 +1,209 @@ + + + + + + + + Please use the 64-bit installer + + + + + + VersionNT64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/installer/Installer64.wxs b/installer/Installer64.wxs new file mode 100644 index 0000000000..49710523df --- /dev/null +++ b/installer/Installer64.wxs @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/installer/LICENSE.rtf b/installer/LICENSE.rtf new file mode 100644 index 0000000000..b85cfd45d7 Binary files /dev/null and b/installer/LICENSE.rtf differ diff --git a/installer/chm.ico b/installer/chm.ico new file mode 100644 index 0000000000..6cb071ff1f Binary files /dev/null and b/installer/chm.ico differ diff --git a/pdblocate/pdblocate.cpp b/pdblocate/pdblocate.cpp new file mode 100644 index 0000000000..2591c6fc40 --- /dev/null +++ b/pdblocate/pdblocate.cpp @@ -0,0 +1,478 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +using std::vector; +using std::wstring; + +// must match definition in callstack.h +struct AddrInfo +{ + wchar_t funcName[127]; + wchar_t fileName[127]; + unsigned long lineNum; +}; + +struct Module +{ + Module(IDiaDataSource* src, IDiaSession* sess) : + pSource(src), pSession(sess) {} + + IDiaDataSource* pSource; + IDiaSession* pSession; +}; + +vector modules; + +typedef BOOL (CALLBACK *PFINDFILEINPATHCALLBACKW)(PCWSTR, PVOID); + +typedef BOOL (WINAPI *PSYMINITIALIZEW)(HANDLE, PCWSTR, BOOL); +typedef BOOL (WINAPI *PSYMFINDFILEINPATHW)(HANDLE, PCWSTR, PCWSTR, PVOID, DWORD, DWORD, DWORD, PWSTR, PFINDFILEINPATHCALLBACKW, PVOID); + +PSYMINITIALIZEW dynSymInitializeW = NULL; +PSYMFINDFILEINPATHW dynSymFindFileInPathW = NULL; + +wstring GetSymSearchPath() +{ + PWSTR appDataPath; + SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_SIMPLE_IDLIST|KF_FLAG_DONT_UNEXPAND, NULL, &appDataPath); + wstring appdata = appDataPath; + CoTaskMemFree(appDataPath); + + wstring sympath = L".;"; + sympath += appdata; + sympath += L"\\renderdoc\\symbols;SRV*"; + sympath += appdata; + sympath += L"\\renderdoc\\symbols\\symsrv*http://msdl.microsoft.com/download/symbols"; + + return sympath; +} + +wstring LookupModule(wstring moduleDetails) +{ + uint32_t params[12]; + int charsRead = 0; + swscanf_s(moduleDetails.c_str(), L"%d %d %d %d %d %d %d %d %d %d %d %d%n", + ¶ms[0], ¶ms[1], ¶ms[2], ¶ms[3], ¶ms[4], ¶ms[5], + ¶ms[6], ¶ms[7], ¶ms[8], ¶ms[9], ¶ms[10], ¶ms[11], &charsRead); + + wchar_t *modName = (wchar_t *)moduleDetails.c_str() + charsRead + 1; + + while(*modName != L'\0' && iswspace(*modName)) modName++; + + DWORD age = params[0]; + GUID guid; + guid.Data1 = params[1]; + guid.Data2 = params[2]; + guid.Data3 = params[3]; + guid.Data4[0] = params[4]; + guid.Data4[1] = params[5]; + guid.Data4[2] = params[6]; + guid.Data4[3] = params[7]; + guid.Data4[4] = params[8]; + guid.Data4[5] = params[9]; + guid.Data4[6] = params[10]; + guid.Data4[7] = params[11]; + + wchar_t *pdbName = modName; + + if(wcsrchr(pdbName, L'\\')) + pdbName = wcsrchr(pdbName, L'\\')+1; + + if(wcsrchr(pdbName, L'/')) + pdbName = wcsrchr(pdbName, L'/')+1; + + if(wcsstr(pdbName, L".pdb") == NULL && + wcsstr(pdbName, L".PDB") == NULL) + { + wchar_t *ext = wcsrchr(pdbName, L'.'); + + if(ext) + { + ext[1] = L'p'; + ext[2] = L'd'; + ext[3] = L'b'; + } + } + + wstring ret = modName; + + if(dynSymFindFileInPathW != NULL) + { + wstring sympath = GetSymSearchPath(); + + wchar_t path[MAX_PATH] = {0}; + BOOL found = dynSymFindFileInPathW(GetCurrentProcess(), sympath.c_str(), pdbName, &guid, age, 0, SSRVOPT_GUIDPTR, path, NULL, NULL); + DWORD err = GetLastError(); + + if(found == TRUE && path[0] != 0) + ret = path; + } + + return ret; +} + +uint32_t GetModule(wstring moduleDetails) +{ + uint32_t params[12]; + int charsRead = 0; + swscanf_s(moduleDetails.c_str(), L"%d %d %d %d %d %d %d %d %d %d %d %d%n", + ¶ms[0], ¶ms[1], ¶ms[2], ¶ms[3], ¶ms[4], ¶ms[5], + ¶ms[6], ¶ms[7], ¶ms[8], ¶ms[9], ¶ms[10], ¶ms[11], &charsRead); + + wchar_t *pdbName = (wchar_t *)moduleDetails.c_str() + charsRead + 1; + + while(*pdbName != L'\0' && iswspace(*pdbName)) pdbName++; + + DWORD age = params[0]; + GUID guid; + guid.Data1 = params[1]; + guid.Data2 = params[2]; + guid.Data3 = params[3]; + guid.Data4[0] = params[4]; + guid.Data4[1] = params[5]; + guid.Data4[2] = params[6]; + guid.Data4[3] = params[7]; + guid.Data4[4] = params[8]; + guid.Data4[5] = params[9]; + guid.Data4[6] = params[10]; + guid.Data4[7] = params[11]; + + USES_CONVERSION; + LPCOLESTR fName = W2COLE(pdbName); + + Module m(NULL, NULL); + + CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER, __uuidof(IDiaDataSource), (void **)&m.pSource); + + HRESULT hr = S_OK; + + // check this pdb is the one we expected from our chunk + if(guid.Data1 == 0 && guid.Data2 == 0) + { + hr = m.pSource->loadDataFromPdb( fName ); + } + else + { + hr = m.pSource->loadAndValidateDataFromPdb( fName, &guid, 0, age); + } + + if(SUCCEEDED(hr)) + { + // open the session + hr = m.pSource->openSession( &m.pSession ); + if (FAILED(hr)) + { + m.pSource->Release(); + return 0; + } + + modules.push_back(m); + + return modules.size()-1; + } + + m.pSource->Release(); + + return 0; +} + +void SetBaseAddress(wstring req) +{ + uint32_t module; + uint64_t addr; + int charsRead = swscanf_s(req.c_str(), L"%d %llu", &module, &addr); + + if(module > 0 && module < modules.size()) + modules[module].pSession->put_loadAddress(addr); +} + +AddrInfo GetAddr(wstring req) +{ + uint32_t module; + uint64_t addr; + int charsRead = swscanf_s(req.c_str(), L"%d %llu", &module, &addr); + + AddrInfo ret; + ZeroMemory(&ret, sizeof(ret)); + + if(module > 0 && module < modules.size()) + { + IDiaSymbol* pFunc = NULL; + HRESULT hr = modules[module].pSession->findSymbolByVA( addr, SymTagFunction, &pFunc ); + + if(hr != S_OK) + { + if(pFunc) pFunc->Release(); + return ret; + } + + DWORD opts = 0; + opts |= UNDNAME_NO_LEADING_UNDERSCORES; + opts |= UNDNAME_NO_MS_KEYWORDS; + opts |= UNDNAME_NO_FUNCTION_RETURNS; + opts |= UNDNAME_NO_ALLOCATION_MODEL; + opts |= UNDNAME_NO_ALLOCATION_LANGUAGE; + opts |= UNDNAME_NO_THISTYPE; + opts |= UNDNAME_NO_ACCESS_SPECIFIERS; + opts |= UNDNAME_NO_THROW_SIGNATURES; + opts |= UNDNAME_NO_MEMBER_TYPE; + opts |= UNDNAME_NO_RETURN_UDT_MODEL; + opts |= UNDNAME_32_BIT_DECODE; + opts |= UNDNAME_NO_LEADING_UNDERSCORES; + + // first try undecorated name + BSTR file; + hr = pFunc->get_undecoratedNameEx(opts, &file); + + // if not, just try name + if(hr != S_OK) + { + hr = pFunc->get_name(&file); + + if(hr != S_OK) + { + pFunc->Release(); + return ret; + } + + wcsncpy_s(ret.funcName, file, 126); + } + else + { + wcsncpy_s(ret.funcName, file, 126); + + // remove stupid (void) for empty parameters + if(wcsstr(ret.funcName, L"(void)")) + { + wchar_t *a = wcsstr(ret.funcName, L"(void)"); + *(a+1) = L')'; + *(a+2) = 0; + } + } + + pFunc->Release(); + pFunc = NULL; + + SysFreeString(file); + + // find the line numbers touched by this address. + IDiaEnumLineNumbers* lines = NULL; + hr = modules[module].pSession->findLinesByVA(addr, DWORD(4), &lines); + if(FAILED(hr)) + { + if(lines) lines->Release(); + return ret; + } + + IDiaLineNumber* line = NULL; + ULONG count = 0; + + // just take the first one + if(SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) + { + IDiaSourceFile *dia_source = NULL; + hr = line->get_sourceFile(&dia_source); + if(FAILED(hr)) + { + line->Release(); + lines->Release(); + if(dia_source) dia_source->Release(); + return ret; + } + + hr = dia_source->get_fileName(&file); + if(FAILED(hr)) + { + line->Release(); + lines->Release(); + dia_source->Release(); + return ret; + } + + wcsncpy_s(ret.fileName, file, 126); + + SysFreeString(file); + + dia_source->Release(); + dia_source = NULL; + + DWORD line_num = 0; + hr = line->get_lineNumber(&line_num); + if(FAILED(hr)) + { + line->Release(); + lines->Release(); + return ret; + } + + ret.lineNum = line_num; + + line->Release(); + } + + lines->Release(); + } + + return ret; +} + +wstring HandleRequest(wstring req) +{ + size_t idx = req.find(L' '); + + if(idx == wstring::npos) + return L"."; + + wstring type = req.substr(0, idx); + wstring payload = req.substr(idx+1); + + if(type == L"lookup") + return LookupModule(payload); + + if(type == L"baseaddr") + { + SetBaseAddress(payload); + return L"."; + } + + if(type == L"getmodule") + { + wstring ret; + ret.resize(4); + + uint32_t *output = (uint32_t *)&ret[0]; + + *output = GetModule(payload); + + return ret; + } + + if(type == L"getaddr") + { + wstring ret; + ret.resize(sizeof(AddrInfo)/sizeof(wchar_t)); + + AddrInfo info = GetAddr(payload); + + memcpy(&ret[0], &info, sizeof(AddrInfo)); + + return ret; + } + + return L"."; +} + +int WINAPI wWinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPWSTR lpCmdLine, __in int nShowCmd ) +{ + modules.push_back(Module(NULL, NULL)); + + // CreatePipe + HANDLE pipe = CreateNamedPipeW( L"\\\\.\\pipe\\RenderDoc.pdblocate", PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, 0, NULL); + + if(pipe == INVALID_HANDLE_VALUE) + return 1; + + BOOL connected = ConnectNamedPipe(pipe, NULL); + if(!connected && GetLastError() == ERROR_PIPE_CONNECTED) + connected = true; + + if(!connected) + { + CloseHandle(pipe); + return 1; + } + + CoInitialize(NULL); + + HMODULE mod = LoadLibraryW(L"x86/dbghelp.dll"); + + if(mod != NULL) + { + dynSymInitializeW = (PSYMINITIALIZEW)GetProcAddress(mod, "SymInitializeW"); + dynSymFindFileInPathW = (PSYMFINDFILEINPATHW)GetProcAddress(mod, "SymFindFileInPathW"); + + wstring sympath = GetSymSearchPath(); + + if(dynSymInitializeW != NULL) + { + dynSymInitializeW(GetCurrentProcess(), sympath.c_str(), TRUE); + } + } + + wchar_t buf[1024]; + + while(true) + { + DWORD read = 0; + BOOL success = ReadFile(pipe, buf, 1024, &read, NULL); + + if(!success || read == 0) + { + DWORD err = GetLastError(); + break; + } + + wstring request(buf, buf+read/sizeof(wchar_t)); + if(request.back() != L'\0') + request.push_back(L'\0'); + + wstring reply = HandleRequest(request); + + reply.push_back(L'\0'); + + DWORD msglen = reply.length()*sizeof(wchar_t); + + DWORD written = 0; + success = WriteFile(pipe, reply.c_str(), msglen, &written, NULL); + + if(!success || written != msglen) + { + DWORD err = GetLastError(); + break; + } + } + + CloseHandle(pipe); + return 0; +} \ No newline at end of file diff --git a/pdblocate/pdblocate.vcxproj b/pdblocate/pdblocate.vcxproj new file mode 100644 index 0000000000..3864fad93c --- /dev/null +++ b/pdblocate/pdblocate.vcxproj @@ -0,0 +1,99 @@ + + + + + Profile + Win32 + + + Release + Win32 + + + + {6CCB39BA-AB6B-4589-B7C4-9DA879571713} + Win32Proj + pdblocate + + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + false + $(VSInstallDir)\DIA SDK\include;$(IncludePath) + $(SolutionDir)$(Platform)\$(Configuration)\pdblocate\ + + + false + $(VSInstallDir)\DIA SDK\include;$(IncludePath) + $(SolutionDir)$(Platform)\$(Configuration)\pdblocate\ + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + xcopy /Y /Q /S "$(ProjectDir)x86" "$(OutDir)x86\" +xcopy /Y /Q /S "$(ProjectDir)x64" "$(OutDir)x64\" + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + xcopy /Y /Q /S "$(ProjectDir)x86" "$(OutDir)x86\" +xcopy /Y /Q /S "$(ProjectDir)x64" "$(OutDir)x64\" + + + + + + + + + \ No newline at end of file diff --git a/pdblocate/pdblocate.vcxproj.filters b/pdblocate/pdblocate.vcxproj.filters new file mode 100644 index 0000000000..212e4ea22d --- /dev/null +++ b/pdblocate/pdblocate.vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pdblocate/x64/dbghelp.dll b/pdblocate/x64/dbghelp.dll new file mode 100644 index 0000000000..43180bc828 Binary files /dev/null and b/pdblocate/x64/dbghelp.dll differ diff --git a/pdblocate/x64/symsrv.dll b/pdblocate/x64/symsrv.dll new file mode 100644 index 0000000000..3f57f72c44 Binary files /dev/null and b/pdblocate/x64/symsrv.dll differ diff --git a/pdblocate/x64/symsrv.yes b/pdblocate/x64/symsrv.yes new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/pdblocate/x64/symsrv.yes @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pdblocate/x86/dbghelp.dll b/pdblocate/x86/dbghelp.dll new file mode 100644 index 0000000000..e671d38860 Binary files /dev/null and b/pdblocate/x86/dbghelp.dll differ diff --git a/pdblocate/x86/symsrv.dll b/pdblocate/x86/symsrv.dll new file mode 100644 index 0000000000..8e0fe3d606 Binary files /dev/null and b/pdblocate/x86/symsrv.dll differ diff --git a/pdblocate/x86/symsrv.yes b/pdblocate/x86/symsrv.yes new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/pdblocate/x86/symsrv.yes @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/renderdoc.sln b/renderdoc.sln new file mode 100644 index 0000000000..15424dd20b --- /dev/null +++ b/renderdoc.sln @@ -0,0 +1,89 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "renderdoc", "renderdoc\renderdoc.vcxproj", "{E2B46D67-90E2-40B6-9597-72930E7845E5}" + ProjectSection(ProjectDependencies) = postProject + {6CCB39BA-AB6B-4589-B7C4-9DA879571713} = {6CCB39BA-AB6B-4589-B7C4-9DA879571713} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "renderdocui", "renderdocui\renderdocui.csproj", "{5504BAC8-287E-4083-A57F-5EE172EDDAEB}" + ProjectSection(ProjectDependencies) = postProject + {E2B46D67-90E2-40B6-9597-72930E7845E5} = {E2B46D67-90E2-40B6-9597-72930E7845E5} + {6CCB39BA-AB6B-4589-B7C4-9DA879571713} = {6CCB39BA-AB6B-4589-B7C4-9DA879571713} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pdblocate", "pdblocate\pdblocate.vcxproj", "{6CCB39BA-AB6B-4589-B7C4-9DA879571713}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsUI", "WinFormsUI\WinFormsUI.csproj", "{C75532C4-765B-418E-B09B-46D36B2ABDB1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DLL", "DLL", "{B1FB29A4-9C48-4D47-BAEF-CF14CB2A40A3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{89059266-9C4E-4637-AB1D-BFF1DC15096B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "renderdoccmd", "renderdoccmd\renderdoccmd.vcxproj", "{D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}" + ProjectSection(ProjectDependencies) = postProject + {E2B46D67-90E2-40B6-9597-72930E7845E5} = {E2B46D67-90E2-40B6-9597-72930E7845E5} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utility", "Utility", "{B5A783D9-AEB9-420D-8E77-D4D930F8D88C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Profile|Win32 = Profile|Win32 + Profile|x64 = Profile|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Profile|Win32.ActiveCfg = Profile|Win32 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Profile|Win32.Build.0 = Profile|Win32 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Profile|x64.ActiveCfg = Profile|x64 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Profile|x64.Build.0 = Profile|x64 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Release|Win32.ActiveCfg = Release|Win32 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Release|Win32.Build.0 = Release|Win32 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Release|x64.ActiveCfg = Release|x64 + {E2B46D67-90E2-40B6-9597-72930E7845E5}.Release|x64.Build.0 = Release|x64 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Profile|Win32.ActiveCfg = Profile|x86 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Profile|Win32.Build.0 = Profile|x86 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Profile|x64.ActiveCfg = Profile|x64 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Profile|x64.Build.0 = Profile|x64 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Release|Win32.ActiveCfg = Release|x86 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Release|Win32.Build.0 = Release|x86 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Release|x64.ActiveCfg = Release|x64 + {5504BAC8-287E-4083-A57F-5EE172EDDAEB}.Release|x64.Build.0 = Release|x64 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Profile|Win32.ActiveCfg = Profile|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Profile|Win32.Build.0 = Profile|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Profile|x64.ActiveCfg = Profile|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Profile|x64.Build.0 = Profile|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Release|Win32.ActiveCfg = Release|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Release|Win32.Build.0 = Release|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Release|x64.ActiveCfg = Release|Win32 + {6CCB39BA-AB6B-4589-B7C4-9DA879571713}.Release|x64.Build.0 = Release|Win32 + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Profile|Win32.ActiveCfg = Profile|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Profile|Win32.Build.0 = Profile|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Profile|x64.ActiveCfg = Profile|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Profile|x64.Build.0 = Profile|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|Win32.ActiveCfg = Release|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|Win32.Build.0 = Release|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x64.ActiveCfg = Release|Any CPU + {C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x64.Build.0 = Release|Any CPU + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Profile|Win32.ActiveCfg = Profile|Win32 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Profile|Win32.Build.0 = Profile|Win32 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Profile|x64.ActiveCfg = Profile|x64 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Profile|x64.Build.0 = Profile|x64 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Release|Win32.ActiveCfg = Release|Win32 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Release|Win32.Build.0 = Release|Win32 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Release|x64.ActiveCfg = Release|x64 + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E2B46D67-90E2-40B6-9597-72930E7845E5} = {B1FB29A4-9C48-4D47-BAEF-CF14CB2A40A3} + {C75532C4-765B-418E-B09B-46D36B2ABDB1} = {89059266-9C4E-4637-AB1D-BFF1DC15096B} + {5504BAC8-287E-4083-A57F-5EE172EDDAEB} = {89059266-9C4E-4637-AB1D-BFF1DC15096B} + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7} = {B5A783D9-AEB9-420D-8E77-D4D930F8D88C} + {6CCB39BA-AB6B-4589-B7C4-9DA879571713} = {B5A783D9-AEB9-420D-8E77-D4D930F8D88C} + EndGlobalSection +EndGlobal diff --git a/renderdoc/3rdparty/jpeg-compressor/LICENSE.txt b/renderdoc/3rdparty/jpeg-compressor/LICENSE.txt new file mode 100644 index 0000000000..b735cc06ff --- /dev/null +++ b/renderdoc/3rdparty/jpeg-compressor/LICENSE.txt @@ -0,0 +1,4 @@ +jpeg-compressor - C++ class for JPEG compression. +Public domain, Rich Geldreich + +https://code.google.com/p/jpeg-compressor/ diff --git a/renderdoc/3rdparty/jpeg-compressor/jpgd.cpp b/renderdoc/3rdparty/jpeg-compressor/jpgd.cpp new file mode 100644 index 0000000000..fad9a37a9a --- /dev/null +++ b/renderdoc/3rdparty/jpeg-compressor/jpgd.cpp @@ -0,0 +1,3172 @@ +// jpgd.cpp - C++ class for JPEG decompression. +// Public domain, Rich Geldreich +// Alex Evans: Linear memory allocator (taken from jpge.h). +// v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings (all looked harmless) +// +// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2. +// +// Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling. +// Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain" +// http://vision.ai.uiuc.edu/~dugad/research/dct/index.html + +#include "jpgd.h" +#include + +#include +#define JPGD_ASSERT(x) assert(x) + +#ifdef _MSC_VER +#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +// Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling). +// This is slower, but results in higher quality on images with highly saturated colors. +#define JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING 1 + +#define JPGD_TRUE (1) +#define JPGD_FALSE (0) + +#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b)) +#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b)) + +namespace jpgd { + +static inline void *jpgd_malloc(size_t nSize) { return malloc(nSize); } +static inline void jpgd_free(void *p) { free(p); } + +// DCT coefficients are stored in this sequence. +static int g_ZAG[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; + +enum JPEG_MARKER +{ + M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8, + M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC, + M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7, + M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF, + M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0 +}; + +enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 }; + +#define CONST_BITS 13 +#define PASS1_BITS 2 +#define SCALEDONE ((int32)1) + +#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */ + +#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n)) +#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n)) + +#define MULTIPLY(var, cnst) ((var) * (cnst)) + +#define CLAMP(i) ((static_cast(i) > 255) ? (((~i) >> 31) & 0xFF) : (i)) + +// Compiler creates a fast path 1D IDCT for X non-zero columns +template +struct Row +{ + static void idct(int* pTemp, const jpgd_block_t* pSrc) + { + // ACCESS_COL() will be optimized at compile time to either an array access, or 0. + #define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0) + + const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6); + + const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS; + const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS; + + const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; + + const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1); + + const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3; + const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602); + + const int az1 = MULTIPLY(bz1, - FIX_0_899976223); + const int az2 = MULTIPLY(bz2, - FIX_2_562915447); + const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5; + const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5; + + const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3; + const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4; + const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3; + const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4; + + pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS-PASS1_BITS); + pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS-PASS1_BITS); + pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS-PASS1_BITS); + pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS-PASS1_BITS); + pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS-PASS1_BITS); + pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS-PASS1_BITS); + pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS-PASS1_BITS); + pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS-PASS1_BITS); + } +}; + +template <> +struct Row<0> +{ + static void idct(int* pTemp, const jpgd_block_t* pSrc) + { +#ifdef _MSC_VER + pTemp; pSrc; +#endif + } +}; + +template <> +struct Row<1> +{ + static void idct(int* pTemp, const jpgd_block_t* pSrc) + { + const int dcval = (pSrc[0] << PASS1_BITS); + + pTemp[0] = dcval; + pTemp[1] = dcval; + pTemp[2] = dcval; + pTemp[3] = dcval; + pTemp[4] = dcval; + pTemp[5] = dcval; + pTemp[6] = dcval; + pTemp[7] = dcval; + } +}; + +// Compiler creates a fast path 1D IDCT for X non-zero rows +template +struct Col +{ + static void idct(uint8* pDst_ptr, const int* pTemp) + { + // ACCESS_ROW() will be optimized at compile time to either an array access, or 0. + #define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0) + + const int z2 = ACCESS_ROW(2); + const int z3 = ACCESS_ROW(6); + + const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS; + const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS; + + const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; + + const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1); + + const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3; + const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602); + + const int az1 = MULTIPLY(bz1, - FIX_0_899976223); + const int az2 = MULTIPLY(bz2, - FIX_2_562915447); + const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5; + const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5; + + const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3; + const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4; + const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3; + const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4; + + int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*0] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*7] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*1] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*6] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*2] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*5] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*3] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*4] = (uint8)CLAMP(i); + } +}; + +template <> +struct Col<1> +{ + static void idct(uint8* pDst_ptr, const int* pTemp) + { + int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS+3); + const uint8 dcval_clamped = (uint8)CLAMP(dcval); + pDst_ptr[0*8] = dcval_clamped; + pDst_ptr[1*8] = dcval_clamped; + pDst_ptr[2*8] = dcval_clamped; + pDst_ptr[3*8] = dcval_clamped; + pDst_ptr[4*8] = dcval_clamped; + pDst_ptr[5*8] = dcval_clamped; + pDst_ptr[6*8] = dcval_clamped; + pDst_ptr[7*8] = dcval_clamped; + } +}; + +static const uint8 s_idct_row_table[] = +{ + 1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0, + 4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0, + 6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0, + 6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0, + 8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2, + 8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2, + 8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4, + 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8, +}; + +static const uint8 s_idct_col_table[] = { 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; + +void idct(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag) +{ + JPGD_ASSERT(block_max_zag >= 1); + JPGD_ASSERT(block_max_zag <= 64); + + if (block_max_zag <= 1) + { + int k = ((pSrc_ptr[0] + 4) >> 3) + 128; + k = CLAMP(k); + k = k | (k<<8); + k = k | (k<<16); + + for (int i = 8; i > 0; i--) + { + *(int*)&pDst_ptr[0] = k; + *(int*)&pDst_ptr[4] = k; + pDst_ptr += 8; + } + return; + } + + int temp[64]; + + const jpgd_block_t* pSrc = pSrc_ptr; + int* pTemp = temp; + + const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8]; + int i; + for (i = 8; i > 0; i--, pRow_tab++) + { + switch (*pRow_tab) + { + case 0: Row<0>::idct(pTemp, pSrc); break; + case 1: Row<1>::idct(pTemp, pSrc); break; + case 2: Row<2>::idct(pTemp, pSrc); break; + case 3: Row<3>::idct(pTemp, pSrc); break; + case 4: Row<4>::idct(pTemp, pSrc); break; + case 5: Row<5>::idct(pTemp, pSrc); break; + case 6: Row<6>::idct(pTemp, pSrc); break; + case 7: Row<7>::idct(pTemp, pSrc); break; + case 8: Row<8>::idct(pTemp, pSrc); break; + } + + pSrc += 8; + pTemp += 8; + } + + pTemp = temp; + + const int nonzero_rows = s_idct_col_table[block_max_zag - 1]; + for (i = 8; i > 0; i--) + { + switch (nonzero_rows) + { + case 1: Col<1>::idct(pDst_ptr, pTemp); break; + case 2: Col<2>::idct(pDst_ptr, pTemp); break; + case 3: Col<3>::idct(pDst_ptr, pTemp); break; + case 4: Col<4>::idct(pDst_ptr, pTemp); break; + case 5: Col<5>::idct(pDst_ptr, pTemp); break; + case 6: Col<6>::idct(pDst_ptr, pTemp); break; + case 7: Col<7>::idct(pDst_ptr, pTemp); break; + case 8: Col<8>::idct(pDst_ptr, pTemp); break; + } + + pTemp++; + pDst_ptr++; + } +} + +void idct_4x4(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr) +{ + int temp[64]; + int* pTemp = temp; + const jpgd_block_t* pSrc = pSrc_ptr; + + for (int i = 4; i > 0; i--) + { + Row<4>::idct(pTemp, pSrc); + pSrc += 8; + pTemp += 8; + } + + pTemp = temp; + for (int i = 8; i > 0; i--) + { + Col<4>::idct(pDst_ptr, pTemp); + pTemp++; + pDst_ptr++; + } +} + +// Retrieve one character from the input stream. +inline uint jpeg_decoder::get_char() +{ + // Any bytes remaining in buffer? + if (!m_in_buf_left) + { + // Try to get more bytes. + prep_in_buffer(); + // Still nothing to get? + if (!m_in_buf_left) + { + // Pad the end of the stream with 0xFF 0xD9 (EOI marker) + int t = m_tem_flag; + m_tem_flag ^= 1; + if (t) + return 0xD9; + else + return 0xFF; + } + } + + uint c = *m_pIn_buf_ofs++; + m_in_buf_left--; + + return c; +} + +// Same as previous method, except can indicate if the character is a pad character or not. +inline uint jpeg_decoder::get_char(bool *pPadding_flag) +{ + if (!m_in_buf_left) + { + prep_in_buffer(); + if (!m_in_buf_left) + { + *pPadding_flag = true; + int t = m_tem_flag; + m_tem_flag ^= 1; + if (t) + return 0xD9; + else + return 0xFF; + } + } + + *pPadding_flag = false; + + uint c = *m_pIn_buf_ofs++; + m_in_buf_left--; + + return c; +} + +// Inserts a previously retrieved character back into the input buffer. +inline void jpeg_decoder::stuff_char(uint8 q) +{ + *(--m_pIn_buf_ofs) = q; + m_in_buf_left++; +} + +// Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered. +inline uint8 jpeg_decoder::get_octet() +{ + bool padding_flag; + int c = get_char(&padding_flag); + + if (c == 0xFF) + { + if (padding_flag) + return 0xFF; + + c = get_char(&padding_flag); + if (padding_flag) + { + stuff_char(0xFF); + return 0xFF; + } + + if (c == 0x00) + return 0xFF; + else + { + stuff_char(static_cast(c)); + stuff_char(0xFF); + return 0xFF; + } + } + + return static_cast(c); +} + +// Retrieves a variable number of bits from the input stream. Does not recognize markers. +inline uint jpeg_decoder::get_bits(int num_bits) +{ + if (!num_bits) + return 0; + + uint i = m_bit_buf >> (32 - num_bits); + + if ((m_bits_left -= num_bits) <= 0) + { + m_bit_buf <<= (num_bits += m_bits_left); + + uint c1 = get_char(); + uint c2 = get_char(); + m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2; + + m_bit_buf <<= -m_bits_left; + + m_bits_left += 16; + + JPGD_ASSERT(m_bits_left >= 0); + } + else + m_bit_buf <<= num_bits; + + return i; +} + +// Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered. +inline uint jpeg_decoder::get_bits_no_markers(int num_bits) +{ + if (!num_bits) + return 0; + + uint i = m_bit_buf >> (32 - num_bits); + + if ((m_bits_left -= num_bits) <= 0) + { + m_bit_buf <<= (num_bits += m_bits_left); + + if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF)) + { + uint c1 = get_octet(); + uint c2 = get_octet(); + m_bit_buf |= (c1 << 8) | c2; + } + else + { + m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1]; + m_in_buf_left -= 2; + m_pIn_buf_ofs += 2; + } + + m_bit_buf <<= -m_bits_left; + + m_bits_left += 16; + + JPGD_ASSERT(m_bits_left >= 0); + } + else + m_bit_buf <<= num_bits; + + return i; +} + +// Decodes a Huffman encoded symbol. +inline int jpeg_decoder::huff_decode(huff_tables *pH) +{ + int symbol; + + // Check first 8-bits: do we have a complete symbol? + if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0) + { + // Decode more bits, use a tree traversal to find symbol. + int ofs = 23; + do + { + symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))]; + ofs--; + } while (symbol < 0); + + get_bits_no_markers(8 + (23 - ofs)); + } + else + get_bits_no_markers(pH->code_size[symbol]); + + return symbol; +} + +// Decodes a Huffman encoded symbol. +inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits) +{ + int symbol; + + // Check first 8-bits: do we have a complete symbol? + if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0) + { + // Use a tree traversal to find symbol. + int ofs = 23; + do + { + symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))]; + ofs--; + } while (symbol < 0); + + get_bits_no_markers(8 + (23 - ofs)); + + extra_bits = get_bits_no_markers(symbol & 0xF); + } + else + { + JPGD_ASSERT(((symbol >> 8) & 31) == pH->code_size[symbol & 255] + ((symbol & 0x8000) ? (symbol & 15) : 0)); + + if (symbol & 0x8000) + { + get_bits_no_markers((symbol >> 8) & 31); + extra_bits = symbol >> 16; + } + else + { + int code_size = (symbol >> 8) & 31; + int num_extra_bits = symbol & 0xF; + int bits = code_size + num_extra_bits; + if (bits <= (m_bits_left + 16)) + extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1); + else + { + get_bits_no_markers(code_size); + extra_bits = get_bits_no_markers(num_extra_bits); + } + } + + symbol &= 0xFF; + } + + return symbol; +} + +// Tables and macro used to fully decode the DPCM differences. +static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; +static const int s_extend_offset[16] = { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; +static const int s_extend_mask[] = { 0, (1<<0), (1<<1), (1<<2), (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15), (1<<16) }; +// The logical AND's in this macro are to shut up static code analysis (aren't really necessary - couldn't find another way to do this) +#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x)) + +// Clamps a value between 0-255. +inline uint8 jpeg_decoder::clamp(int i) +{ + if (static_cast(i) > 255) + i = (((~i) >> 31) & 0xFF); + + return static_cast(i); +} + +namespace DCT_Upsample +{ + struct Matrix44 + { + typedef int Element_Type; + enum { NUM_ROWS = 4, NUM_COLS = 4 }; + + Element_Type v[NUM_ROWS][NUM_COLS]; + + inline int rows() const { return NUM_ROWS; } + inline int cols() const { return NUM_COLS; } + + inline const Element_Type & at(int r, int c) const { return v[r][c]; } + inline Element_Type & at(int r, int c) { return v[r][c]; } + + inline Matrix44() { } + + inline Matrix44& operator += (const Matrix44& a) + { + for (int r = 0; r < NUM_ROWS; r++) + { + at(r, 0) += a.at(r, 0); + at(r, 1) += a.at(r, 1); + at(r, 2) += a.at(r, 2); + at(r, 3) += a.at(r, 3); + } + return *this; + } + + inline Matrix44& operator -= (const Matrix44& a) + { + for (int r = 0; r < NUM_ROWS; r++) + { + at(r, 0) -= a.at(r, 0); + at(r, 1) -= a.at(r, 1); + at(r, 2) -= a.at(r, 2); + at(r, 3) -= a.at(r, 3); + } + return *this; + } + + friend inline Matrix44 operator + (const Matrix44& a, const Matrix44& b) + { + Matrix44 ret; + for (int r = 0; r < NUM_ROWS; r++) + { + ret.at(r, 0) = a.at(r, 0) + b.at(r, 0); + ret.at(r, 1) = a.at(r, 1) + b.at(r, 1); + ret.at(r, 2) = a.at(r, 2) + b.at(r, 2); + ret.at(r, 3) = a.at(r, 3) + b.at(r, 3); + } + return ret; + } + + friend inline Matrix44 operator - (const Matrix44& a, const Matrix44& b) + { + Matrix44 ret; + for (int r = 0; r < NUM_ROWS; r++) + { + ret.at(r, 0) = a.at(r, 0) - b.at(r, 0); + ret.at(r, 1) = a.at(r, 1) - b.at(r, 1); + ret.at(r, 2) = a.at(r, 2) - b.at(r, 2); + ret.at(r, 3) = a.at(r, 3) - b.at(r, 3); + } + return ret; + } + + static inline void add_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b) + { + for (int r = 0; r < 4; r++) + { + pDst[0*8 + r] = static_cast(a.at(r, 0) + b.at(r, 0)); + pDst[1*8 + r] = static_cast(a.at(r, 1) + b.at(r, 1)); + pDst[2*8 + r] = static_cast(a.at(r, 2) + b.at(r, 2)); + pDst[3*8 + r] = static_cast(a.at(r, 3) + b.at(r, 3)); + } + } + + static inline void sub_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b) + { + for (int r = 0; r < 4; r++) + { + pDst[0*8 + r] = static_cast(a.at(r, 0) - b.at(r, 0)); + pDst[1*8 + r] = static_cast(a.at(r, 1) - b.at(r, 1)); + pDst[2*8 + r] = static_cast(a.at(r, 2) - b.at(r, 2)); + pDst[3*8 + r] = static_cast(a.at(r, 3) - b.at(r, 3)); + } + } + }; + + const int FRACT_BITS = 10; + const int SCALE = 1 << FRACT_BITS; + + typedef int Temp_Type; + #define D(i) (((i) + (SCALE >> 1)) >> FRACT_BITS) + #define F(i) ((int)((i) * SCALE + .5f)) + + // Any decent C++ compiler will optimize this at compile time to a 0, or an array access. + #define AT(c, r) ((((c)>=NUM_COLS)||((r)>=NUM_ROWS)) ? 0 : pSrc[(c)+(r)*8]) + + // NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix + template + struct P_Q + { + static void calc(Matrix44& P, Matrix44& Q, const jpgd_block_t* pSrc) + { + // 4x8 = 4x8 times 8x8, matrix 0 is constant + const Temp_Type X000 = AT(0, 0); + const Temp_Type X001 = AT(0, 1); + const Temp_Type X002 = AT(0, 2); + const Temp_Type X003 = AT(0, 3); + const Temp_Type X004 = AT(0, 4); + const Temp_Type X005 = AT(0, 5); + const Temp_Type X006 = AT(0, 6); + const Temp_Type X007 = AT(0, 7); + const Temp_Type X010 = D(F(0.415735f) * AT(1, 0) + F(0.791065f) * AT(3, 0) + F(-0.352443f) * AT(5, 0) + F(0.277785f) * AT(7, 0)); + const Temp_Type X011 = D(F(0.415735f) * AT(1, 1) + F(0.791065f) * AT(3, 1) + F(-0.352443f) * AT(5, 1) + F(0.277785f) * AT(7, 1)); + const Temp_Type X012 = D(F(0.415735f) * AT(1, 2) + F(0.791065f) * AT(3, 2) + F(-0.352443f) * AT(5, 2) + F(0.277785f) * AT(7, 2)); + const Temp_Type X013 = D(F(0.415735f) * AT(1, 3) + F(0.791065f) * AT(3, 3) + F(-0.352443f) * AT(5, 3) + F(0.277785f) * AT(7, 3)); + const Temp_Type X014 = D(F(0.415735f) * AT(1, 4) + F(0.791065f) * AT(3, 4) + F(-0.352443f) * AT(5, 4) + F(0.277785f) * AT(7, 4)); + const Temp_Type X015 = D(F(0.415735f) * AT(1, 5) + F(0.791065f) * AT(3, 5) + F(-0.352443f) * AT(5, 5) + F(0.277785f) * AT(7, 5)); + const Temp_Type X016 = D(F(0.415735f) * AT(1, 6) + F(0.791065f) * AT(3, 6) + F(-0.352443f) * AT(5, 6) + F(0.277785f) * AT(7, 6)); + const Temp_Type X017 = D(F(0.415735f) * AT(1, 7) + F(0.791065f) * AT(3, 7) + F(-0.352443f) * AT(5, 7) + F(0.277785f) * AT(7, 7)); + const Temp_Type X020 = AT(4, 0); + const Temp_Type X021 = AT(4, 1); + const Temp_Type X022 = AT(4, 2); + const Temp_Type X023 = AT(4, 3); + const Temp_Type X024 = AT(4, 4); + const Temp_Type X025 = AT(4, 5); + const Temp_Type X026 = AT(4, 6); + const Temp_Type X027 = AT(4, 7); + const Temp_Type X030 = D(F(0.022887f) * AT(1, 0) + F(-0.097545f) * AT(3, 0) + F(0.490393f) * AT(5, 0) + F(0.865723f) * AT(7, 0)); + const Temp_Type X031 = D(F(0.022887f) * AT(1, 1) + F(-0.097545f) * AT(3, 1) + F(0.490393f) * AT(5, 1) + F(0.865723f) * AT(7, 1)); + const Temp_Type X032 = D(F(0.022887f) * AT(1, 2) + F(-0.097545f) * AT(3, 2) + F(0.490393f) * AT(5, 2) + F(0.865723f) * AT(7, 2)); + const Temp_Type X033 = D(F(0.022887f) * AT(1, 3) + F(-0.097545f) * AT(3, 3) + F(0.490393f) * AT(5, 3) + F(0.865723f) * AT(7, 3)); + const Temp_Type X034 = D(F(0.022887f) * AT(1, 4) + F(-0.097545f) * AT(3, 4) + F(0.490393f) * AT(5, 4) + F(0.865723f) * AT(7, 4)); + const Temp_Type X035 = D(F(0.022887f) * AT(1, 5) + F(-0.097545f) * AT(3, 5) + F(0.490393f) * AT(5, 5) + F(0.865723f) * AT(7, 5)); + const Temp_Type X036 = D(F(0.022887f) * AT(1, 6) + F(-0.097545f) * AT(3, 6) + F(0.490393f) * AT(5, 6) + F(0.865723f) * AT(7, 6)); + const Temp_Type X037 = D(F(0.022887f) * AT(1, 7) + F(-0.097545f) * AT(3, 7) + F(0.490393f) * AT(5, 7) + F(0.865723f) * AT(7, 7)); + + // 4x4 = 4x8 times 8x4, matrix 1 is constant + P.at(0, 0) = X000; + P.at(0, 1) = D(X001 * F(0.415735f) + X003 * F(0.791065f) + X005 * F(-0.352443f) + X007 * F(0.277785f)); + P.at(0, 2) = X004; + P.at(0, 3) = D(X001 * F(0.022887f) + X003 * F(-0.097545f) + X005 * F(0.490393f) + X007 * F(0.865723f)); + P.at(1, 0) = X010; + P.at(1, 1) = D(X011 * F(0.415735f) + X013 * F(0.791065f) + X015 * F(-0.352443f) + X017 * F(0.277785f)); + P.at(1, 2) = X014; + P.at(1, 3) = D(X011 * F(0.022887f) + X013 * F(-0.097545f) + X015 * F(0.490393f) + X017 * F(0.865723f)); + P.at(2, 0) = X020; + P.at(2, 1) = D(X021 * F(0.415735f) + X023 * F(0.791065f) + X025 * F(-0.352443f) + X027 * F(0.277785f)); + P.at(2, 2) = X024; + P.at(2, 3) = D(X021 * F(0.022887f) + X023 * F(-0.097545f) + X025 * F(0.490393f) + X027 * F(0.865723f)); + P.at(3, 0) = X030; + P.at(3, 1) = D(X031 * F(0.415735f) + X033 * F(0.791065f) + X035 * F(-0.352443f) + X037 * F(0.277785f)); + P.at(3, 2) = X034; + P.at(3, 3) = D(X031 * F(0.022887f) + X033 * F(-0.097545f) + X035 * F(0.490393f) + X037 * F(0.865723f)); + // 40 muls 24 adds + + // 4x4 = 4x8 times 8x4, matrix 1 is constant + Q.at(0, 0) = D(X001 * F(0.906127f) + X003 * F(-0.318190f) + X005 * F(0.212608f) + X007 * F(-0.180240f)); + Q.at(0, 1) = X002; + Q.at(0, 2) = D(X001 * F(-0.074658f) + X003 * F(0.513280f) + X005 * F(0.768178f) + X007 * F(-0.375330f)); + Q.at(0, 3) = X006; + Q.at(1, 0) = D(X011 * F(0.906127f) + X013 * F(-0.318190f) + X015 * F(0.212608f) + X017 * F(-0.180240f)); + Q.at(1, 1) = X012; + Q.at(1, 2) = D(X011 * F(-0.074658f) + X013 * F(0.513280f) + X015 * F(0.768178f) + X017 * F(-0.375330f)); + Q.at(1, 3) = X016; + Q.at(2, 0) = D(X021 * F(0.906127f) + X023 * F(-0.318190f) + X025 * F(0.212608f) + X027 * F(-0.180240f)); + Q.at(2, 1) = X022; + Q.at(2, 2) = D(X021 * F(-0.074658f) + X023 * F(0.513280f) + X025 * F(0.768178f) + X027 * F(-0.375330f)); + Q.at(2, 3) = X026; + Q.at(3, 0) = D(X031 * F(0.906127f) + X033 * F(-0.318190f) + X035 * F(0.212608f) + X037 * F(-0.180240f)); + Q.at(3, 1) = X032; + Q.at(3, 2) = D(X031 * F(-0.074658f) + X033 * F(0.513280f) + X035 * F(0.768178f) + X037 * F(-0.375330f)); + Q.at(3, 3) = X036; + // 40 muls 24 adds + } + }; + + template + struct R_S + { + static void calc(Matrix44& R, Matrix44& S, const jpgd_block_t* pSrc) + { + // 4x8 = 4x8 times 8x8, matrix 0 is constant + const Temp_Type X100 = D(F(0.906127f) * AT(1, 0) + F(-0.318190f) * AT(3, 0) + F(0.212608f) * AT(5, 0) + F(-0.180240f) * AT(7, 0)); + const Temp_Type X101 = D(F(0.906127f) * AT(1, 1) + F(-0.318190f) * AT(3, 1) + F(0.212608f) * AT(5, 1) + F(-0.180240f) * AT(7, 1)); + const Temp_Type X102 = D(F(0.906127f) * AT(1, 2) + F(-0.318190f) * AT(3, 2) + F(0.212608f) * AT(5, 2) + F(-0.180240f) * AT(7, 2)); + const Temp_Type X103 = D(F(0.906127f) * AT(1, 3) + F(-0.318190f) * AT(3, 3) + F(0.212608f) * AT(5, 3) + F(-0.180240f) * AT(7, 3)); + const Temp_Type X104 = D(F(0.906127f) * AT(1, 4) + F(-0.318190f) * AT(3, 4) + F(0.212608f) * AT(5, 4) + F(-0.180240f) * AT(7, 4)); + const Temp_Type X105 = D(F(0.906127f) * AT(1, 5) + F(-0.318190f) * AT(3, 5) + F(0.212608f) * AT(5, 5) + F(-0.180240f) * AT(7, 5)); + const Temp_Type X106 = D(F(0.906127f) * AT(1, 6) + F(-0.318190f) * AT(3, 6) + F(0.212608f) * AT(5, 6) + F(-0.180240f) * AT(7, 6)); + const Temp_Type X107 = D(F(0.906127f) * AT(1, 7) + F(-0.318190f) * AT(3, 7) + F(0.212608f) * AT(5, 7) + F(-0.180240f) * AT(7, 7)); + const Temp_Type X110 = AT(2, 0); + const Temp_Type X111 = AT(2, 1); + const Temp_Type X112 = AT(2, 2); + const Temp_Type X113 = AT(2, 3); + const Temp_Type X114 = AT(2, 4); + const Temp_Type X115 = AT(2, 5); + const Temp_Type X116 = AT(2, 6); + const Temp_Type X117 = AT(2, 7); + const Temp_Type X120 = D(F(-0.074658f) * AT(1, 0) + F(0.513280f) * AT(3, 0) + F(0.768178f) * AT(5, 0) + F(-0.375330f) * AT(7, 0)); + const Temp_Type X121 = D(F(-0.074658f) * AT(1, 1) + F(0.513280f) * AT(3, 1) + F(0.768178f) * AT(5, 1) + F(-0.375330f) * AT(7, 1)); + const Temp_Type X122 = D(F(-0.074658f) * AT(1, 2) + F(0.513280f) * AT(3, 2) + F(0.768178f) * AT(5, 2) + F(-0.375330f) * AT(7, 2)); + const Temp_Type X123 = D(F(-0.074658f) * AT(1, 3) + F(0.513280f) * AT(3, 3) + F(0.768178f) * AT(5, 3) + F(-0.375330f) * AT(7, 3)); + const Temp_Type X124 = D(F(-0.074658f) * AT(1, 4) + F(0.513280f) * AT(3, 4) + F(0.768178f) * AT(5, 4) + F(-0.375330f) * AT(7, 4)); + const Temp_Type X125 = D(F(-0.074658f) * AT(1, 5) + F(0.513280f) * AT(3, 5) + F(0.768178f) * AT(5, 5) + F(-0.375330f) * AT(7, 5)); + const Temp_Type X126 = D(F(-0.074658f) * AT(1, 6) + F(0.513280f) * AT(3, 6) + F(0.768178f) * AT(5, 6) + F(-0.375330f) * AT(7, 6)); + const Temp_Type X127 = D(F(-0.074658f) * AT(1, 7) + F(0.513280f) * AT(3, 7) + F(0.768178f) * AT(5, 7) + F(-0.375330f) * AT(7, 7)); + const Temp_Type X130 = AT(6, 0); + const Temp_Type X131 = AT(6, 1); + const Temp_Type X132 = AT(6, 2); + const Temp_Type X133 = AT(6, 3); + const Temp_Type X134 = AT(6, 4); + const Temp_Type X135 = AT(6, 5); + const Temp_Type X136 = AT(6, 6); + const Temp_Type X137 = AT(6, 7); + // 80 muls 48 adds + + // 4x4 = 4x8 times 8x4, matrix 1 is constant + R.at(0, 0) = X100; + R.at(0, 1) = D(X101 * F(0.415735f) + X103 * F(0.791065f) + X105 * F(-0.352443f) + X107 * F(0.277785f)); + R.at(0, 2) = X104; + R.at(0, 3) = D(X101 * F(0.022887f) + X103 * F(-0.097545f) + X105 * F(0.490393f) + X107 * F(0.865723f)); + R.at(1, 0) = X110; + R.at(1, 1) = D(X111 * F(0.415735f) + X113 * F(0.791065f) + X115 * F(-0.352443f) + X117 * F(0.277785f)); + R.at(1, 2) = X114; + R.at(1, 3) = D(X111 * F(0.022887f) + X113 * F(-0.097545f) + X115 * F(0.490393f) + X117 * F(0.865723f)); + R.at(2, 0) = X120; + R.at(2, 1) = D(X121 * F(0.415735f) + X123 * F(0.791065f) + X125 * F(-0.352443f) + X127 * F(0.277785f)); + R.at(2, 2) = X124; + R.at(2, 3) = D(X121 * F(0.022887f) + X123 * F(-0.097545f) + X125 * F(0.490393f) + X127 * F(0.865723f)); + R.at(3, 0) = X130; + R.at(3, 1) = D(X131 * F(0.415735f) + X133 * F(0.791065f) + X135 * F(-0.352443f) + X137 * F(0.277785f)); + R.at(3, 2) = X134; + R.at(3, 3) = D(X131 * F(0.022887f) + X133 * F(-0.097545f) + X135 * F(0.490393f) + X137 * F(0.865723f)); + // 40 muls 24 adds + // 4x4 = 4x8 times 8x4, matrix 1 is constant + S.at(0, 0) = D(X101 * F(0.906127f) + X103 * F(-0.318190f) + X105 * F(0.212608f) + X107 * F(-0.180240f)); + S.at(0, 1) = X102; + S.at(0, 2) = D(X101 * F(-0.074658f) + X103 * F(0.513280f) + X105 * F(0.768178f) + X107 * F(-0.375330f)); + S.at(0, 3) = X106; + S.at(1, 0) = D(X111 * F(0.906127f) + X113 * F(-0.318190f) + X115 * F(0.212608f) + X117 * F(-0.180240f)); + S.at(1, 1) = X112; + S.at(1, 2) = D(X111 * F(-0.074658f) + X113 * F(0.513280f) + X115 * F(0.768178f) + X117 * F(-0.375330f)); + S.at(1, 3) = X116; + S.at(2, 0) = D(X121 * F(0.906127f) + X123 * F(-0.318190f) + X125 * F(0.212608f) + X127 * F(-0.180240f)); + S.at(2, 1) = X122; + S.at(2, 2) = D(X121 * F(-0.074658f) + X123 * F(0.513280f) + X125 * F(0.768178f) + X127 * F(-0.375330f)); + S.at(2, 3) = X126; + S.at(3, 0) = D(X131 * F(0.906127f) + X133 * F(-0.318190f) + X135 * F(0.212608f) + X137 * F(-0.180240f)); + S.at(3, 1) = X132; + S.at(3, 2) = D(X131 * F(-0.074658f) + X133 * F(0.513280f) + X135 * F(0.768178f) + X137 * F(-0.375330f)); + S.at(3, 3) = X136; + // 40 muls 24 adds + } + }; +} // end namespace DCT_Upsample + +// Unconditionally frees all allocated m_blocks. +void jpeg_decoder::free_all_blocks() +{ + m_pStream = NULL; + for (mem_block *b = m_pMem_blocks; b; ) + { + mem_block *n = b->m_pNext; + jpgd_free(b); + b = n; + } + m_pMem_blocks = NULL; +} + +// This method handles all errors. It will never return. +// It could easily be changed to use C++ exceptions. +JPGD_NORETURN void jpeg_decoder::stop_decoding(jpgd_status status) +{ + m_error_code = status; + free_all_blocks(); + longjmp(m_jmp_state, status); +} + +void *jpeg_decoder::alloc(size_t nSize, bool zero) +{ + nSize = (JPGD_MAX(nSize, 1) + 3) & ~3; + char *rv = NULL; + for (mem_block *b = m_pMem_blocks; b; b = b->m_pNext) + { + if ((b->m_used_count + nSize) <= b->m_size) + { + rv = b->m_data + b->m_used_count; + b->m_used_count += nSize; + break; + } + } + if (!rv) + { + int capacity = JPGD_MAX(32768 - 256, (nSize + 2047) & ~2047); + mem_block *b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity); + if (!b) { stop_decoding(JPGD_NOTENOUGHMEM); } + b->m_pNext = m_pMem_blocks; m_pMem_blocks = b; + b->m_used_count = nSize; + b->m_size = capacity; + rv = b->m_data; + } + if (zero) memset(rv, 0, nSize); + return rv; +} + +void jpeg_decoder::word_clear(void *p, uint16 c, uint n) +{ + uint8 *pD = (uint8*)p; + const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF; + while (n) + { + pD[0] = l; pD[1] = h; pD += 2; + n--; + } +} + +// Refill the input buffer. +// This method will sit in a loop until (A) the buffer is full or (B) +// the stream's read() method reports and end of file condition. +void jpeg_decoder::prep_in_buffer() +{ + m_in_buf_left = 0; + m_pIn_buf_ofs = m_in_buf; + + if (m_eof_flag) + return; + + do + { + int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag); + if (bytes_read == -1) + stop_decoding(JPGD_STREAM_READ); + + m_in_buf_left += bytes_read; + } while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag)); + + m_total_bytes_read += m_in_buf_left; + + // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid). + // (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.) + word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64); +} + +// Read a Huffman code table. +void jpeg_decoder::read_dht_marker() +{ + int i, index, count; + uint8 huff_num[17]; + uint8 huff_val[256]; + + uint num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_DHT_MARKER); + + num_left -= 2; + + while (num_left) + { + index = get_bits(8); + + huff_num[0] = 0; + + count = 0; + + for (i = 1; i <= 16; i++) + { + huff_num[i] = static_cast(get_bits(8)); + count += huff_num[i]; + } + + if (count > 255) + stop_decoding(JPGD_BAD_DHT_COUNTS); + + for (i = 0; i < count; i++) + huff_val[i] = static_cast(get_bits(8)); + + i = 1 + 16 + count; + + if (num_left < (uint)i) + stop_decoding(JPGD_BAD_DHT_MARKER); + + num_left -= i; + + if ((index & 0x10) > 0x10) + stop_decoding(JPGD_BAD_DHT_INDEX); + + index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1); + + if (index >= JPGD_MAX_HUFF_TABLES) + stop_decoding(JPGD_BAD_DHT_INDEX); + + if (!m_huff_num[index]) + m_huff_num[index] = (uint8 *)alloc(17); + + if (!m_huff_val[index]) + m_huff_val[index] = (uint8 *)alloc(256); + + m_huff_ac[index] = (index & 0x10) != 0; + memcpy(m_huff_num[index], huff_num, 17); + memcpy(m_huff_val[index], huff_val, 256); + } +} + +// Read a quantization table. +void jpeg_decoder::read_dqt_marker() +{ + int n, i, prec; + uint num_left; + uint temp; + + num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_DQT_MARKER); + + num_left -= 2; + + while (num_left) + { + n = get_bits(8); + prec = n >> 4; + n &= 0x0F; + + if (n >= JPGD_MAX_QUANT_TABLES) + stop_decoding(JPGD_BAD_DQT_TABLE); + + if (!m_quant[n]) + m_quant[n] = (jpgd_quant_t *)alloc(64 * sizeof(jpgd_quant_t)); + + // read quantization entries, in zag order + for (i = 0; i < 64; i++) + { + temp = get_bits(8); + + if (prec) + temp = (temp << 8) + get_bits(8); + + m_quant[n][i] = static_cast(temp); + } + + i = 64 + 1; + + if (prec) + i += 64; + + if (num_left < (uint)i) + stop_decoding(JPGD_BAD_DQT_LENGTH); + + num_left -= i; + } +} + +// Read the start of frame (SOF) marker. +void jpeg_decoder::read_sof_marker() +{ + int i; + uint num_left; + + num_left = get_bits(16); + + if (get_bits(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */ + stop_decoding(JPGD_BAD_PRECISION); + + m_image_y_size = get_bits(16); + + if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT)) + stop_decoding(JPGD_BAD_HEIGHT); + + m_image_x_size = get_bits(16); + + if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH)) + stop_decoding(JPGD_BAD_WIDTH); + + m_comps_in_frame = get_bits(8); + + if (m_comps_in_frame > JPGD_MAX_COMPONENTS) + stop_decoding(JPGD_TOO_MANY_COMPONENTS); + + if (num_left != (uint)(m_comps_in_frame * 3 + 8)) + stop_decoding(JPGD_BAD_SOF_LENGTH); + + for (i = 0; i < m_comps_in_frame; i++) + { + m_comp_ident[i] = get_bits(8); + m_comp_h_samp[i] = get_bits(4); + m_comp_v_samp[i] = get_bits(4); + m_comp_quant[i] = get_bits(8); + } +} + +// Used to skip unrecognized markers. +void jpeg_decoder::skip_variable_marker() +{ + uint num_left; + + num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_VARIABLE_MARKER); + + num_left -= 2; + + while (num_left) + { + get_bits(8); + num_left--; + } +} + +// Read a define restart interval (DRI) marker. +void jpeg_decoder::read_dri_marker() +{ + if (get_bits(16) != 4) + stop_decoding(JPGD_BAD_DRI_LENGTH); + + m_restart_interval = get_bits(16); +} + +// Read a start of scan (SOS) marker. +void jpeg_decoder::read_sos_marker() +{ + uint num_left; + int i, ci, n, c, cc; + + num_left = get_bits(16); + + n = get_bits(8); + + m_comps_in_scan = n; + + num_left -= 3; + + if ( (num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN) ) + stop_decoding(JPGD_BAD_SOS_LENGTH); + + for (i = 0; i < n; i++) + { + cc = get_bits(8); + c = get_bits(8); + num_left -= 2; + + for (ci = 0; ci < m_comps_in_frame; ci++) + if (cc == m_comp_ident[ci]) + break; + + if (ci >= m_comps_in_frame) + stop_decoding(JPGD_BAD_SOS_COMP_ID); + + m_comp_list[i] = ci; + m_comp_dc_tab[ci] = (c >> 4) & 15; + m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1); + } + + m_spectral_start = get_bits(8); + m_spectral_end = get_bits(8); + m_successive_high = get_bits(4); + m_successive_low = get_bits(4); + + if (!m_progressive_flag) + { + m_spectral_start = 0; + m_spectral_end = 63; + } + + num_left -= 3; + + while (num_left) /* read past whatever is num_left */ + { + get_bits(8); + num_left--; + } +} + +// Finds the next marker. +int jpeg_decoder::next_marker() +{ + uint c, bytes; + + bytes = 0; + + do + { + do + { + bytes++; + c = get_bits(8); + } while (c != 0xFF); + + do + { + c = get_bits(8); + } while (c == 0xFF); + + } while (c == 0); + + // If bytes > 0 here, there where extra bytes before the marker (not good). + + return c; +} + +// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is +// encountered. +int jpeg_decoder::process_markers() +{ + int c; + + for ( ; ; ) + { + c = next_marker(); + + switch (c) + { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: +// case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + { + return c; + } + case M_DHT: + { + read_dht_marker(); + break; + } + // No arithmitic support - dumb patents! + case M_DAC: + { + stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT); + break; + } + case M_DQT: + { + read_dqt_marker(); + break; + } + case M_DRI: + { + read_dri_marker(); + break; + } + //case M_APP0: /* no need to read the JFIF marker */ + + case M_JPG: + case M_RST0: /* no parameters */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + { + stop_decoding(JPGD_UNEXPECTED_MARKER); + break; + } + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ + { + skip_variable_marker(); + break; + } + } + } +} + +// Finds the start of image (SOI) marker. +// This code is rather defensive: it only checks the first 512 bytes to avoid +// false positives. +void jpeg_decoder::locate_soi_marker() +{ + uint lastchar, thischar; + uint bytesleft; + + lastchar = get_bits(8); + + thischar = get_bits(8); + + /* ok if it's a normal JPEG file without a special header */ + + if ((lastchar == 0xFF) && (thischar == M_SOI)) + return; + + bytesleft = 4096; //512; + + for ( ; ; ) + { + if (--bytesleft == 0) + stop_decoding(JPGD_NOT_JPEG); + + lastchar = thischar; + + thischar = get_bits(8); + + if (lastchar == 0xFF) + { + if (thischar == M_SOI) + break; + else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end + stop_decoding(JPGD_NOT_JPEG); + } + } + + // Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad. + thischar = (m_bit_buf >> 24) & 0xFF; + + if (thischar != 0xFF) + stop_decoding(JPGD_NOT_JPEG); +} + +// Find a start of frame (SOF) marker. +void jpeg_decoder::locate_sof_marker() +{ + locate_soi_marker(); + + int c = process_markers(); + + switch (c) + { + case M_SOF2: + m_progressive_flag = JPGD_TRUE; + case M_SOF0: /* baseline DCT */ + case M_SOF1: /* extended sequential DCT */ + { + read_sof_marker(); + break; + } + case M_SOF9: /* Arithmitic coding */ + { + stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT); + break; + } + default: + { + stop_decoding(JPGD_UNSUPPORTED_MARKER); + break; + } + } +} + +// Find a start of scan (SOS) marker. +int jpeg_decoder::locate_sos_marker() +{ + int c; + + c = process_markers(); + + if (c == M_EOI) + return JPGD_FALSE; + else if (c != M_SOS) + stop_decoding(JPGD_UNEXPECTED_MARKER); + + read_sos_marker(); + + return JPGD_TRUE; +} + +// Reset everything to default/uninitialized state. +void jpeg_decoder::init(jpeg_decoder_stream *pStream) +{ + m_pMem_blocks = NULL; + m_error_code = JPGD_SUCCESS; + m_ready_flag = false; + m_image_x_size = m_image_y_size = 0; + m_pStream = pStream; + m_progressive_flag = JPGD_FALSE; + + memset(m_huff_ac, 0, sizeof(m_huff_ac)); + memset(m_huff_num, 0, sizeof(m_huff_num)); + memset(m_huff_val, 0, sizeof(m_huff_val)); + memset(m_quant, 0, sizeof(m_quant)); + + m_scan_type = 0; + m_comps_in_frame = 0; + + memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp)); + memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp)); + memset(m_comp_quant, 0, sizeof(m_comp_quant)); + memset(m_comp_ident, 0, sizeof(m_comp_ident)); + memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks)); + memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks)); + + m_comps_in_scan = 0; + memset(m_comp_list, 0, sizeof(m_comp_list)); + memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab)); + memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab)); + + m_spectral_start = 0; + m_spectral_end = 0; + m_successive_low = 0; + m_successive_high = 0; + m_max_mcu_x_size = 0; + m_max_mcu_y_size = 0; + m_blocks_per_mcu = 0; + m_max_blocks_per_row = 0; + m_mcus_per_row = 0; + m_mcus_per_col = 0; + m_expanded_blocks_per_component = 0; + m_expanded_blocks_per_mcu = 0; + m_expanded_blocks_per_row = 0; + m_freq_domain_chroma_upsample = false; + + memset(m_mcu_org, 0, sizeof(m_mcu_org)); + + m_total_lines_left = 0; + m_mcu_lines_left = 0; + m_real_dest_bytes_per_scan_line = 0; + m_dest_bytes_per_scan_line = 0; + m_dest_bytes_per_pixel = 0; + + memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs)); + + memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs)); + memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs)); + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + m_eob_run = 0; + + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + m_pIn_buf_ofs = m_in_buf; + m_in_buf_left = 0; + m_eof_flag = false; + m_tem_flag = 0; + + memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start)); + memset(m_in_buf, 0, sizeof(m_in_buf)); + memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end)); + + m_restart_interval = 0; + m_restarts_left = 0; + m_next_restart_num = 0; + + m_max_mcus_per_row = 0; + m_max_blocks_per_mcu = 0; + m_max_mcus_per_col = 0; + + memset(m_last_dc_val, 0, sizeof(m_last_dc_val)); + m_pMCU_coefficients = NULL; + m_pSample_buf = NULL; + + m_total_bytes_read = 0; + + m_pScan_line_0 = NULL; + m_pScan_line_1 = NULL; + + // Ready the input buffer. + prep_in_buffer(); + + // Prime the bit buffer. + m_bits_left = 16; + m_bit_buf = 0; + + get_bits(16); + get_bits(16); + + for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++) + m_mcu_block_max_zag[i] = 64; +} + +#define SCALEBITS 16 +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) +#define FIX(x) ((int) ((x) * (1L<> SCALEBITS; + m_cbb[i] = ( FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS; + m_crg[i] = (-FIX(0.71414f)) * k; + m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF; + } +} + +// This method throws back into the stream any bytes that where read +// into the bit buffer during initial marker scanning. +void jpeg_decoder::fix_in_buffer() +{ + // In case any 0xFF's where pulled into the buffer during marker scanning. + JPGD_ASSERT((m_bits_left & 7) == 0); + + if (m_bits_left == 16) + stuff_char( (uint8)(m_bit_buf & 0xFF)); + + if (m_bits_left >= 8) + stuff_char( (uint8)((m_bit_buf >> 8) & 0xFF)); + + stuff_char((uint8)((m_bit_buf >> 16) & 0xFF)); + stuff_char((uint8)((m_bit_buf >> 24) & 0xFF)); + + m_bits_left = 16; + get_bits_no_markers(16); + get_bits_no_markers(16); +} + +void jpeg_decoder::transform_mcu(int mcu_row) +{ + jpgd_block_t* pSrc_ptr = m_pMCU_coefficients; + uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64; + + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]); + pSrc_ptr += 64; + pDst_ptr += 64; + } +} + +static const uint8 s_max_rc[64] = +{ + 17, 18, 34, 50, 50, 51, 52, 52, 52, 68, 84, 84, 84, 84, 85, 86, 86, 86, 86, 86, + 102, 118, 118, 118, 118, 118, 118, 119, 120, 120, 120, 120, 120, 120, 120, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136 +}; + +void jpeg_decoder::transform_mcu_expand(int mcu_row) +{ + jpgd_block_t* pSrc_ptr = m_pMCU_coefficients; + uint8* pDst_ptr = m_pSample_buf + mcu_row * m_expanded_blocks_per_mcu * 64; + + // Y IDCT + int mcu_block; + for (mcu_block = 0; mcu_block < m_expanded_blocks_per_component; mcu_block++) + { + idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]); + pSrc_ptr += 64; + pDst_ptr += 64; + } + + // Chroma IDCT, with upsampling + jpgd_block_t temp_block[64]; + + for (int i = 0; i < 2; i++) + { + DCT_Upsample::Matrix44 P, Q, R, S; + + JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] >= 1); + JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] <= 64); + + int max_zag = m_mcu_block_max_zag[mcu_block++] - 1; + if (max_zag <= 0) max_zag = 0; // should never happen, only here to shut up static analysis + switch (s_max_rc[max_zag]) + { + case 1*16+1: + DCT_Upsample::P_Q<1, 1>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<1, 1>::calc(R, S, pSrc_ptr); + break; + case 1*16+2: + DCT_Upsample::P_Q<1, 2>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<1, 2>::calc(R, S, pSrc_ptr); + break; + case 2*16+2: + DCT_Upsample::P_Q<2, 2>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<2, 2>::calc(R, S, pSrc_ptr); + break; + case 3*16+2: + DCT_Upsample::P_Q<3, 2>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<3, 2>::calc(R, S, pSrc_ptr); + break; + case 3*16+3: + DCT_Upsample::P_Q<3, 3>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<3, 3>::calc(R, S, pSrc_ptr); + break; + case 3*16+4: + DCT_Upsample::P_Q<3, 4>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<3, 4>::calc(R, S, pSrc_ptr); + break; + case 4*16+4: + DCT_Upsample::P_Q<4, 4>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<4, 4>::calc(R, S, pSrc_ptr); + break; + case 5*16+4: + DCT_Upsample::P_Q<5, 4>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<5, 4>::calc(R, S, pSrc_ptr); + break; + case 5*16+5: + DCT_Upsample::P_Q<5, 5>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<5, 5>::calc(R, S, pSrc_ptr); + break; + case 5*16+6: + DCT_Upsample::P_Q<5, 6>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<5, 6>::calc(R, S, pSrc_ptr); + break; + case 6*16+6: + DCT_Upsample::P_Q<6, 6>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<6, 6>::calc(R, S, pSrc_ptr); + break; + case 7*16+6: + DCT_Upsample::P_Q<7, 6>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<7, 6>::calc(R, S, pSrc_ptr); + break; + case 7*16+7: + DCT_Upsample::P_Q<7, 7>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<7, 7>::calc(R, S, pSrc_ptr); + break; + case 7*16+8: + DCT_Upsample::P_Q<7, 8>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<7, 8>::calc(R, S, pSrc_ptr); + break; + case 8*16+8: + DCT_Upsample::P_Q<8, 8>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<8, 8>::calc(R, S, pSrc_ptr); + break; + default: + JPGD_ASSERT(false); + } + + DCT_Upsample::Matrix44 a(P + Q); P -= Q; + DCT_Upsample::Matrix44& b = P; + DCT_Upsample::Matrix44 c(R + S); R -= S; + DCT_Upsample::Matrix44& d = R; + + DCT_Upsample::Matrix44::add_and_store(temp_block, a, c); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + DCT_Upsample::Matrix44::sub_and_store(temp_block, a, c); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + DCT_Upsample::Matrix44::add_and_store(temp_block, b, d); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + DCT_Upsample::Matrix44::sub_and_store(temp_block, b, d); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + pSrc_ptr += 64; + } +} + +// Loads and dequantizes the next row of (already decoded) coefficients. +// Progressive images only. +void jpeg_decoder::load_next_row() +{ + int i; + jpgd_block_t *p; + jpgd_quant_t *q; + int mcu_row, mcu_block, row_block = 0; + int component_num, component_id; + int block_x_mcu[JPGD_MAX_COMPONENTS]; + + memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int)); + + for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; + + for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + component_id = m_mcu_org[mcu_block]; + q = m_quant[m_comp_quant[component_id]]; + + p = m_pMCU_coefficients + 64 * mcu_block; + + jpgd_block_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + jpgd_block_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + p[0] = pDC[0]; + memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t)); + + for (i = 63; i > 0; i--) + if (p[g_ZAG[i]]) + break; + + m_mcu_block_max_zag[mcu_block] = i + 1; + + for ( ; i >= 0; i--) + if (p[g_ZAG[i]]) + p[g_ZAG[i]] = static_cast(p[g_ZAG[i]] * q[i]); + + row_block++; + + if (m_comps_in_scan == 1) + block_x_mcu[component_id]++; + else + { + if (++block_x_mcu_ofs == m_comp_h_samp[component_id]) + { + block_x_mcu_ofs = 0; + + if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) + { + block_y_mcu_ofs = 0; + + block_x_mcu[component_id] += m_comp_h_samp[component_id]; + } + } + } + } + + if (m_freq_domain_chroma_upsample) + transform_mcu_expand(mcu_row); + else + transform_mcu(mcu_row); + } + + if (m_comps_in_scan == 1) + m_block_y_mcu[m_comp_list[0]]++; + else + { + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + component_id = m_comp_list[component_num]; + + m_block_y_mcu[component_id] += m_comp_v_samp[component_id]; + } + } +} + +// Restart interval processing. +void jpeg_decoder::process_restart() +{ + int i; + int c = 0; + + // Align to a byte boundry + // FIXME: Is this really necessary? get_bits_no_markers() never reads in markers! + //get_bits_no_markers(m_bits_left & 7); + + // Let's scan a little bit to find the marker, but not _too_ far. + // 1536 is a "fudge factor" that determines how much to scan. + for (i = 1536; i > 0; i--) + if (get_char() == 0xFF) + break; + + if (i == 0) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + for ( ; i > 0; i--) + if ((c = get_char()) != 0xFF) + break; + + if (i == 0) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + // Is it the expected marker? If not, something bad happened. + if (c != (m_next_restart_num + M_RST0)) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + // Reset each component's DC prediction values. + memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint)); + + m_eob_run = 0; + + m_restarts_left = m_restart_interval; + + m_next_restart_num = (m_next_restart_num + 1) & 7; + + // Get the bit buffer going again... + + m_bits_left = 16; + get_bits_no_markers(16); + get_bits_no_markers(16); +} + +static inline int dequantize_ac(int c, int q) { c *= q; return c; } + +// Decodes and dequantizes the next row of coefficients. +void jpeg_decoder::decode_next_row() +{ + int row_block = 0; + + for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + if ((m_restart_interval) && (m_restarts_left == 0)) + process_restart(); + + jpgd_block_t* p = m_pMCU_coefficients; + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64) + { + int component_id = m_mcu_org[mcu_block]; + jpgd_quant_t* q = m_quant[m_comp_quant[component_id]]; + + int r, s; + s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r); + s = JPGD_HUFF_EXTEND(r, s); + + m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]); + + p[0] = static_cast(s * q[0]); + + int prev_num_set = m_mcu_block_max_zag[mcu_block]; + + huff_tables *pH = m_pHuff_tabs[m_comp_ac_tab[component_id]]; + + int k; + for (k = 1; k < 64; k++) + { + int extra_bits; + s = huff_decode(pH, extra_bits); + + r = s >> 4; + s &= 15; + + if (s) + { + if (r) + { + if ((k + r) > 63) + stop_decoding(JPGD_DECODE_ERROR); + + if (k < prev_num_set) + { + int n = JPGD_MIN(r, prev_num_set - k); + int kt = k; + while (n--) + p[g_ZAG[kt++]] = 0; + } + + k += r; + } + + s = JPGD_HUFF_EXTEND(extra_bits, s); + + JPGD_ASSERT(k < 64); + + p[g_ZAG[k]] = static_cast(dequantize_ac(s, q[k])); //s * q[k]; + } + else + { + if (r == 15) + { + if ((k + 16) > 64) + stop_decoding(JPGD_DECODE_ERROR); + + if (k < prev_num_set) + { + int n = JPGD_MIN(16, prev_num_set - k); + int kt = k; + while (n--) + { + JPGD_ASSERT(kt <= 63); + p[g_ZAG[kt++]] = 0; + } + } + + k += 16 - 1; // - 1 because the loop counter is k + JPGD_ASSERT(p[g_ZAG[k]] == 0); + } + else + break; + } + } + + if (k < prev_num_set) + { + int kt = k; + while (kt < prev_num_set) + p[g_ZAG[kt++]] = 0; + } + + m_mcu_block_max_zag[mcu_block] = k; + + row_block++; + } + + if (m_freq_domain_chroma_upsample) + transform_mcu_expand(mcu_row); + else + transform_mcu(mcu_row); + + m_restarts_left--; + } +} + +// YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB +void jpeg_decoder::H1V1Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d = m_pScan_line_0; + uint8 *s = m_pSample_buf + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int j = 0; j < 8; j++) + { + int y = s[j]; + int cb = s[64+j]; + int cr = s[128+j]; + + d[0] = clamp(y + m_crr[cr]); + d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16)); + d[2] = clamp(y + m_cbb[cb]); + d[3] = 255; + + d += 4; + } + + s += 64*3; + } +} + +// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB +void jpeg_decoder::H2V1Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d0 = m_pScan_line_0; + uint8 *y = m_pSample_buf + row * 8; + uint8 *c = m_pSample_buf + 2*64 + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int l = 0; l < 2; l++) + { + for (int j = 0; j < 4; j++) + { + int cb = c[0]; + int cr = c[64]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j<<1]; + d0[0] = clamp(yy+rc); + d0[1] = clamp(yy+gc); + d0[2] = clamp(yy+bc); + d0[3] = 255; + + yy = y[(j<<1)+1]; + d0[4] = clamp(yy+rc); + d0[5] = clamp(yy+gc); + d0[6] = clamp(yy+bc); + d0[7] = 255; + + d0 += 8; + + c++; + } + y += 64; + } + + y += 64*4 - 64*2; + c += 64*4 - 8; + } +} + +// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB +void jpeg_decoder::H1V2Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d0 = m_pScan_line_0; + uint8 *d1 = m_pScan_line_1; + uint8 *y; + uint8 *c; + + if (row < 8) + y = m_pSample_buf + row * 8; + else + y = m_pSample_buf + 64*1 + (row & 7) * 8; + + c = m_pSample_buf + 64*2 + (row >> 1) * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int j = 0; j < 8; j++) + { + int cb = c[0+j]; + int cr = c[64+j]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j]; + d0[0] = clamp(yy+rc); + d0[1] = clamp(yy+gc); + d0[2] = clamp(yy+bc); + d0[3] = 255; + + yy = y[8+j]; + d1[0] = clamp(yy+rc); + d1[1] = clamp(yy+gc); + d1[2] = clamp(yy+bc); + d1[3] = 255; + + d0 += 4; + d1 += 4; + } + + y += 64*4; + c += 64*4; + } +} + +// YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB +void jpeg_decoder::H2V2Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d0 = m_pScan_line_0; + uint8 *d1 = m_pScan_line_1; + uint8 *y; + uint8 *c; + + if (row < 8) + y = m_pSample_buf + row * 8; + else + y = m_pSample_buf + 64*2 + (row & 7) * 8; + + c = m_pSample_buf + 64*4 + (row >> 1) * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int l = 0; l < 2; l++) + { + for (int j = 0; j < 8; j += 2) + { + int cb = c[0]; + int cr = c[64]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j]; + d0[0] = clamp(yy+rc); + d0[1] = clamp(yy+gc); + d0[2] = clamp(yy+bc); + d0[3] = 255; + + yy = y[j+1]; + d0[4] = clamp(yy+rc); + d0[5] = clamp(yy+gc); + d0[6] = clamp(yy+bc); + d0[7] = 255; + + yy = y[j+8]; + d1[0] = clamp(yy+rc); + d1[1] = clamp(yy+gc); + d1[2] = clamp(yy+bc); + d1[3] = 255; + + yy = y[j+8+1]; + d1[4] = clamp(yy+rc); + d1[5] = clamp(yy+gc); + d1[6] = clamp(yy+bc); + d1[7] = 255; + + d0 += 8; + d1 += 8; + + c++; + } + y += 64; + } + + y += 64*6 - 64*2; + c += 64*6 - 8; + } +} + +// Y (1 block per MCU) to 8-bit grayscale +void jpeg_decoder::gray_convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d = m_pScan_line_0; + uint8 *s = m_pSample_buf + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + *(uint *)d = *(uint *)s; + *(uint *)(&d[4]) = *(uint *)(&s[4]); + + s += 64; + d += 8; + } +} + +void jpeg_decoder::expanded_convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + + uint8* Py = m_pSample_buf + (row / 8) * 64 * m_comp_h_samp[0] + (row & 7) * 8; + + uint8* d = m_pScan_line_0; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int k = 0; k < m_max_mcu_x_size; k += 8) + { + const int Y_ofs = k * 8; + const int Cb_ofs = Y_ofs + 64 * m_expanded_blocks_per_component; + const int Cr_ofs = Y_ofs + 64 * m_expanded_blocks_per_component * 2; + for (int j = 0; j < 8; j++) + { + int y = Py[Y_ofs + j]; + int cb = Py[Cb_ofs + j]; + int cr = Py[Cr_ofs + j]; + + d[0] = clamp(y + m_crr[cr]); + d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16)); + d[2] = clamp(y + m_cbb[cb]); + d[3] = 255; + + d += 4; + } + } + + Py += 64 * m_expanded_blocks_per_mcu; + } +} + +// Find end of image (EOI) marker, so we can return to the user the exact size of the input stream. +void jpeg_decoder::find_eoi() +{ + if (!m_progressive_flag) + { + // Attempt to read the EOI marker. + //get_bits_no_markers(m_bits_left & 7); + + // Prime the bit buffer + m_bits_left = 16; + get_bits(16); + get_bits(16); + + // The next marker _should_ be EOI + process_markers(); + } + + m_total_bytes_read -= m_in_buf_left; +} + +int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len) +{ + if ((m_error_code) || (!m_ready_flag)) + return JPGD_FAILED; + + if (m_total_lines_left == 0) + return JPGD_DONE; + + if (m_mcu_lines_left == 0) + { + if (setjmp(m_jmp_state)) + return JPGD_FAILED; + + if (m_progressive_flag) + load_next_row(); + else + decode_next_row(); + + // Find the EOI marker if that was the last row. + if (m_total_lines_left <= m_max_mcu_y_size) + find_eoi(); + + m_mcu_lines_left = m_max_mcu_y_size; + } + + if (m_freq_domain_chroma_upsample) + { + expanded_convert(); + *pScan_line = m_pScan_line_0; + } + else + { + switch (m_scan_type) + { + case JPGD_YH2V2: + { + if ((m_mcu_lines_left & 1) == 0) + { + H2V2Convert(); + *pScan_line = m_pScan_line_0; + } + else + *pScan_line = m_pScan_line_1; + + break; + } + case JPGD_YH2V1: + { + H2V1Convert(); + *pScan_line = m_pScan_line_0; + break; + } + case JPGD_YH1V2: + { + if ((m_mcu_lines_left & 1) == 0) + { + H1V2Convert(); + *pScan_line = m_pScan_line_0; + } + else + *pScan_line = m_pScan_line_1; + + break; + } + case JPGD_YH1V1: + { + H1V1Convert(); + *pScan_line = m_pScan_line_0; + break; + } + case JPGD_GRAYSCALE: + { + gray_convert(); + *pScan_line = m_pScan_line_0; + + break; + } + } + } + + *pScan_line_len = m_real_dest_bytes_per_scan_line; + + m_mcu_lines_left--; + m_total_lines_left--; + + return JPGD_SUCCESS; +} + +// Creates the tables needed for efficient Huffman decoding. +void jpeg_decoder::make_huff_table(int index, huff_tables *pH) +{ + int p, i, l, si; + uint8 huffsize[257]; + uint huffcode[257]; + uint code; + uint subtree; + int code_size; + int lastp; + int nextfreeentry; + int currententry; + + pH->ac_table = m_huff_ac[index] != 0; + + p = 0; + + for (l = 1; l <= 16; l++) + { + for (i = 1; i <= m_huff_num[index][l]; i++) + huffsize[p++] = static_cast(l); + } + + huffsize[p] = 0; + + lastp = p; + + code = 0; + si = huffsize[0]; + p = 0; + + while (huffsize[p]) + { + while (huffsize[p] == si) + { + huffcode[p++] = code; + code++; + } + + code <<= 1; + si++; + } + + memset(pH->look_up, 0, sizeof(pH->look_up)); + memset(pH->look_up2, 0, sizeof(pH->look_up2)); + memset(pH->tree, 0, sizeof(pH->tree)); + memset(pH->code_size, 0, sizeof(pH->code_size)); + + nextfreeentry = -1; + + p = 0; + + while (p < lastp) + { + i = m_huff_val[index][p]; + code = huffcode[p]; + code_size = huffsize[p]; + + pH->code_size[i] = static_cast(code_size); + + if (code_size <= 8) + { + code <<= (8 - code_size); + + for (l = 1 << (8 - code_size); l > 0; l--) + { + JPGD_ASSERT(i < 256); + + pH->look_up[code] = i; + + bool has_extrabits = false; + int extra_bits = 0; + int num_extra_bits = i & 15; + + int bits_to_fetch = code_size; + if (num_extra_bits) + { + int total_codesize = code_size + num_extra_bits; + if (total_codesize <= 8) + { + has_extrabits = true; + extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize)); + JPGD_ASSERT(extra_bits <= 0x7FFF); + bits_to_fetch += num_extra_bits; + } + } + + if (!has_extrabits) + pH->look_up2[code] = i | (bits_to_fetch << 8); + else + pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8); + + code++; + } + } + else + { + subtree = (code >> (code_size - 8)) & 0xFF; + + currententry = pH->look_up[subtree]; + + if (currententry == 0) + { + pH->look_up[subtree] = currententry = nextfreeentry; + pH->look_up2[subtree] = currententry = nextfreeentry; + + nextfreeentry -= 2; + } + + code <<= (16 - (code_size - 8)); + + for (l = code_size; l > 9; l--) + { + if ((code & 0x8000) == 0) + currententry--; + + if (pH->tree[-currententry - 1] == 0) + { + pH->tree[-currententry - 1] = nextfreeentry; + + currententry = nextfreeentry; + + nextfreeentry -= 2; + } + else + currententry = pH->tree[-currententry - 1]; + + code <<= 1; + } + + if ((code & 0x8000) == 0) + currententry--; + + pH->tree[-currententry - 1] = i; + } + + p++; + } +} + +// Verifies the quantization tables needed for this scan are available. +void jpeg_decoder::check_quant_tables() +{ + for (int i = 0; i < m_comps_in_scan; i++) + if (m_quant[m_comp_quant[m_comp_list[i]]] == NULL) + stop_decoding(JPGD_UNDEFINED_QUANT_TABLE); +} + +// Verifies that all the Huffman tables needed for this scan are available. +void jpeg_decoder::check_huff_tables() +{ + for (int i = 0; i < m_comps_in_scan; i++) + { + if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == NULL)) + stop_decoding(JPGD_UNDEFINED_HUFF_TABLE); + + if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == NULL)) + stop_decoding(JPGD_UNDEFINED_HUFF_TABLE); + } + + for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++) + if (m_huff_num[i]) + { + if (!m_pHuff_tabs[i]) + m_pHuff_tabs[i] = (huff_tables *)alloc(sizeof(huff_tables)); + + make_huff_table(i, m_pHuff_tabs[i]); + } +} + +// Determines the component order inside each MCU. +// Also calcs how many MCU's are on each row, etc. +void jpeg_decoder::calc_mcu_block_order() +{ + int component_num, component_id; + int max_h_samp = 0, max_v_samp = 0; + + for (component_id = 0; component_id < m_comps_in_frame; component_id++) + { + if (m_comp_h_samp[component_id] > max_h_samp) + max_h_samp = m_comp_h_samp[component_id]; + + if (m_comp_v_samp[component_id] > max_v_samp) + max_v_samp = m_comp_v_samp[component_id]; + } + + for (component_id = 0; component_id < m_comps_in_frame; component_id++) + { + m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8; + m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8; + } + + if (m_comps_in_scan == 1) + { + m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]]; + m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]]; + } + else + { + m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp; + m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp; + } + + if (m_comps_in_scan == 1) + { + m_mcu_org[0] = m_comp_list[0]; + + m_blocks_per_mcu = 1; + } + else + { + m_blocks_per_mcu = 0; + + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + int num_blocks; + + component_id = m_comp_list[component_num]; + + num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id]; + + while (num_blocks--) + m_mcu_org[m_blocks_per_mcu++] = component_id; + } + } +} + +// Starts a new scan. +int jpeg_decoder::init_scan() +{ + if (!locate_sos_marker()) + return JPGD_FALSE; + + calc_mcu_block_order(); + + check_huff_tables(); + + check_quant_tables(); + + memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint)); + + m_eob_run = 0; + + if (m_restart_interval) + { + m_restarts_left = m_restart_interval; + m_next_restart_num = 0; + } + + fix_in_buffer(); + + return JPGD_TRUE; +} + +// Starts a frame. Determines if the number of components or sampling factors +// are supported. +void jpeg_decoder::init_frame() +{ + int i; + + if (m_comps_in_frame == 1) + { + if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1)) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + m_scan_type = JPGD_GRAYSCALE; + m_max_blocks_per_mcu = 1; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 8; + } + else if (m_comps_in_frame == 3) + { + if ( ((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) || + ((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1)) ) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1)) + { + m_scan_type = JPGD_YH1V1; + + m_max_blocks_per_mcu = 3; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 8; + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1)) + { + m_scan_type = JPGD_YH2V1; + m_max_blocks_per_mcu = 4; + m_max_mcu_x_size = 16; + m_max_mcu_y_size = 8; + } + else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2)) + { + m_scan_type = JPGD_YH1V2; + m_max_blocks_per_mcu = 4; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 16; + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2)) + { + m_scan_type = JPGD_YH2V2; + m_max_blocks_per_mcu = 6; + m_max_mcu_x_size = 16; + m_max_mcu_y_size = 16; + } + else + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + } + else + stop_decoding(JPGD_UNSUPPORTED_COLORSPACE); + + m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size; + m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size; + + // These values are for the *destination* pixels: after conversion. + if (m_scan_type == JPGD_GRAYSCALE) + m_dest_bytes_per_pixel = 1; + else + m_dest_bytes_per_pixel = 4; + + m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel; + + m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel); + + // Initialize two scan line buffers. + m_pScan_line_0 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true); + if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2)) + m_pScan_line_1 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true); + + m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu; + + // Should never happen + if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW) + stop_decoding(JPGD_ASSERTION_ERROR); + + // Allocate the coefficient buffer, enough for one MCU + m_pMCU_coefficients = (jpgd_block_t*)alloc(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_t)); + + for (i = 0; i < m_max_blocks_per_mcu; i++) + m_mcu_block_max_zag[i] = 64; + + m_expanded_blocks_per_component = m_comp_h_samp[0] * m_comp_v_samp[0]; + m_expanded_blocks_per_mcu = m_expanded_blocks_per_component * m_comps_in_frame; + m_expanded_blocks_per_row = m_max_mcus_per_row * m_expanded_blocks_per_mcu; + // Freq. domain chroma upsampling is only supported for H2V2 subsampling factor (the most common one I've seen). + m_freq_domain_chroma_upsample = false; +#if JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING + m_freq_domain_chroma_upsample = (m_expanded_blocks_per_mcu == 4*3); +#endif + + if (m_freq_domain_chroma_upsample) + m_pSample_buf = (uint8 *)alloc(m_expanded_blocks_per_row * 64); + else + m_pSample_buf = (uint8 *)alloc(m_max_blocks_per_row * 64); + + m_total_lines_left = m_image_y_size; + + m_mcu_lines_left = 0; + + create_look_ups(); +} + +// The coeff_buf series of methods originally stored the coefficients +// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache +// was used to make this process more efficient. Now, we can store the entire +// thing in RAM. +jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y) +{ + coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf)); + + cb->block_num_x = block_num_x; + cb->block_num_y = block_num_y; + cb->block_len_x = block_len_x; + cb->block_len_y = block_len_y; + cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_t); + cb->pData = (uint8 *)alloc(cb->block_size * block_num_x * block_num_y, true); + return cb; +} + +inline jpgd_block_t *jpeg_decoder::coeff_buf_getp(coeff_buf *cb, int block_x, int block_y) +{ + JPGD_ASSERT((block_x < cb->block_num_x) && (block_y < cb->block_num_y)); + return (jpgd_block_t *)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x)); +} + +// The following methods decode the various types of m_blocks encountered +// in progressively encoded images. +void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + int s, r; + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y); + + if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0) + { + r = pD->get_bits_no_markers(s); + s = JPGD_HUFF_EXTEND(r, s); + } + + pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]); + + p[0] = static_cast(s << pD->m_successive_low); +} + +void jpeg_decoder::decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + if (pD->get_bits_no_markers(1)) + { + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y); + + p[0] |= (1 << pD->m_successive_low); + } +} + +void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + int k, s, r; + + if (pD->m_eob_run) + { + pD->m_eob_run--; + return; + } + + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); + + for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++) + { + s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]); + + r = s >> 4; + s &= 15; + + if (s) + { + if ((k += r) > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + + r = pD->get_bits_no_markers(s); + s = JPGD_HUFF_EXTEND(r, s); + + p[g_ZAG[k]] = static_cast(s << pD->m_successive_low); + } + else + { + if (r == 15) + { + if ((k += 15) > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + } + else + { + pD->m_eob_run = 1 << r; + + if (r) + pD->m_eob_run += pD->get_bits_no_markers(r); + + pD->m_eob_run--; + + break; + } + } + } +} + +void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + int s, k, r; + int p1 = 1 << pD->m_successive_low; + int m1 = (-1) << pD->m_successive_low; + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); + + JPGD_ASSERT(pD->m_spectral_end <= 63); + + k = pD->m_spectral_start; + + if (pD->m_eob_run == 0) + { + for ( ; k <= pD->m_spectral_end; k++) + { + s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]); + + r = s >> 4; + s &= 15; + + if (s) + { + if (s != 1) + pD->stop_decoding(JPGD_DECODE_ERROR); + + if (pD->get_bits_no_markers(1)) + s = p1; + else + s = m1; + } + else + { + if (r != 15) + { + pD->m_eob_run = 1 << r; + + if (r) + pD->m_eob_run += pD->get_bits_no_markers(r); + + break; + } + } + + do + { + jpgd_block_t *this_coef = p + g_ZAG[k & 63]; + + if (*this_coef != 0) + { + if (pD->get_bits_no_markers(1)) + { + if ((*this_coef & p1) == 0) + { + if (*this_coef >= 0) + *this_coef = static_cast(*this_coef + p1); + else + *this_coef = static_cast(*this_coef + m1); + } + } + } + else + { + if (--r < 0) + break; + } + + k++; + + } while (k <= pD->m_spectral_end); + + if ((s) && (k < 64)) + { + p[g_ZAG[k]] = static_cast(s); + } + } + } + + if (pD->m_eob_run > 0) + { + for ( ; k <= pD->m_spectral_end; k++) + { + jpgd_block_t *this_coef = p + g_ZAG[k & 63]; // logical AND to shut up static code analysis + + if (*this_coef != 0) + { + if (pD->get_bits_no_markers(1)) + { + if ((*this_coef & p1) == 0) + { + if (*this_coef >= 0) + *this_coef = static_cast(*this_coef + p1); + else + *this_coef = static_cast(*this_coef + m1); + } + } + } + } + + pD->m_eob_run--; + } +} + +// Decode a scan in a progressively encoded image. +void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func) +{ + int mcu_row, mcu_col, mcu_block; + int block_x_mcu[JPGD_MAX_COMPONENTS], m_block_y_mcu[JPGD_MAX_COMPONENTS]; + + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++) + { + int component_num, component_id; + + memset(block_x_mcu, 0, sizeof(block_x_mcu)); + + for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; + + if ((m_restart_interval) && (m_restarts_left == 0)) + process_restart(); + + for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + component_id = m_mcu_org[mcu_block]; + + decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + + if (m_comps_in_scan == 1) + block_x_mcu[component_id]++; + else + { + if (++block_x_mcu_ofs == m_comp_h_samp[component_id]) + { + block_x_mcu_ofs = 0; + + if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) + { + block_y_mcu_ofs = 0; + block_x_mcu[component_id] += m_comp_h_samp[component_id]; + } + } + } + } + + m_restarts_left--; + } + + if (m_comps_in_scan == 1) + m_block_y_mcu[m_comp_list[0]]++; + else + { + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + component_id = m_comp_list[component_num]; + m_block_y_mcu[component_id] += m_comp_v_samp[component_id]; + } + } + } +} + +// Decode a progressively encoded image. +void jpeg_decoder::init_progressive() +{ + int i; + + if (m_comps_in_frame == 4) + stop_decoding(JPGD_UNSUPPORTED_COLORSPACE); + + // Allocate the coefficient buffers. + for (i = 0; i < m_comps_in_frame; i++) + { + m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1); + m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8); + } + + for ( ; ; ) + { + int dc_only_scan, refinement_scan; + pDecode_block_func decode_block_func; + + if (!init_scan()) + break; + + dc_only_scan = (m_spectral_start == 0); + refinement_scan = (m_successive_high != 0); + + if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63)) + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + + if (dc_only_scan) + { + if (m_spectral_end) + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + } + else if (m_comps_in_scan != 1) /* AC scans can only contain one component */ + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + + if ((refinement_scan) && (m_successive_low != m_successive_high - 1)) + stop_decoding(JPGD_BAD_SOS_SUCCESSIVE); + + if (dc_only_scan) + { + if (refinement_scan) + decode_block_func = decode_block_dc_refine; + else + decode_block_func = decode_block_dc_first; + } + else + { + if (refinement_scan) + decode_block_func = decode_block_ac_refine; + else + decode_block_func = decode_block_ac_first; + } + + decode_scan(decode_block_func); + + m_bits_left = 16; + get_bits(16); + get_bits(16); + } + + m_comps_in_scan = m_comps_in_frame; + + for (i = 0; i < m_comps_in_frame; i++) + m_comp_list[i] = i; + + calc_mcu_block_order(); +} + +void jpeg_decoder::init_sequential() +{ + if (!init_scan()) + stop_decoding(JPGD_UNEXPECTED_MARKER); +} + +void jpeg_decoder::decode_start() +{ + init_frame(); + + if (m_progressive_flag) + init_progressive(); + else + init_sequential(); +} + +void jpeg_decoder::decode_init(jpeg_decoder_stream *pStream) +{ + init(pStream); + locate_sof_marker(); +} + +jpeg_decoder::jpeg_decoder(jpeg_decoder_stream *pStream) +{ + if (setjmp(m_jmp_state)) + return; + decode_init(pStream); +} + +int jpeg_decoder::begin_decoding() +{ + if (m_ready_flag) + return JPGD_SUCCESS; + + if (m_error_code) + return JPGD_FAILED; + + if (setjmp(m_jmp_state)) + return JPGD_FAILED; + + decode_start(); + + m_ready_flag = true; + + return JPGD_SUCCESS; +} + +jpeg_decoder::~jpeg_decoder() +{ + free_all_blocks(); +} + +jpeg_decoder_file_stream::jpeg_decoder_file_stream() +{ + m_pFile = NULL; + m_eof_flag = false; + m_error_flag = false; +} + +void jpeg_decoder_file_stream::close() +{ + if (m_pFile) + { + fclose(m_pFile); + m_pFile = NULL; + } + + m_eof_flag = false; + m_error_flag = false; +} + +jpeg_decoder_file_stream::~jpeg_decoder_file_stream() +{ + close(); +} + +bool jpeg_decoder_file_stream::open(const char *Pfilename) +{ + close(); + + m_eof_flag = false; + m_error_flag = false; + +#if defined(_MSC_VER) + m_pFile = NULL; + fopen_s(&m_pFile, Pfilename, "rb"); +#else + m_pFile = fopen(Pfilename, "rb"); +#endif + return m_pFile != NULL; +} + +int jpeg_decoder_file_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) +{ + if (!m_pFile) + return -1; + + if (m_eof_flag) + { + *pEOF_flag = true; + return 0; + } + + if (m_error_flag) + return -1; + + int bytes_read = static_cast(fread(pBuf, 1, max_bytes_to_read, m_pFile)); + if (bytes_read < max_bytes_to_read) + { + if (ferror(m_pFile)) + { + m_error_flag = true; + return -1; + } + + m_eof_flag = true; + *pEOF_flag = true; + } + + return bytes_read; +} + +bool jpeg_decoder_mem_stream::open(const uint8 *pSrc_data, uint size) +{ + close(); + m_pSrc_data = pSrc_data; + m_ofs = 0; + m_size = size; + return true; +} + +int jpeg_decoder_mem_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) +{ + *pEOF_flag = false; + + if (!m_pSrc_data) + return -1; + + uint bytes_remaining = m_size - m_ofs; + if ((uint)max_bytes_to_read > bytes_remaining) + { + max_bytes_to_read = bytes_remaining; + *pEOF_flag = true; + } + + memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read); + m_ofs += max_bytes_to_read; + + return max_bytes_to_read; +} + +unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps) +{ + if (!actual_comps) + return NULL; + *actual_comps = 0; + + if ((!pStream) || (!width) || (!height) || (!req_comps)) + return NULL; + + if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) + return NULL; + + jpeg_decoder decoder(pStream); + if (decoder.get_error_code() != JPGD_SUCCESS) + return NULL; + + const int image_width = decoder.get_width(), image_height = decoder.get_height(); + *width = image_width; + *height = image_height; + *actual_comps = decoder.get_num_components(); + + if (decoder.begin_decoding() != JPGD_SUCCESS) + return NULL; + + const int dst_bpl = image_width * req_comps; + + uint8 *pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height); + if (!pImage_data) + return NULL; + + for (int y = 0; y < image_height; y++) + { + const uint8* pScan_line; + uint scan_line_len; + if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) + { + jpgd_free(pImage_data); + return NULL; + } + + uint8 *pDst = pImage_data + y * dst_bpl; + + if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3))) + memcpy(pDst, pScan_line, dst_bpl); + else if (decoder.get_num_components() == 1) + { + if (req_comps == 3) + { + for (int x = 0; x < image_width; x++) + { + uint8 luma = pScan_line[x]; + pDst[0] = luma; + pDst[1] = luma; + pDst[2] = luma; + pDst += 3; + } + } + else + { + for (int x = 0; x < image_width; x++) + { + uint8 luma = pScan_line[x]; + pDst[0] = luma; + pDst[1] = luma; + pDst[2] = luma; + pDst[3] = 255; + pDst += 4; + } + } + } + else if (decoder.get_num_components() == 3) + { + if (req_comps == 1) + { + const int YR = 19595, YG = 38470, YB = 7471; + for (int x = 0; x < image_width; x++) + { + int r = pScan_line[x*4+0]; + int g = pScan_line[x*4+1]; + int b = pScan_line[x*4+2]; + *pDst++ = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); + } + } + else + { + for (int x = 0; x < image_width; x++) + { + pDst[0] = pScan_line[x*4+0]; + pDst[1] = pScan_line[x*4+1]; + pDst[2] = pScan_line[x*4+2]; + pDst += 3; + } + } + } + } + + return pImage_data; +} + +unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps) +{ + jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size); + return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps); +} + +unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps) +{ + jpgd::jpeg_decoder_file_stream file_stream; + if (!file_stream.open(pSrc_filename)) + return NULL; + return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps); +} + +} // namespace jpgd \ No newline at end of file diff --git a/renderdoc/3rdparty/jpeg-compressor/jpgd.h b/renderdoc/3rdparty/jpeg-compressor/jpgd.h new file mode 100644 index 0000000000..150b9a0b26 --- /dev/null +++ b/renderdoc/3rdparty/jpeg-compressor/jpgd.h @@ -0,0 +1,319 @@ +// jpgd.h - C++ class for JPEG decompression. +// Public domain, Rich Geldreich +#ifndef JPEG_DECODER_H +#define JPEG_DECODER_H + +#include +#include +#include + +#ifdef _MSC_VER + #define JPGD_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) + #define JPGD_NORETURN __attribute__ ((noreturn)) +#else + #define JPGD_NORETURN +#endif + +namespace jpgd +{ + typedef unsigned char uint8; + typedef signed short int16; + typedef unsigned short uint16; + typedef unsigned int uint; + typedef signed int int32; + + // Loads a JPEG image from a memory buffer or a file. + // req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA). + // On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB). + // Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly. + // Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp. + unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps); + unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps); + + // Success/failure error codes. + enum jpgd_status + { + JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1, + JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE, + JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS, + JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH, + JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER, + JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS, + JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE, + JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR, + JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM + }; + + // Input stream interface. + // Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available. + // The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set. + // It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer. + // Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding. + class jpeg_decoder_stream + { + public: + jpeg_decoder_stream() { } + virtual ~jpeg_decoder_stream() { } + + // The read() method is called when the internal input buffer is empty. + // Parameters: + // pBuf - input buffer + // max_bytes_to_read - maximum bytes that can be written to pBuf + // pEOF_flag - set this to true if at end of stream (no more bytes remaining) + // Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0). + // Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full. + virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) = 0; + }; + + // stdio FILE stream class. + class jpeg_decoder_file_stream : public jpeg_decoder_stream + { + jpeg_decoder_file_stream(const jpeg_decoder_file_stream &); + jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &); + + FILE *m_pFile; + bool m_eof_flag, m_error_flag; + + public: + jpeg_decoder_file_stream(); + virtual ~jpeg_decoder_file_stream(); + + bool open(const char *Pfilename); + void close(); + + virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag); + }; + + // Memory stream class. + class jpeg_decoder_mem_stream : public jpeg_decoder_stream + { + const uint8 *m_pSrc_data; + uint m_ofs, m_size; + + public: + jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { } + jpeg_decoder_mem_stream(const uint8 *pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { } + + virtual ~jpeg_decoder_mem_stream() { } + + bool open(const uint8 *pSrc_data, uint size); + void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; } + + virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag); + }; + + // Loads JPEG file from a jpeg_decoder_stream. + unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps); + + enum + { + JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4, + JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384 + }; + + typedef int16 jpgd_quant_t; + typedef int16 jpgd_block_t; + + class jpeg_decoder + { + public: + // Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc. + // methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline. + jpeg_decoder(jpeg_decoder_stream *pStream); + + ~jpeg_decoder(); + + // Call this method after constructing the object to begin decompression. + // If JPGD_SUCCESS is returned you may then call decode() on each scanline. + int begin_decoding(); + + // Returns the next scan line. + // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1). + // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4). + // Returns JPGD_SUCCESS if a scan line has been returned. + // Returns JPGD_DONE if all scan lines have been returned. + // Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info. + int decode(const void** pScan_line, uint* pScan_line_len); + + inline jpgd_status get_error_code() const { return m_error_code; } + + inline int get_width() const { return m_image_x_size; } + inline int get_height() const { return m_image_y_size; } + + inline int get_num_components() const { return m_comps_in_frame; } + + inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; } + inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); } + + // Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file). + inline int get_total_bytes_read() const { return m_total_bytes_read; } + + private: + jpeg_decoder(const jpeg_decoder &); + jpeg_decoder &operator =(const jpeg_decoder &); + + typedef void (*pDecode_block_func)(jpeg_decoder *, int, int, int); + + struct huff_tables + { + bool ac_table; + uint look_up[256]; + uint look_up2[256]; + uint8 code_size[256]; + uint tree[512]; + }; + + struct coeff_buf + { + uint8 *pData; + int block_num_x, block_num_y; + int block_len_x, block_len_y; + int block_size; + }; + + struct mem_block + { + mem_block *m_pNext; + size_t m_used_count; + size_t m_size; + char m_data[1]; + }; + + jmp_buf m_jmp_state; + mem_block *m_pMem_blocks; + int m_image_x_size; + int m_image_y_size; + jpeg_decoder_stream *m_pStream; + int m_progressive_flag; + uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES]; + uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size + uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size + jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables + int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported) + int m_comps_in_frame; // # of components in frame + int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor + int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor + int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector + int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID + int m_comp_h_blocks[JPGD_MAX_COMPONENTS]; + int m_comp_v_blocks[JPGD_MAX_COMPONENTS]; + int m_comps_in_scan; // # of components in scan + int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan + int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector + int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector + int m_spectral_start; // spectral selection start + int m_spectral_end; // spectral selection end + int m_successive_low; // successive approximation low + int m_successive_high; // successive approximation high + int m_max_mcu_x_size; // MCU's max. X size in pixels + int m_max_mcu_y_size; // MCU's max. Y size in pixels + int m_blocks_per_mcu; + int m_max_blocks_per_row; + int m_mcus_per_row, m_mcus_per_col; + int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU]; + int m_total_lines_left; // total # lines left in image + int m_mcu_lines_left; // total # lines left in this MCU + int m_real_dest_bytes_per_scan_line; + int m_dest_bytes_per_scan_line; // rounded up + int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y) + huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES]; + coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS]; + coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS]; + int m_eob_run; + int m_block_y_mcu[JPGD_MAX_COMPONENTS]; + uint8* m_pIn_buf_ofs; + int m_in_buf_left; + int m_tem_flag; + bool m_eof_flag; + uint8 m_in_buf_pad_start[128]; + uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128]; + uint8 m_in_buf_pad_end[128]; + int m_bits_left; + uint m_bit_buf; + int m_restart_interval; + int m_restarts_left; + int m_next_restart_num; + int m_max_mcus_per_row; + int m_max_blocks_per_mcu; + int m_expanded_blocks_per_mcu; + int m_expanded_blocks_per_row; + int m_expanded_blocks_per_component; + bool m_freq_domain_chroma_upsample; + int m_max_mcus_per_col; + uint m_last_dc_val[JPGD_MAX_COMPONENTS]; + jpgd_block_t* m_pMCU_coefficients; + int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU]; + uint8* m_pSample_buf; + int m_crr[256]; + int m_cbb[256]; + int m_crg[256]; + int m_cbg[256]; + uint8* m_pScan_line_0; + uint8* m_pScan_line_1; + jpgd_status m_error_code; + bool m_ready_flag; + int m_total_bytes_read; + + void free_all_blocks(); + JPGD_NORETURN void stop_decoding(jpgd_status status); + void *alloc(size_t n, bool zero = false); + void word_clear(void *p, uint16 c, uint n); + void prep_in_buffer(); + void read_dht_marker(); + void read_dqt_marker(); + void read_sof_marker(); + void skip_variable_marker(); + void read_dri_marker(); + void read_sos_marker(); + int next_marker(); + int process_markers(); + void locate_soi_marker(); + void locate_sof_marker(); + int locate_sos_marker(); + void init(jpeg_decoder_stream * pStream); + void create_look_ups(); + void fix_in_buffer(); + void transform_mcu(int mcu_row); + void transform_mcu_expand(int mcu_row); + coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y); + inline jpgd_block_t *coeff_buf_getp(coeff_buf *cb, int block_x, int block_y); + void load_next_row(); + void decode_next_row(); + void make_huff_table(int index, huff_tables *pH); + void check_quant_tables(); + void check_huff_tables(); + void calc_mcu_block_order(); + int init_scan(); + void init_frame(); + void process_restart(); + void decode_scan(pDecode_block_func decode_block_func); + void init_progressive(); + void init_sequential(); + void decode_start(); + void decode_init(jpeg_decoder_stream * pStream); + void H2V2Convert(); + void H2V1Convert(); + void H1V2Convert(); + void H1V1Convert(); + void gray_convert(); + void expanded_convert(); + void find_eoi(); + inline uint get_char(); + inline uint get_char(bool *pPadding_flag); + inline void stuff_char(uint8 q); + inline uint8 get_octet(); + inline uint get_bits(int num_bits); + inline uint get_bits_no_markers(int numbits); + inline int huff_decode(huff_tables *pH); + inline int huff_decode(huff_tables *pH, int& extrabits); + static inline uint8 clamp(int i); + static void decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y); + static void decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y); + static void decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y); + static void decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y); + }; + +} // namespace jpgd + +#endif // JPEG_DECODER_H diff --git a/renderdoc/3rdparty/jpeg-compressor/jpge.cpp b/renderdoc/3rdparty/jpeg-compressor/jpge.cpp new file mode 100644 index 0000000000..74d9d10069 --- /dev/null +++ b/renderdoc/3rdparty/jpeg-compressor/jpge.cpp @@ -0,0 +1,1039 @@ +// jpge.cpp - C++ class for JPEG compression. +// Public domain, Rich Geldreich +// v1.01, Dec. 18, 2010 - Initial release +// v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.) +// v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc. +// Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03). +// v1.04, May. 19, 2012: Forgot to set m_pFile ptr to NULL in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug. +// Code tweaks to fix VS2008 static code analysis warnings (all looked harmless). +// Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02. + +#include "jpge.h" + +#include +#include + +#pragma warning(disable: 4996) + +#define JPGE_MAX(a,b) (((a)>(b))?(a):(b)) +#define JPGE_MIN(a,b) (((a)<(b))?(a):(b)) + +namespace jpge { + +static inline void *jpge_malloc(size_t nSize) { return malloc(nSize); } +static inline void jpge_free(void *p) { free(p); } + +// Various JPEG enums and tables. +enum { M_SOF0 = 0xC0, M_DHT = 0xC4, M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_APP0 = 0xE0 }; +enum { DC_LUM_CODES = 12, AC_LUM_CODES = 256, DC_CHROMA_CODES = 12, AC_CHROMA_CODES = 256, MAX_HUFF_SYMBOLS = 257, MAX_HUFF_CODESIZE = 32 }; + +static uint8 s_zag[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; +static int16 s_std_lum_quant[64] = { 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 }; +static int16 s_std_croma_quant[64] = { 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 }; +static uint8 s_dc_lum_bits[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 }; +static uint8 s_dc_lum_val[DC_LUM_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; +static uint8 s_ac_lum_bits[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d }; +static uint8 s_ac_lum_val[AC_LUM_CODES] = +{ + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, + 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, + 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, + 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, + 0xf9,0xfa +}; +static uint8 s_dc_chroma_bits[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; +static uint8 s_dc_chroma_val[DC_CHROMA_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; +static uint8 s_ac_chroma_bits[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 }; +static uint8 s_ac_chroma_val[AC_CHROMA_CODES] = +{ + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, + 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, + 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, + 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, + 0xf9,0xfa +}; + +// Low-level helper functions. +template inline void clear_obj(T &obj) { memset(&obj, 0, sizeof(obj)); } + +const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329; +static inline uint8 clamp(int i) { if (static_cast(i) > 255U) { if (i < 0) i = 0; else if (i > 255) i = 255; } return static_cast(i); } + +static void RGB_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels) +{ + for ( ; num_pixels; pDst += 3, pSrc += 3, num_pixels--) + { + const int r = pSrc[0], g = pSrc[1], b = pSrc[2]; + pDst[0] = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); + pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16)); + pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16)); + } +} + +static void RGB_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels) +{ + for ( ; num_pixels; pDst++, pSrc += 3, num_pixels--) + pDst[0] = static_cast((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16); +} + +static void RGBA_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels) +{ + for ( ; num_pixels; pDst += 3, pSrc += 4, num_pixels--) + { + const int r = pSrc[0], g = pSrc[1], b = pSrc[2]; + pDst[0] = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); + pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16)); + pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16)); + } +} + +static void RGBA_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels) +{ + for ( ; num_pixels; pDst++, pSrc += 4, num_pixels--) + pDst[0] = static_cast((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16); +} + +static void Y_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels) +{ + for( ; num_pixels; pDst += 3, pSrc++, num_pixels--) { pDst[0] = pSrc[0]; pDst[1] = 128; pDst[2] = 128; } +} + +// Forward DCT - DCT derived from jfdctint. +enum { CONST_BITS = 13, ROW_BITS = 2 }; +#define DCT_DESCALE(x, n) (((x) + (((int32)1) << ((n) - 1))) >> (n)) +#define DCT_MUL(var, c) (static_cast(var) * static_cast(c)) +#define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7) \ + int32 t0 = s0 + s7, t7 = s0 - s7, t1 = s1 + s6, t6 = s1 - s6, t2 = s2 + s5, t5 = s2 - s5, t3 = s3 + s4, t4 = s3 - s4; \ + int32 t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2; \ + int32 u1 = DCT_MUL(t12 + t13, 4433); \ + s2 = u1 + DCT_MUL(t13, 6270); \ + s6 = u1 + DCT_MUL(t12, -15137); \ + u1 = t4 + t7; \ + int32 u2 = t5 + t6, u3 = t4 + t6, u4 = t5 + t7; \ + int32 z5 = DCT_MUL(u3 + u4, 9633); \ + t4 = DCT_MUL(t4, 2446); t5 = DCT_MUL(t5, 16819); \ + t6 = DCT_MUL(t6, 25172); t7 = DCT_MUL(t7, 12299); \ + u1 = DCT_MUL(u1, -7373); u2 = DCT_MUL(u2, -20995); \ + u3 = DCT_MUL(u3, -16069); u4 = DCT_MUL(u4, -3196); \ + u3 += z5; u4 += z5; \ + s0 = t10 + t11; s1 = t7 + u1 + u4; s3 = t6 + u2 + u3; s4 = t10 - t11; s5 = t5 + u2 + u4; s7 = t4 + u1 + u3; + +static void DCT2D(int32 *p) +{ + int32 c, *q = p; + for (c = 7; c >= 0; c--, q += 8) + { + int32 s0 = q[0], s1 = q[1], s2 = q[2], s3 = q[3], s4 = q[4], s5 = q[5], s6 = q[6], s7 = q[7]; + DCT1D(s0, s1, s2, s3, s4, s5, s6, s7); + q[0] = s0 << ROW_BITS; q[1] = DCT_DESCALE(s1, CONST_BITS-ROW_BITS); q[2] = DCT_DESCALE(s2, CONST_BITS-ROW_BITS); q[3] = DCT_DESCALE(s3, CONST_BITS-ROW_BITS); + q[4] = s4 << ROW_BITS; q[5] = DCT_DESCALE(s5, CONST_BITS-ROW_BITS); q[6] = DCT_DESCALE(s6, CONST_BITS-ROW_BITS); q[7] = DCT_DESCALE(s7, CONST_BITS-ROW_BITS); + } + for (q = p, c = 7; c >= 0; c--, q++) + { + int32 s0 = q[0*8], s1 = q[1*8], s2 = q[2*8], s3 = q[3*8], s4 = q[4*8], s5 = q[5*8], s6 = q[6*8], s7 = q[7*8]; + DCT1D(s0, s1, s2, s3, s4, s5, s6, s7); + q[0*8] = DCT_DESCALE(s0, ROW_BITS+3); q[1*8] = DCT_DESCALE(s1, CONST_BITS+ROW_BITS+3); q[2*8] = DCT_DESCALE(s2, CONST_BITS+ROW_BITS+3); q[3*8] = DCT_DESCALE(s3, CONST_BITS+ROW_BITS+3); + q[4*8] = DCT_DESCALE(s4, ROW_BITS+3); q[5*8] = DCT_DESCALE(s5, CONST_BITS+ROW_BITS+3); q[6*8] = DCT_DESCALE(s6, CONST_BITS+ROW_BITS+3); q[7*8] = DCT_DESCALE(s7, CONST_BITS+ROW_BITS+3); + } +} + +struct sym_freq { uint m_key, m_sym_index; }; + +// Radix sorts sym_freq[] array by 32-bit key m_key. Returns ptr to sorted values. +static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* pSyms0, sym_freq* pSyms1) +{ + const uint cMaxPasses = 4; + uint32 hist[256 * cMaxPasses]; clear_obj(hist); + for (uint i = 0; i < num_syms; i++) { uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; hist[256*2 + ((freq >> 16) & 0xFF)]++; hist[256*3 + ((freq >> 24) & 0xFF)]++; } + sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; + uint total_passes = cMaxPasses; while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (uint pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const uint32* pHist = &hist[pass << 8]; + uint offsets[256], cur_ofs = 0; + for (uint i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (uint i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; + } + return pCur_syms; +} + +// calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void calculate_minimum_redundancy(sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next=1; next < n-1; next++) + { + if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; + avbl = 1; used = dpth = 0; root = n-2; next = n-1; + while (avbl>0) + { + while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } + while (avbl>used) { A[next--].m_key = dpth; avbl--; } + avbl = 2*used; dpth++; used = 0; + } +} + +// Limits canonical Huffman code table's max code size to max_code_size. +static void huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + if (code_list_len <= 1) return; + + for (int i = max_code_size + 1; i <= MAX_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + + uint32 total = 0; + for (int i = max_code_size; i > 0; i--) + total += (((uint32)pNum_codes[i]) << (max_code_size - i)); + + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (int i = max_code_size - 1; i > 0; i--) + { + if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + } + total--; + } +} + +// Generates an optimized offman table. +void jpeg_encoder::optimize_huffman_table(int table_num, int table_len) +{ + sym_freq syms0[MAX_HUFF_SYMBOLS], syms1[MAX_HUFF_SYMBOLS]; + syms0[0].m_key = 1; syms0[0].m_sym_index = 0; // dummy symbol, assures that no valid code contains all 1's + int num_used_syms = 1; + const uint32 *pSym_count = &m_huff_count[table_num][0]; + for (int i = 0; i < table_len; i++) + if (pSym_count[i]) { syms0[num_used_syms].m_key = pSym_count[i]; syms0[num_used_syms++].m_sym_index = i + 1; } + sym_freq* pSyms = radix_sort_syms(num_used_syms, syms0, syms1); + calculate_minimum_redundancy(pSyms, num_used_syms); + + // Count the # of symbols of each code size. + int num_codes[1 + MAX_HUFF_CODESIZE]; clear_obj(num_codes); + for (int i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + const uint JPGE_CODE_SIZE_LIMIT = 16; // the maximum possible size of a JPEG Huffman code (valid range is [9,16] - 9 vs. 8 because of the dummy symbol) + huffman_enforce_max_code_size(num_codes, num_used_syms, JPGE_CODE_SIZE_LIMIT); + + // Compute m_huff_bits array, which contains the # of symbols per code size. + clear_obj(m_huff_bits[table_num]); + for (int i = 1; i <= (int)JPGE_CODE_SIZE_LIMIT; i++) + m_huff_bits[table_num][i] = static_cast(num_codes[i]); + + // Remove the dummy symbol added above, which must be in largest bucket. + for (int i = JPGE_CODE_SIZE_LIMIT; i >= 1; i--) + { + if (m_huff_bits[table_num][i]) { m_huff_bits[table_num][i]--; break; } + } + + // Compute the m_huff_val array, which contains the symbol indices sorted by code size (smallest to largest). + for (int i = num_used_syms - 1; i >= 1; i--) + m_huff_val[table_num][num_used_syms - 1 - i] = static_cast(pSyms[i].m_sym_index - 1); +} + +// JPEG marker generation. +void jpeg_encoder::emit_byte(uint8 i) +{ + m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_obj(i); +} + +void jpeg_encoder::emit_word(uint i) +{ + emit_byte(uint8(i >> 8)); emit_byte(uint8(i & 0xFF)); +} + +void jpeg_encoder::emit_marker(int marker) +{ + emit_byte(uint8(0xFF)); emit_byte(uint8(marker)); +} + +// Emit JFIF marker +void jpeg_encoder::emit_jfif_app0() +{ + emit_marker(M_APP0); + emit_word(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); + emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */ + emit_byte(0); + emit_byte(1); /* Major version */ + emit_byte(1); /* Minor version */ + emit_byte(0); /* Density unit */ + emit_word(1); + emit_word(1); + emit_byte(0); /* No thumbnail image */ + emit_byte(0); +} + +// Emit quantization tables +void jpeg_encoder::emit_dqt() +{ + for (int i = 0; i < ((m_num_components == 3) ? 2 : 1); i++) + { + emit_marker(M_DQT); + emit_word(64 + 1 + 2); + emit_byte(static_cast(i)); + for (int j = 0; j < 64; j++) + emit_byte(static_cast(m_quantization_tables[i][j])); + } +} + +// Emit start of frame marker +void jpeg_encoder::emit_sof() +{ + emit_marker(M_SOF0); /* baseline */ + emit_word(3 * m_num_components + 2 + 5 + 1); + emit_byte(8); /* precision */ + emit_word(m_image_y); + emit_word(m_image_x); + emit_byte(m_num_components); + for (int i = 0; i < m_num_components; i++) + { + emit_byte(static_cast(i + 1)); /* component ID */ + emit_byte((m_comp_h_samp[i] << 4) + m_comp_v_samp[i]); /* h and v sampling */ + emit_byte(i > 0); /* quant. table num */ + } +} + +// Emit Huffman table. +void jpeg_encoder::emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag) +{ + emit_marker(M_DHT); + + int length = 0; + for (int i = 1; i <= 16; i++) + length += bits[i]; + + emit_word(length + 2 + 1 + 16); + emit_byte(static_cast(index + (ac_flag << 4))); + + for (int i = 1; i <= 16; i++) + emit_byte(bits[i]); + + for (int i = 0; i < length; i++) + emit_byte(val[i]); +} + +// Emit all Huffman tables. +void jpeg_encoder::emit_dhts() +{ + emit_dht(m_huff_bits[0+0], m_huff_val[0+0], 0, false); + emit_dht(m_huff_bits[2+0], m_huff_val[2+0], 0, true); + if (m_num_components == 3) + { + emit_dht(m_huff_bits[0+1], m_huff_val[0+1], 1, false); + emit_dht(m_huff_bits[2+1], m_huff_val[2+1], 1, true); + } +} + +// emit start of scan +void jpeg_encoder::emit_sos() +{ + emit_marker(M_SOS); + emit_word(2 * m_num_components + 2 + 1 + 3); + emit_byte(m_num_components); + for (int i = 0; i < m_num_components; i++) + { + emit_byte(static_cast(i + 1)); + if (i == 0) + emit_byte((0 << 4) + 0); + else + emit_byte((1 << 4) + 1); + } + emit_byte(0); /* spectral selection */ + emit_byte(63); + emit_byte(0); +} + +// Emit all markers at beginning of image file. +void jpeg_encoder::emit_markers() +{ + emit_marker(M_SOI); + emit_jfif_app0(); + emit_dqt(); + emit_sof(); + emit_dhts(); + emit_sos(); +} + +// Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays. +void jpeg_encoder::compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val) +{ + int i, l, last_p, si; + uint8 huff_size[257]; + uint huff_code[257]; + uint code; + + int p = 0; + for (l = 1; l <= 16; l++) + for (i = 1; i <= bits[l]; i++) + huff_size[p++] = (char)l; + + huff_size[p] = 0; last_p = p; // write sentinel + + code = 0; si = huff_size[0]; p = 0; + + while (huff_size[p]) + { + while (huff_size[p] == si) + huff_code[p++] = code++; + code <<= 1; + si++; + } + + memset(codes, 0, sizeof(codes[0])*256); + memset(code_sizes, 0, sizeof(code_sizes[0])*256); + for (p = 0; p < last_p; p++) + { + codes[val[p]] = huff_code[p]; + code_sizes[val[p]] = huff_size[p]; + } +} + +// Quantization table generation. +void jpeg_encoder::compute_quant_table(int32 *pDst, int16 *pSrc) +{ + int32 q; + if (m_params.m_quality < 50) + q = 5000 / m_params.m_quality; + else + q = 200 - m_params.m_quality * 2; + for (int i = 0; i < 64; i++) + { + int32 j = *pSrc++; j = (j * q + 50L) / 100L; + *pDst++ = JPGE_MIN(JPGE_MAX(j, 1), 255); + } +} + +// Higher-level methods. +void jpeg_encoder::first_pass_init() +{ + m_bit_buffer = 0; m_bits_in = 0; + memset(m_last_dc_val, 0, 3 * sizeof(m_last_dc_val[0])); + m_mcu_y_ofs = 0; + m_pass_num = 1; +} + +bool jpeg_encoder::second_pass_init() +{ + compute_huffman_table(&m_huff_codes[0+0][0], &m_huff_code_sizes[0+0][0], m_huff_bits[0+0], m_huff_val[0+0]); + compute_huffman_table(&m_huff_codes[2+0][0], &m_huff_code_sizes[2+0][0], m_huff_bits[2+0], m_huff_val[2+0]); + if (m_num_components > 1) + { + compute_huffman_table(&m_huff_codes[0+1][0], &m_huff_code_sizes[0+1][0], m_huff_bits[0+1], m_huff_val[0+1]); + compute_huffman_table(&m_huff_codes[2+1][0], &m_huff_code_sizes[2+1][0], m_huff_bits[2+1], m_huff_val[2+1]); + } + first_pass_init(); + emit_markers(); + m_pass_num = 2; + return true; +} + +bool jpeg_encoder::jpg_open(int p_x_res, int p_y_res, int src_channels) +{ + m_num_components = 3; + switch (m_params.m_subsampling) + { + case Y_ONLY: + { + m_num_components = 1; + m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1; + m_mcu_x = 8; m_mcu_y = 8; + break; + } + case H1V1: + { + m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1; + m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; + m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; + m_mcu_x = 8; m_mcu_y = 8; + break; + } + case H2V1: + { + m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 1; + m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; + m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; + m_mcu_x = 16; m_mcu_y = 8; + break; + } + case H2V2: + { + m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 2; + m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; + m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; + m_mcu_x = 16; m_mcu_y = 16; + } + } + + m_image_x = p_x_res; m_image_y = p_y_res; + m_image_bpp = src_channels; + m_image_bpl = m_image_x * src_channels; + m_image_x_mcu = (m_image_x + m_mcu_x - 1) & (~(m_mcu_x - 1)); + m_image_y_mcu = (m_image_y + m_mcu_y - 1) & (~(m_mcu_y - 1)); + m_image_bpl_xlt = m_image_x * m_num_components; + m_image_bpl_mcu = m_image_x_mcu * m_num_components; + m_mcus_per_row = m_image_x_mcu / m_mcu_x; + + if ((m_mcu_lines[0] = static_cast(jpge_malloc(m_image_bpl_mcu * m_mcu_y))) == NULL) return false; + for (int i = 1; i < m_mcu_y; i++) + m_mcu_lines[i] = m_mcu_lines[i-1] + m_image_bpl_mcu; + + compute_quant_table(m_quantization_tables[0], s_std_lum_quant); + compute_quant_table(m_quantization_tables[1], m_params.m_no_chroma_discrim_flag ? s_std_lum_quant : s_std_croma_quant); + + m_out_buf_left = JPGE_OUT_BUF_SIZE; + m_pOut_buf = m_out_buf; + + if (m_params.m_two_pass_flag) + { + clear_obj(m_huff_count); + first_pass_init(); + } + else + { + memcpy(m_huff_bits[0+0], s_dc_lum_bits, 17); memcpy(m_huff_val [0+0], s_dc_lum_val, DC_LUM_CODES); + memcpy(m_huff_bits[2+0], s_ac_lum_bits, 17); memcpy(m_huff_val [2+0], s_ac_lum_val, AC_LUM_CODES); + memcpy(m_huff_bits[0+1], s_dc_chroma_bits, 17); memcpy(m_huff_val [0+1], s_dc_chroma_val, DC_CHROMA_CODES); + memcpy(m_huff_bits[2+1], s_ac_chroma_bits, 17); memcpy(m_huff_val [2+1], s_ac_chroma_val, AC_CHROMA_CODES); + if (!second_pass_init()) return false; // in effect, skip over the first pass + } + return m_all_stream_writes_succeeded; +} + +void jpeg_encoder::load_block_8_8_grey(int x) +{ + uint8 *pSrc; + sample_array_t *pDst = m_sample_array; + x <<= 3; + for (int i = 0; i < 8; i++, pDst += 8) + { + pSrc = m_mcu_lines[i] + x; + pDst[0] = pSrc[0] - 128; pDst[1] = pSrc[1] - 128; pDst[2] = pSrc[2] - 128; pDst[3] = pSrc[3] - 128; + pDst[4] = pSrc[4] - 128; pDst[5] = pSrc[5] - 128; pDst[6] = pSrc[6] - 128; pDst[7] = pSrc[7] - 128; + } +} + +void jpeg_encoder::load_block_8_8(int x, int y, int c) +{ + uint8 *pSrc; + sample_array_t *pDst = m_sample_array; + x = (x * (8 * 3)) + c; + y <<= 3; + for (int i = 0; i < 8; i++, pDst += 8) + { + pSrc = m_mcu_lines[y + i] + x; + pDst[0] = pSrc[0 * 3] - 128; pDst[1] = pSrc[1 * 3] - 128; pDst[2] = pSrc[2 * 3] - 128; pDst[3] = pSrc[3 * 3] - 128; + pDst[4] = pSrc[4 * 3] - 128; pDst[5] = pSrc[5 * 3] - 128; pDst[6] = pSrc[6 * 3] - 128; pDst[7] = pSrc[7 * 3] - 128; + } +} + +void jpeg_encoder::load_block_16_8(int x, int c) +{ + uint8 *pSrc1, *pSrc2; + sample_array_t *pDst = m_sample_array; + x = (x * (16 * 3)) + c; + int a = 0, b = 2; + for (int i = 0; i < 16; i += 2, pDst += 8) + { + pSrc1 = m_mcu_lines[i + 0] + x; + pSrc2 = m_mcu_lines[i + 1] + x; + pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3] + pSrc2[ 0 * 3] + pSrc2[ 1 * 3] + a) >> 2) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3] + pSrc2[ 2 * 3] + pSrc2[ 3 * 3] + b) >> 2) - 128; + pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3] + pSrc2[ 4 * 3] + pSrc2[ 5 * 3] + a) >> 2) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3] + pSrc2[ 6 * 3] + pSrc2[ 7 * 3] + b) >> 2) - 128; + pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3] + pSrc2[ 8 * 3] + pSrc2[ 9 * 3] + a) >> 2) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + pSrc2[10 * 3] + pSrc2[11 * 3] + b) >> 2) - 128; + pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + pSrc2[12 * 3] + pSrc2[13 * 3] + a) >> 2) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + pSrc2[14 * 3] + pSrc2[15 * 3] + b) >> 2) - 128; + int temp = a; a = b; b = temp; + } +} + +void jpeg_encoder::load_block_16_8_8(int x, int c) +{ + uint8 *pSrc1; + sample_array_t *pDst = m_sample_array; + x = (x * (16 * 3)) + c; + for (int i = 0; i < 8; i++, pDst += 8) + { + pSrc1 = m_mcu_lines[i + 0] + x; + pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3]) >> 1) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3]) >> 1) - 128; + pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3]) >> 1) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3]) >> 1) - 128; + pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3]) >> 1) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3]) >> 1) - 128; + pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3]) >> 1) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3]) >> 1) - 128; + } +} + +void jpeg_encoder::load_quantized_coefficients(int component_num) +{ + int32 *q = m_quantization_tables[component_num > 0]; + int16 *pDst = m_coefficient_array; + for (int i = 0; i < 64; i++) + { + sample_array_t j = m_sample_array[s_zag[i]]; + if (j < 0) + { + if ((j = -j + (*q >> 1)) < *q) + *pDst++ = 0; + else + *pDst++ = static_cast(-(j / *q)); + } + else + { + if ((j = j + (*q >> 1)) < *q) + *pDst++ = 0; + else + *pDst++ = static_cast((j / *q)); + } + q++; + } +} + +void jpeg_encoder::flush_output_buffer() +{ + if (m_out_buf_left != JPGE_OUT_BUF_SIZE) + m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(m_out_buf, JPGE_OUT_BUF_SIZE - m_out_buf_left); + m_pOut_buf = m_out_buf; + m_out_buf_left = JPGE_OUT_BUF_SIZE; +} + +void jpeg_encoder::put_bits(uint bits, uint len) +{ + m_bit_buffer |= ((uint32)bits << (24 - (m_bits_in += len))); + while (m_bits_in >= 8) + { + uint8 c; + #define JPGE_PUT_BYTE(c) { *m_pOut_buf++ = (c); if (--m_out_buf_left == 0) flush_output_buffer(); } + JPGE_PUT_BYTE(c = (uint8)((m_bit_buffer >> 16) & 0xFF)); + if (c == 0xFF) JPGE_PUT_BYTE(0); + m_bit_buffer <<= 8; + m_bits_in -= 8; + } +} + +void jpeg_encoder::code_coefficients_pass_one(int component_num) +{ + if (component_num >= 3) return; // just to shut up static analysis + int i, run_len, nbits, temp1; + int16 *src = m_coefficient_array; + uint32 *dc_count = component_num ? m_huff_count[0 + 1] : m_huff_count[0 + 0], *ac_count = component_num ? m_huff_count[2 + 1] : m_huff_count[2 + 0]; + + temp1 = src[0] - m_last_dc_val[component_num]; + m_last_dc_val[component_num] = src[0]; + if (temp1 < 0) temp1 = -temp1; + + nbits = 0; + while (temp1) + { + nbits++; temp1 >>= 1; + } + + dc_count[nbits]++; + for (run_len = 0, i = 1; i < 64; i++) + { + if ((temp1 = m_coefficient_array[i]) == 0) + run_len++; + else + { + while (run_len >= 16) + { + ac_count[0xF0]++; + run_len -= 16; + } + if (temp1 < 0) temp1 = -temp1; + nbits = 1; + while (temp1 >>= 1) nbits++; + ac_count[(run_len << 4) + nbits]++; + run_len = 0; + } + } + if (run_len) ac_count[0]++; +} + +void jpeg_encoder::code_coefficients_pass_two(int component_num) +{ + int i, j, run_len, nbits, temp1, temp2; + int16 *pSrc = m_coefficient_array; + uint *codes[2]; + uint8 *code_sizes[2]; + + if (component_num == 0) + { + codes[0] = m_huff_codes[0 + 0]; codes[1] = m_huff_codes[2 + 0]; + code_sizes[0] = m_huff_code_sizes[0 + 0]; code_sizes[1] = m_huff_code_sizes[2 + 0]; + } + else + { + codes[0] = m_huff_codes[0 + 1]; codes[1] = m_huff_codes[2 + 1]; + code_sizes[0] = m_huff_code_sizes[0 + 1]; code_sizes[1] = m_huff_code_sizes[2 + 1]; + } + + temp1 = temp2 = pSrc[0] - m_last_dc_val[component_num]; + m_last_dc_val[component_num] = pSrc[0]; + + if (temp1 < 0) + { + temp1 = -temp1; temp2--; + } + + nbits = 0; + while (temp1) + { + nbits++; temp1 >>= 1; + } + + put_bits(codes[0][nbits], code_sizes[0][nbits]); + if (nbits) put_bits(temp2 & ((1 << nbits) - 1), nbits); + + for (run_len = 0, i = 1; i < 64; i++) + { + if ((temp1 = m_coefficient_array[i]) == 0) + run_len++; + else + { + while (run_len >= 16) + { + put_bits(codes[1][0xF0], code_sizes[1][0xF0]); + run_len -= 16; + } + if ((temp2 = temp1) < 0) + { + temp1 = -temp1; + temp2--; + } + nbits = 1; + while (temp1 >>= 1) + nbits++; + j = (run_len << 4) + nbits; + put_bits(codes[1][j], code_sizes[1][j]); + put_bits(temp2 & ((1 << nbits) - 1), nbits); + run_len = 0; + } + } + if (run_len) + put_bits(codes[1][0], code_sizes[1][0]); +} + +void jpeg_encoder::code_block(int component_num) +{ + DCT2D(m_sample_array); + load_quantized_coefficients(component_num); + if (m_pass_num == 1) + code_coefficients_pass_one(component_num); + else + code_coefficients_pass_two(component_num); +} + +void jpeg_encoder::process_mcu_row() +{ + if (m_num_components == 1) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8_grey(i); code_block(0); + } + } + else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1)) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8(i, 0, 0); code_block(0); load_block_8_8(i, 0, 1); code_block(1); load_block_8_8(i, 0, 2); code_block(2); + } + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1)) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0); + load_block_16_8_8(i, 1); code_block(1); load_block_16_8_8(i, 2); code_block(2); + } + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2)) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0); + load_block_8_8(i * 2 + 0, 1, 0); code_block(0); load_block_8_8(i * 2 + 1, 1, 0); code_block(0); + load_block_16_8(i, 1); code_block(1); load_block_16_8(i, 2); code_block(2); + } + } +} + +bool jpeg_encoder::terminate_pass_one() +{ + optimize_huffman_table(0+0, DC_LUM_CODES); optimize_huffman_table(2+0, AC_LUM_CODES); + if (m_num_components > 1) + { + optimize_huffman_table(0+1, DC_CHROMA_CODES); optimize_huffman_table(2+1, AC_CHROMA_CODES); + } + return second_pass_init(); +} + +bool jpeg_encoder::terminate_pass_two() +{ + put_bits(0x7F, 7); + flush_output_buffer(); + emit_marker(M_EOI); + m_pass_num++; // purposely bump up m_pass_num, for debugging + return true; +} + +bool jpeg_encoder::process_end_of_image() +{ + if (m_mcu_y_ofs) + { + if (m_mcu_y_ofs < 16) // check here just to shut up static analysis + { + for (int i = m_mcu_y_ofs; i < m_mcu_y; i++) + memcpy(m_mcu_lines[i], m_mcu_lines[m_mcu_y_ofs - 1], m_image_bpl_mcu); + } + + process_mcu_row(); + } + + if (m_pass_num == 1) + return terminate_pass_one(); + else + return terminate_pass_two(); +} + +void jpeg_encoder::load_mcu(const void *pSrc) +{ + const uint8* Psrc = reinterpret_cast(pSrc); + + uint8* pDst = m_mcu_lines[m_mcu_y_ofs]; // OK to write up to m_image_bpl_xlt bytes to pDst + + if (m_num_components == 1) + { + if (m_image_bpp == 4) + RGBA_to_Y(pDst, Psrc, m_image_x); + else if (m_image_bpp == 3) + RGB_to_Y(pDst, Psrc, m_image_x); + else + memcpy(pDst, Psrc, m_image_x); + } + else + { + if (m_image_bpp == 4) + RGBA_to_YCC(pDst, Psrc, m_image_x); + else if (m_image_bpp == 3) + RGB_to_YCC(pDst, Psrc, m_image_x); + else + Y_to_YCC(pDst, Psrc, m_image_x); + } + + // Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16 + if (m_num_components == 1) + memset(m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt, pDst[m_image_bpl_xlt - 1], m_image_x_mcu - m_image_x); + else + { + const uint8 y = pDst[m_image_bpl_xlt - 3 + 0], cb = pDst[m_image_bpl_xlt - 3 + 1], cr = pDst[m_image_bpl_xlt - 3 + 2]; + uint8 *q = m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt; + for (int i = m_image_x; i < m_image_x_mcu; i++) + { + *q++ = y; *q++ = cb; *q++ = cr; + } + } + + if (++m_mcu_y_ofs == m_mcu_y) + { + process_mcu_row(); + m_mcu_y_ofs = 0; + } +} + +void jpeg_encoder::clear() +{ + m_mcu_lines[0] = NULL; + m_pass_num = 0; + m_all_stream_writes_succeeded = true; +} + +jpeg_encoder::jpeg_encoder() +{ + clear(); +} + +jpeg_encoder::~jpeg_encoder() +{ + deinit(); +} + +bool jpeg_encoder::init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params) +{ + deinit(); + if (((!pStream) || (width < 1) || (height < 1)) || ((src_channels != 1) && (src_channels != 3) && (src_channels != 4)) || (!comp_params.check())) return false; + m_pStream = pStream; + m_params = comp_params; + return jpg_open(width, height, src_channels); +} + +void jpeg_encoder::deinit() +{ + jpge_free(m_mcu_lines[0]); + clear(); +} + +bool jpeg_encoder::process_scanline(const void* pScanline) +{ + if ((m_pass_num < 1) || (m_pass_num > 2)) return false; + if (m_all_stream_writes_succeeded) + { + if (!pScanline) + { + if (!process_end_of_image()) return false; + } + else + { + load_mcu(pScanline); + } + } + return m_all_stream_writes_succeeded; +} + +// Higher level wrappers/examples (optional). +#include + +class cfile_stream : public output_stream +{ + cfile_stream(const cfile_stream &); + cfile_stream &operator= (const cfile_stream &); + + FILE* m_pFile; + bool m_bStatus; + +public: + cfile_stream() : m_pFile(NULL), m_bStatus(false) { } + + virtual ~cfile_stream() + { + close(); + } + + bool open(const char *pFilename) + { + close(); + m_pFile = fopen(pFilename, "wb"); + m_bStatus = (m_pFile != NULL); + return m_bStatus; + } + + bool close() + { + if (m_pFile) + { + if (fclose(m_pFile) == EOF) + { + m_bStatus = false; + } + m_pFile = NULL; + } + return m_bStatus; + } + + virtual bool put_buf(const void* pBuf, int len) + { + m_bStatus = m_bStatus && (fwrite(pBuf, len, 1, m_pFile) == 1); + return m_bStatus; + } + + uint get_size() const + { + return m_pFile ? ftell(m_pFile) : 0; + } +}; + +// Writes JPEG image to file. +bool compress_image_to_jpeg_file(const char *pFilename, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params) +{ + cfile_stream dst_stream; + if (!dst_stream.open(pFilename)) + return false; + + jpge::jpeg_encoder dst_image; + if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params)) + return false; + + for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++) + { + for (int i = 0; i < height; i++) + { + const uint8* pBuf = pImage_data + i * width * num_channels; + if (!dst_image.process_scanline(pBuf)) + return false; + } + if (!dst_image.process_scanline(NULL)) + return false; + } + + dst_image.deinit(); + + return dst_stream.close(); +} + +class memory_stream : public output_stream +{ + memory_stream(const memory_stream &); + memory_stream &operator= (const memory_stream &); + + uint8 *m_pBuf; + uint m_buf_size, m_buf_ofs; + +public: + memory_stream(void *pBuf, uint buf_size) : m_pBuf(static_cast(pBuf)), m_buf_size(buf_size), m_buf_ofs(0) { } + + virtual ~memory_stream() { } + + virtual bool put_buf(const void* pBuf, int len) + { + uint buf_remaining = m_buf_size - m_buf_ofs; + if ((uint)len > buf_remaining) + return false; + memcpy(m_pBuf + m_buf_ofs, pBuf, len); + m_buf_ofs += len; + return true; + } + + uint get_size() const + { + return m_buf_ofs; + } +}; + +bool compress_image_to_jpeg_file_in_memory(void *pDstBuf, int &buf_size, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params) +{ + if ((!pDstBuf) || (!buf_size)) + return false; + + memory_stream dst_stream(pDstBuf, buf_size); + + buf_size = 0; + + jpge::jpeg_encoder dst_image; + if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params)) + return false; + + for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++) + { + for (int i = 0; i < height; i++) + { + const uint8* pScanline = pImage_data + i * width * num_channels; + if (!dst_image.process_scanline(pScanline)) + return false; + } + if (!dst_image.process_scanline(NULL)) + return false; + } + + dst_image.deinit(); + + buf_size = dst_stream.get_size(); + return true; +} + +} // namespace jpge diff --git a/renderdoc/3rdparty/jpeg-compressor/jpge.h b/renderdoc/3rdparty/jpeg-compressor/jpge.h new file mode 100644 index 0000000000..262bbfbb38 --- /dev/null +++ b/renderdoc/3rdparty/jpeg-compressor/jpge.h @@ -0,0 +1,169 @@ +// jpge.h - C++ class for JPEG compression. +// Public domain, Rich Geldreich +// Alex Evans: Added RGBA support, linear memory allocator. +#ifndef JPEG_ENCODER_H +#define JPEG_ENCODER_H + +namespace jpge +{ + typedef unsigned char uint8; + typedef signed short int16; + typedef signed int int32; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef unsigned int uint; + + // JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common. + enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 }; + + // JPEG compression parameters structure. + struct params + { + inline params() : m_quality(85), m_subsampling(H2V2), m_no_chroma_discrim_flag(false), m_two_pass_flag(false) { } + + inline bool check() const + { + if ((m_quality < 1) || (m_quality > 100)) return false; + if ((uint)m_subsampling > (uint)H2V2) return false; + return true; + } + + // Quality: 1-100, higher is better. Typical values are around 50-95. + int m_quality; + + // m_subsampling: + // 0 = Y (grayscale) only + // 1 = YCbCr, no subsampling (H1V1, YCbCr 1x1x1, 3 blocks per MCU) + // 2 = YCbCr, H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU) + // 3 = YCbCr, H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common) + subsampling_t m_subsampling; + + // Disables CbCr discrimination - only intended for testing. + // If true, the Y quantization table is also used for the CbCr channels. + bool m_no_chroma_discrim_flag; + + bool m_two_pass_flag; + }; + + // Writes JPEG image to a file. + // num_channels must be 1 (Y) or 3 (RGB), image pitch must be width*num_channels. + bool compress_image_to_jpeg_file(const char *pFilename, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params = params()); + + // Writes JPEG image to memory buffer. + // On entry, buf_size is the size of the output buffer pointed at by pBuf, which should be at least ~1024 bytes. + // If return value is true, buf_size will be set to the size of the compressed data. + bool compress_image_to_jpeg_file_in_memory(void *pBuf, int &buf_size, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params = params()); + + // Output stream abstract class - used by the jpeg_encoder class to write to the output stream. + // put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts. + class output_stream + { + public: + virtual ~output_stream() { }; + virtual bool put_buf(const void* Pbuf, int len) = 0; + template inline bool put_obj(const T& obj) { return put_buf(&obj, sizeof(T)); } + }; + + // Lower level jpeg_encoder class - useful if more control is needed than the above helper functions. + class jpeg_encoder + { + public: + jpeg_encoder(); + ~jpeg_encoder(); + + // Initializes the compressor. + // pStream: The stream object to use for writing compressed data. + // params - Compression parameters structure, defined above. + // width, height - Image dimensions. + // channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data. + // Returns false on out of memory or if a stream write fails. + bool init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params = params()); + + const params &get_params() const { return m_params; } + + // Deinitializes the compressor, freeing any allocated memory. May be called at any time. + void deinit(); + + uint get_total_passes() const { return m_params.m_two_pass_flag ? 2 : 1; } + inline uint get_cur_pass() { return m_pass_num; } + + // Call this method with each source scanline. + // width * src_channels bytes per scanline is expected (RGB or Y format). + // You must call with NULL after all scanlines are processed to finish compression. + // Returns false on out of memory or if a stream write fails. + bool process_scanline(const void* pScanline); + + private: + jpeg_encoder(const jpeg_encoder &); + jpeg_encoder &operator =(const jpeg_encoder &); + + typedef int32 sample_array_t; + + output_stream *m_pStream; + params m_params; + uint8 m_num_components; + uint8 m_comp_h_samp[3], m_comp_v_samp[3]; + int m_image_x, m_image_y, m_image_bpp, m_image_bpl; + int m_image_x_mcu, m_image_y_mcu; + int m_image_bpl_xlt, m_image_bpl_mcu; + int m_mcus_per_row; + int m_mcu_x, m_mcu_y; + uint8 *m_mcu_lines[16]; + uint8 m_mcu_y_ofs; + sample_array_t m_sample_array[64]; + int16 m_coefficient_array[64]; + int32 m_quantization_tables[2][64]; + uint m_huff_codes[4][256]; + uint8 m_huff_code_sizes[4][256]; + uint8 m_huff_bits[4][17]; + uint8 m_huff_val[4][256]; + uint32 m_huff_count[4][256]; + int m_last_dc_val[3]; + enum { JPGE_OUT_BUF_SIZE = 2048 }; + uint8 m_out_buf[JPGE_OUT_BUF_SIZE]; + uint8 *m_pOut_buf; + uint m_out_buf_left; + uint32 m_bit_buffer; + uint m_bits_in; + uint8 m_pass_num; + bool m_all_stream_writes_succeeded; + + void optimize_huffman_table(int table_num, int table_len); + void emit_byte(uint8 i); + void emit_word(uint i); + void emit_marker(int marker); + void emit_jfif_app0(); + void emit_dqt(); + void emit_sof(); + void emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag); + void emit_dhts(); + void emit_sos(); + void emit_markers(); + void compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val); + void compute_quant_table(int32 *dst, int16 *src); + void adjust_quant_table(int32 *dst, int32 *src); + void first_pass_init(); + bool second_pass_init(); + bool jpg_open(int p_x_res, int p_y_res, int src_channels); + void load_block_8_8_grey(int x); + void load_block_8_8(int x, int y, int c); + void load_block_16_8(int x, int c); + void load_block_16_8_8(int x, int c); + void load_quantized_coefficients(int component_num); + void flush_output_buffer(); + void put_bits(uint bits, uint len); + void code_coefficients_pass_one(int component_num); + void code_coefficients_pass_two(int component_num); + void code_block(int component_num); + void process_mcu_row(); + bool terminate_pass_one(); + bool terminate_pass_two(); + bool process_end_of_image(); + void load_mcu(const void* src); + void clear(); + void init(); + }; + +} // namespace jpge + +#endif // JPEG_ENCODER diff --git a/renderdoc/3rdparty/lz4/lz4.c b/renderdoc/3rdparty/lz4/lz4.c new file mode 100644 index 0000000000..f521b0fdb7 --- /dev/null +++ b/renderdoc/3rdparty/lz4/lz4.c @@ -0,0 +1,865 @@ +/* + LZ4 - Fast LZ compression algorithm + Copyright (C) 2011-2013, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : http://code.google.com/p/lz4/ + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + +//************************************** +// Tuning parameters +//************************************** +// MEMORY_USAGE : +// Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +// Increasing memory usage improves compression ratio +// Reduced memory usage can improve speed, due to cache effect +// Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache +#define MEMORY_USAGE 14 + +// HEAPMODE : +// Select how default compression functions will allocate memory for their hash table, +// in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)). +#define HEAPMODE 0 + + +//************************************** +// CPU Feature Detection +//************************************** +// 32 or 64 bits ? +#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \ + || defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \ + || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) \ + || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) ) // Detects 64 bits mode +# define LZ4_ARCH64 1 +#else +# define LZ4_ARCH64 0 +#endif + +// Little Endian or Big Endian ? +// Overwrite the #define below if you know your architecture endianess +#if defined (__GLIBC__) +# include +# if (__BYTE_ORDER == __BIG_ENDIAN) +# define LZ4_BIG_ENDIAN 1 +# endif +#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) +# define LZ4_BIG_ENDIAN 1 +#elif defined(__sparc) || defined(__sparc__) \ + || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ + || defined(__hpux) || defined(__hppa) \ + || defined(_MIPSEB) || defined(__s390__) +# define LZ4_BIG_ENDIAN 1 +#else +// Little Endian assumed. PDP Endian and other very rare endian format are unsupported. +#endif + +// Unaligned memory access is automatically enabled for "common" CPU, such as x86. +// For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property +// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance +#if defined(__ARM_FEATURE_UNALIGNED) +# define LZ4_FORCE_UNALIGNED_ACCESS 1 +#endif + +// Define this parameter if your target system or compiler does not support hardware bit count +#if defined(_MSC_VER) && defined(_WIN32_WCE) // Visual Studio for Windows CE does not support Hardware bit count +# define LZ4_FORCE_SW_BITCOUNT +#endif + +// BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : +// This option may provide a small boost to performance for some big endian cpu, although probably modest. +// You may set this option to 1 if data will remain within closed environment. +// This option is useless on Little_Endian CPU (such as x86) +//#define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 + + +//************************************** +// Compiler Options +//************************************** +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) // C99 +/* "restrict" is a known keyword */ +#else +# define restrict // Disable restrict +#endif + +#ifdef _MSC_VER // Visual Studio +# define FORCE_INLINE static __forceinline +# include // For Visual 2005 +# if LZ4_ARCH64 // 64-bits +# pragma intrinsic(_BitScanForward64) // For Visual 2005 +# pragma intrinsic(_BitScanReverse64) // For Visual 2005 +# else // 32-bits +# pragma intrinsic(_BitScanForward) // For Visual 2005 +# pragma intrinsic(_BitScanReverse) // For Visual 2005 +# endif +# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant +#else +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif +#endif + +#ifdef _MSC_VER +# define lz4_bswap16(x) _byteswap_ushort(x) +#else +# define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) +#endif + +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) +# define expect(expr,value) (__builtin_expect ((expr),(value)) ) +#else +# define expect(expr,value) (expr) +#endif + +#define likely(expr) expect((expr) != 0, 1) +#define unlikely(expr) expect((expr) != 0, 0) + + +//************************************** +// Memory routines +//************************************** +#include // malloc, calloc, free +#define ALLOCATOR(n,s) calloc(n,s) +#define FREEMEM free +#include // memset, memcpy +#define MEM_INIT memset + + +//************************************** +// Includes +//************************************** +#include "lz4.h" + + +//************************************** +// Basic Types +//************************************** +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99 +# include + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; +#else + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; +#endif + +#if defined(__GNUC__) && !defined(LZ4_FORCE_UNALIGNED_ACCESS) +# define _PACKED __attribute__ ((packed)) +#else +# define _PACKED +#endif + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +# if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(1) +# else +# pragma pack(push, 1) +# endif +#endif + +typedef struct { U16 v; } _PACKED U16_S; +typedef struct { U32 v; } _PACKED U32_S; +typedef struct { U64 v; } _PACKED U64_S; +typedef struct {size_t v;} _PACKED size_t_S; + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +# if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(0) +# else +# pragma pack(pop) +# endif +#endif + +#define A16(x) (((U16_S *)(x))->v) +#define A32(x) (((U32_S *)(x))->v) +#define A64(x) (((U64_S *)(x))->v) +#define AARCH(x) (((size_t_S *)(x))->v) + + +//************************************** +// Constants +//************************************** +#define LZ4_HASHLOG (MEMORY_USAGE-2) +#define HASHTABLESIZE (1 << MEMORY_USAGE) +#define HASHNBCELLS4 (1 << LZ4_HASHLOG) + +#define MINMATCH 4 + +#define COPYLENGTH 8 +#define LASTLITERALS 5 +#define MFLIMIT (COPYLENGTH+MINMATCH) +const int LZ4_minLength = (MFLIMIT+1); + +#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT-1)) +#define SKIPSTRENGTH 6 // Increasing this value will make the compression run slower on incompressible data + +#define MAXD_LOG 16 +#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) + +#define ML_BITS 4 +#define ML_MASK ((1U<=e; + + +//**************************** +// Private functions +//**************************** +#if LZ4_ARCH64 + +FORCE_INLINE int LZ4_NbCommonBytes (register U64 val) +{ +# if defined(LZ4_BIG_ENDIAN) +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll(val) >> 3); +# else + int r; + if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif +# else +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll(val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif +# endif +} + +#else + +FORCE_INLINE int LZ4_NbCommonBytes (register U32 val) +{ +# if defined(LZ4_BIG_ENDIAN) +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz(val) >> 3); +# else + int r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif +# else +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz(val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif +# endif +} + +#endif + + +//**************************** +// Compression functions +//**************************** +FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType) +{ + if (tableType == byU16) + return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +FORCE_INLINE int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); } + +FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + switch (tableType) + { + case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; } + } +} + +FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); +} + +FORCE_INLINE const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } + if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } + { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } // default, to ensure a return +} + +FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); +} + + +FORCE_INLINE int LZ4_compress_generic( + void* ctx, + const char* source, + char* dest, + int inputSize, + int maxOutputSize, + + limitedOutput_directive limitedOutput, + tableType_t tableType, + prefix64k_directive prefix) +{ + const BYTE* ip = (const BYTE*) source; + const BYTE* const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (const BYTE*) source; + const BYTE* const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (const BYTE*)source); + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + maxOutputSize; + + int length; + const int skipStrength = SKIPSTRENGTH; + U32 forwardH; + + // Init conditions + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; // Unsupported input size, too large (or negative) + if ((prefix==withPrefix) && (ip != ((LZ4_Data_Structure*)ctx)->nextBlock)) return 0; // must continue from end of previous block + if (prefix==withPrefix) ((LZ4_Data_Structure*)ctx)->nextBlock=iend; // do it now, due to potential early exit + if ((tableType == byU16) && (inputSize>=LZ4_64KLIMIT)) return 0; // Size too large (not within 64K limit) + if (inputSize> skipStrength; + ip = forwardIp; + forwardIp = ip + step; + + if unlikely(forwardIp > mflimit) { goto _last_literals; } + + forwardH = LZ4_hashPosition(forwardIp, tableType); + ref = LZ4_getPositionOnHash(h, ctx, tableType, base); + LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + + } while ((ref + MAX_DISTANCE < ip) || (A32(ref) != A32(ip))); + + // Catch up + while ((ip>anchor) && (ref > lowLimit) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; } + + // Encode Literal length + length = (int)(ip - anchor); + token = op++; + if ((limitedOutput) && unlikely(op + length + (2 + 1 + LASTLITERALS) + (length/255) > oend)) return 0; // Check output limit + if (length>=(int)RUN_MASK) + { + int len = length-RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(length<>8) > oend)) return 0; // Check output limit + if (length>=(int)ML_MASK) + { + *token += ML_MASK; + length -= ML_MASK; + for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; } + if (length >= 255) { length-=255; *op++ = 255; } + *op++ = (BYTE)length; + } + else *token += (BYTE)(length); + + // Test end of chunk + if (ip > mflimit) { anchor = ip; break; } + + // Fill table + LZ4_putPosition(ip-2, ctx, tableType, base); + + // Test next position + ref = LZ4_getPosition(ip, ctx, tableType, base); + LZ4_putPosition(ip, ctx, tableType, base); + if ((ref + MAX_DISTANCE >= ip) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; } + + // Prepare next loop + anchor = ip++; + forwardH = LZ4_hashPosition(ip, tableType); + } + +_last_literals: + // Encode Last Literals + { + int lastRun = (int)(iend - anchor); + if ((limitedOutput) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; // Check output limit + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun<hashTable, 0, sizeof(lz4ds->hashTable)); + lz4ds->bufferStart = base; + lz4ds->base = base; + lz4ds->nextBlock = base; +} + +int LZ4_resetStreamState(void* state, const char* inputBuffer) +{ + if ((((size_t)state) & 3) != 0) return 1; // Error : pointer is not aligned on 4-bytes boundary + LZ4_init((LZ4_Data_Structure*)state, (const BYTE*)inputBuffer); + return 0; +} + +void* LZ4_create (const char* inputBuffer) +{ + void* lz4ds = ALLOCATOR(1, sizeof(LZ4_Data_Structure)); + LZ4_init ((LZ4_Data_Structure*)lz4ds, (const BYTE*)inputBuffer); + return lz4ds; +} + + +int LZ4_free (void* LZ4_Data) +{ + FREEMEM(LZ4_Data); + return (0); +} + + +char* LZ4_slideInputBuffer (void* LZ4_Data) +{ + LZ4_Data_Structure* lz4ds = (LZ4_Data_Structure*)LZ4_Data; + size_t delta = lz4ds->nextBlock - (lz4ds->bufferStart + 64 KB); + + if ( (lz4ds->base - delta > lz4ds->base) // underflow control + || ((size_t)(lz4ds->nextBlock - lz4ds->base) > 0xE0000000) ) // close to 32-bits limit + { + size_t deltaLimit = (lz4ds->nextBlock - 64 KB) - lz4ds->base; + int nH; + + for (nH=0; nH < HASHNBCELLS4; nH++) + { + if ((size_t)(lz4ds->hashTable[nH]) < deltaLimit) lz4ds->hashTable[nH] = 0; + else lz4ds->hashTable[nH] -= (U32)deltaLimit; + } + memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB); + lz4ds->base = lz4ds->bufferStart; + lz4ds->nextBlock = lz4ds->base + 64 KB; + } + else + { + memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB); + lz4ds->nextBlock -= delta; + lz4ds->base -= delta; + } + + return (char*)(lz4ds->nextBlock); +} + + +int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize) +{ + return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, 0, notLimited, byU32, withPrefix); +} + + +int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, maxOutputSize, limited, byU32, withPrefix); +} + + +//**************************** +// Decompression functions +//**************************** + +// This generic decompression function cover all use cases. +// It shall be instanciated several times, using different sets of directives +// Note that it is essential this generic function is really inlined, +// in order to remove useless branches during compilation optimisation. +FORCE_INLINE int LZ4_decompress_generic( + const char* source, + char* dest, + int inputSize, // + int outputSize, // If endOnInput==endOnInputSize, this value is the max size of Output Buffer. + + int endOnInput, // endOnOutputSize, endOnInputSize + int prefix64k, // noPrefix, withPrefix + int partialDecoding, // full, partial + int targetOutputSize // only used if partialDecoding==partial + ) +{ + // Local Variables + const BYTE* restrict ip = (const BYTE*) source; + const BYTE* ref; + const BYTE* const iend = ip + inputSize; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + + const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; // static reduces speed for LZ4_decompress_safe() on GCC64 + static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + + + // Special cases + if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; // targetOutputSize too high => decode everything + if ((endOnInput) && unlikely(outputSize==0)) return ((inputSize==1) && (*ip==0)) ? 0 : -1; // Empty output buffer + if ((!endOnInput) && unlikely(outputSize==0)) return (*ip==0?1:-1); + + + // Main Loop + while (1) + { + unsigned token; + size_t length; + + // get runlength + token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) + { + unsigned s=255; + while (((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-COPYLENGTH))) + { + if (partialDecoding) + { + if (cpy > oend) goto _output_error; // Error : write attempt beyond end of output buffer + if ((endOnInput) && (ip+length > iend)) goto _output_error; // Error : read attempt beyond end of input buffer + } + else + { + if ((!endOnInput) && (cpy != oend)) goto _output_error; // Error : block decoding must stop exactly there + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; // Error : input must be consumed + } + memcpy(op, ip, length); + ip += length; + op += length; + break; // Necessarily EOF, due to parsing restrictions + } + LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy; + + // get offset + LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; + if ((prefix64k==noPrefix) && unlikely(ref < (BYTE* const)dest)) goto _output_error; // Error : offset outside destination buffer + + // get matchlength + if ((length=(token&ML_MASK)) == ML_MASK) + { + while ((!endOnInput) || (ipoend-COPYLENGTH-(STEPSIZE-4)) + { + if (cpy > oend-LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals + LZ4_SECURECOPY(op, ref, (oend-COPYLENGTH)); + while(op (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) +static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } + +/* +LZ4_compressBound() : + Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible) + primarily useful for memory allocation of output buffer. + inline function is recommended for the general case, + macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation). + + isize : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) +*/ + + +int LZ4_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); + +/* +LZ4_compress_limitedOutput() : + Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'. + If it cannot achieve it, compression will stop, and result of the function will be zero. + This function never writes outside of provided output buffer. + + inputSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxOutputSize : is the size of the destination buffer (which must be already allocated) + return : the number of bytes written in buffer 'dest' + or 0 if the compression fails +*/ + + +int LZ4_decompress_fast (const char* source, char* dest, int outputSize); + +/* +LZ4_decompress_fast() : + outputSize : is the original (uncompressed) size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is malformed, the function will stop decoding and return a negative result. + note : This function is a bit faster than LZ4_decompress_safe() + This function never writes outside of output buffers, but may read beyond input buffer in case of malicious data packet. + Use this function preferably into a trusted environment (data to decode comes from a trusted source). + Destination buffer must be already allocated. Its size must be a minimum of 'outputSize' bytes. +*/ + +int LZ4_decompress_safe_partial (const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize); + +/* +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'inputSize' at position 'source' + into output buffer 'dest' of size 'maxOutputSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets +*/ + + +//***************************** +// Using an external allocation +//***************************** +int LZ4_sizeofState(); +int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* +These functions are provided should you prefer to allocate memory for compression tables with your own allocation methods. +To know how much memory must be allocated for the compression tables, use : +int LZ4_sizeofState(); + +Note that tables must be aligned on 4-bytes boundaries, otherwise compression will fail (return code 0). + +The allocated memory can be provided to the compressions functions using 'void* state' parameter. +LZ4_compress_withState() and LZ4_compress_limitedOutput_withState() are equivalent to previously described functions. +They just use the externally allocated memory area instead of allocating their own (on stack, or on heap). +*/ + + +//**************************** +// Streaming Functions +//**************************** + +void* LZ4_create (const char* inputBuffer); +int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize); +char* LZ4_slideInputBuffer (void* LZ4_Data); +int LZ4_free (void* LZ4_Data); + +/* +These functions allow the compression of dependent blocks, where each block benefits from prior 64 KB within preceding blocks. +In order to achieve this, it is necessary to start creating the LZ4 Data Structure, thanks to the function : + +void* LZ4_create (const char* inputBuffer); +The result of the function is the (void*) pointer on the LZ4 Data Structure. +This pointer will be needed in all other functions. +If the pointer returned is NULL, then the allocation has failed, and compression must be aborted. +The only parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer. +The input buffer must be already allocated, and size at least 192KB. +'inputBuffer' will also be the 'const char* source' of the first block. + +All blocks are expected to lay next to each other within the input buffer, starting from 'inputBuffer'. +To compress each block, use either LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(). +Their behavior are identical to LZ4_compress() or LZ4_compress_limitedOutput(), +but require the LZ4 Data Structure as their first argument, and check that each block starts right after the previous one. +If next block does not begin immediately after the previous one, the compression will fail (return 0). + +When it's no longer possible to lay the next block after the previous one (not enough space left into input buffer), a call to : +char* LZ4_slideInputBuffer(void* LZ4_Data); +must be performed. It will typically copy the latest 64KB of input at the beginning of input buffer. +Note that, for this function to work properly, minimum size of an input buffer must be 192KB. +==> The memory position where the next input data block must start is provided as the result of the function. + +Compression can then resume, using LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(), as usual. + +When compression is completed, a call to LZ4_free() will release the memory used by the LZ4 Data Structure. +*/ + +int LZ4_sizeofStreamState(); +int LZ4_resetStreamState(void* state, const char* inputBuffer); + +/* +These functions achieve the same result as : +void* LZ4_create (const char* inputBuffer); + +They are provided here to allow the user program to allocate memory using its own routines. + +To know how much space must be allocated, use LZ4_sizeofStreamState(); +Note also that space must be 4-bytes aligned. + +Once space is allocated, you must initialize it using : LZ4_resetStreamState(void* state, const char* inputBuffer); +void* state is a pointer to the space allocated. +It must be aligned on 4-bytes boundaries, and be large enough. +The parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer. +The input buffer must be already allocated, and size at least 192KB. +'inputBuffer' will also be the 'const char* source' of the first block. + +The same space can be re-used multiple times, just by initializing it each time with LZ4_resetStreamState(). +return value of LZ4_resetStreamState() must be 0 is OK. +Any other value means there was an error (typically, pointer is not aligned on 4-bytes boundaries). +*/ + + +int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize); +int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize); + +/* +*_withPrefix64k() : + These decoding functions work the same as their "normal name" versions, + but can use up to 64KB of data in front of 'char* dest'. + These functions are necessary to decode inter-dependant blocks. +*/ + + +//**************************** +// Obsolete Functions +//**************************** + +static inline int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +static inline int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + +/* +These functions are deprecated and should no longer be used. +They are provided here for compatibility with existing user programs. +*/ + + + +#if defined (__cplusplus) +} +#endif diff --git a/renderdoc/3rdparty/mhook/COPYING b/renderdoc/3rdparty/mhook/COPYING new file mode 100644 index 0000000000..1ca1bcf86c --- /dev/null +++ b/renderdoc/3rdparty/mhook/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2007-2008, Marton Anka +Portions Copyright (c) 2007, Matt Conover + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/renderdoc/3rdparty/mhook/disasm-lib/cpu.c b/renderdoc/3rdparty/mhook/disasm-lib/cpu.c new file mode 100644 index 0000000000..2a12692ac0 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/cpu.c @@ -0,0 +1,93 @@ +// Copyright (C) 2003, Matt Conover (mconover@gmail.com) +#include "cpu.h" +#include + +// NOTE: this assumes default scenarios (i.e., we assume CS/DS/ES/SS and flat +// and all have a base of 0 and limit of 0xffffffff, we don't try to verify +// that in the GDT) +// +// TODO: use inline assembly to get selector for segment +// Segment = x86 segment register (SEG_ES = 0, SEG_CS = 1, ...) +BYTE *GetAbsoluteAddressFromSegment(BYTE Segment, DWORD Offset) +{ + switch (Segment) + { + // Windows uses a flat address space (except FS for x86 and GS for x64) + case 0: // SEG_ES + case 1: // SEG_CS + case 2: // SEG_SS + case 3: // SEG_DS + return (BYTE *)(DWORD_PTR)Offset; + case 4: // SEG_FS + case 5: // SEG_GS + return (BYTE *)(DWORD_PTR)Offset; + // Note: we're really supposed to do this, but get_teb is not implemented + // in this bastardized version of the disassembler. + // return (BYTE *)get_teb() + Offset; + default: + assert(0); + return (BYTE *)(DWORD_PTR)Offset; + } +} + +// This is an GDT/LDT selector (pGDT+Selector) +BYTE *GetAbsoluteAddressFromSelector(WORD Selector, DWORD Offset) +{ + DESCRIPTOR_ENTRY Entry; + GATE_ENTRY *Gate; + ULONG_PTR Base; + + assert(Selector < 0x10000); + if (!GetThreadSelectorEntry(GetCurrentThread(), Selector, (LDT_ENTRY *)&Entry)) return NULL; + if (!Entry.Present) return NULL; + if (Entry.System) + { + Base = 0; +#ifdef _WIN64 + Base |= (ULONG_PTR)Entry.HighOffset64 << 32; +#endif + Base |= Entry.BaseHi << 24; + Base |= Entry.BaseMid << 16; + Base |= Entry.BaseLow; + } + else + { + switch (Entry.Type) + { + case 1: // 16-bit TSS (available) + case 2: // LDT + case 3: // 16-bit TSS (busy) + case 9: // 32-bit TSS (available) + case 11: // 32-bit TSS (busy) + Base = 0; +#ifdef _WIN64 + Base |= (ULONG_PTR)Entry.HighOffset64 << 32; +#endif + Base |= Entry.BaseHi << 24; + Base |= Entry.BaseMid << 16; + Base |= Entry.BaseLow; + break; + + case 4: // 16-bit call gate + case 5: // task gate + case 6: // 16-bit interrupt gate + case 7: // 16-bit task gate + case 12: // 32-bit call gate + case 14: // 32-bit interrupt gate + case 15: // 32-bit trap gate + Gate = (GATE_ENTRY *)&Entry; +#ifdef _WIN64 + Base = ((ULONG_PTR)Gate->HighOffset64 << 32) | (Gate->HighOffset << 16) | Gate->LowOffset; +#else + Base = (Gate->HighOffset << 16) | Gate->LowOffset; +#endif + assert(!Offset); Offset = 0; + break; + default: + assert(0); + return NULL; + } + } + return (BYTE *)Base + Offset; +} + diff --git a/renderdoc/3rdparty/mhook/disasm-lib/cpu.h b/renderdoc/3rdparty/mhook/disasm-lib/cpu.h new file mode 100644 index 0000000000..dce9d3ee36 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/cpu.h @@ -0,0 +1,279 @@ +// Copyright (C) 2003, Matt Conover (mconover@gmail.com) +#ifndef CPU_H +#define CPU_H +#ifdef __cplusplus +extern "C" { +#endif +#pragma pack(push,1) + +#pragma warning(disable: 4214) + +#include +#include "misc.h" + +//////////////////////////////////////////////////////// +// System descriptors +//////////////////////////////////////////////////////// + +#define GDT_NULL 0 +#define GDT_R0_CODE 0x08 +#define GDT_R0_DATA 0x10 +#define GDT_R3_CODE 0x18 +#define GDT_R3_DATA 0x20 +#define GDT_TSS 0x28 +#define GDT_PCR 0x30 +#define GDT_R3_TEB 0x38 +#define GDT_VDM 0x40 +#define GDT_LDT 0x48 +#define GDT_DOUBLEFAULT_TSS 0x50 +#define GDT_NMI_TSS 0x58 + +// 16-bit GDT entries: +// TODO: #define GDT_ABIOS_UNKNOWN 0x60 (22F30-32F2F) +#define GDT_ABIOS_VIDEO 0x68 +#define GDT_ABIOS_GDT 0x70 // descriptor describing ABIOS GDT itself +#define GDT_ABIOS_NTOS 0x78 // first 64K of NTOSKRNL +#define GDT_ABIOS_CDA 0xE8 // common data area +#define GDT_ABIOS_CODE 0xF0 // KiI386AbiosCall +#define GDT_ABIOS_STACK 0xF8 + +#define SELECTOR_RPL_MASK 0x03 // bits 0-1 +#define SELECTOR_LDT 0x04 // bit 2 + +// for data selectors +#define DATA_ACCESS_MASK (1<<0) +#define DATA_WRITE_ENABLE_MASK (1<<1) +#define DATA_EXPAND_DOWN_MASK (1<<2) + +// for code selectors +#define CODE_ACCESS_MASK (1<<0) +#define CODE_READ_MASK (1<<1) +#define CODE_CONFORMING_MASK (1<<2) +#define CODE_FLAG (1<<3) + +#define TASK_GATE 5 +#define INTERRUPT_GATE 6 +#define TRAP_GATE 7 + +typedef struct _IDT_ENTRY +{ + USHORT LowOffset; + USHORT Selector; + UCHAR Ignored : 5; + UCHAR Zero : 3; + UCHAR Type : 3; + UCHAR Is32Bit : 1; + UCHAR Ignored2 : 1; + UCHAR DPL : 2; + UCHAR Present : 1; + USHORT HighOffset; +#ifdef _WIN64 + ULONG HighOffset64; + ULONG Reserved; +#endif +} IDT_ENTRY, TRAP_GATE_ENTRY; + +typedef struct _CALL_GATE_ENTRY +{ + USHORT LowOffset; + USHORT Selector; + UCHAR ParameterCount: 4; + UCHAR Ignored : 3; + UCHAR Type : 5; + UCHAR DPL : 2; + UCHAR Present : 1; + USHORT HighOffset; +#ifdef _WIN64 + ULONG HighOffset64; + ULONG Reserved; +#endif +} CALL_GATE_ENTRY; + +typedef struct _TASK_GATE_ENTRY +{ + USHORT Ignored; + USHORT Selector; + UCHAR Ignored2 : 5; + UCHAR Zero : 3; + UCHAR Type : 5; + UCHAR DPL : 2; + UCHAR Present : 1; + USHORT Ignored3; +} TASK_GATE_ENTRY; + +typedef struct _DESCRIPTOR_ENTRY +{ + USHORT LimitLow; + USHORT BaseLow; + UCHAR BaseMid; + UCHAR Type : 4; // 10EWA (code), E=ExpandDown, W=Writable, A=Accessed + // 11CRA (data), C=Conforming, R=Readable, A=Accessed + UCHAR System : 1; // if 1 then it is a gate or LDT + UCHAR DPL : 2; // descriptor privilege level; + // for data selectors, MAX(CPL, RPL) must be <= DPL to access (or else GP# fault) + // for non-conforming code selectors (without callgate), MAX(CPL, RPL) must be <= DPL to access (or else GP# fault) + // for conforming code selectors, MAX(CPL, RPL) must be >= DPL (i.e., CPL 0-2 cannot access if DPL is 3) + // for non-conforming code selectors (with call gate), DPL indicates lowest privilege allowed to access gate + UCHAR Present : 1; + UCHAR LimitHigh : 4; + UCHAR Available: 1; // aka AVL + UCHAR Reserved : 1; + UCHAR Is32Bit : 1; // aka B flag + UCHAR Granularity : 1; // aka G flag + UCHAR BaseHi : 8; +#ifdef _WIN64 + ULONG HighOffset64; + ULONG Reserved2; +#endif +} DESCRIPTOR_ENTRY; + +typedef struct _GATE_ENTRY +{ + USHORT LowOffset; + UCHAR Skip; + UCHAR Type : 5; + UCHAR DPL : 2; + UCHAR Present : 1; + USHORT HighOffset; +#ifdef _WIN64 + ULONG HighOffset64; + ULONG Reserved; +#endif +} GATE_ENTRY; + +// TODO: update for X64 +typedef struct _PTE_ENTRY +{ + ULONG Present : 1; + ULONG Write : 1; + ULONG Owner : 1; // E.g., user mode or supervisor mode + ULONG WriteThrough : 1; + ULONG CacheDisable : 1; + ULONG Accessed : 1; + ULONG Dirty : 1; + ULONG PAT : 1; + ULONG Global : 1; + ULONG CopyOnWrite : 1; + ULONG Prototype : 1; + ULONG Transition : 1; + ULONG Address : 20; +} PTE_ENTRY; + +// TODO: update for X64 +typedef struct _PDE_ENTRY +{ + ULONG Present : 1; + ULONG Write : 1; + ULONG Owner : 1; + ULONG WriteThrough : 1; + ULONG CacheDisable : 1; + ULONG Accessed : 1; + ULONG Reserved1 : 1; + ULONG PageSize : 1; + ULONG Global : 1; + ULONG Reserved : 3; + ULONG Address : 20; +} PDE_ENTRY; + +// TODO: update for X64 +typedef struct _IO_ACCESS_MAP +{ + UCHAR DirectionMap[32]; + UCHAR IoMap[8196]; +} IO_ACCESS_MAP; + +#define MIN_TSS_SIZE FIELD_OFFSET(TSS_ENTRY, IoMaps) +// TODO: update for X64 +typedef struct _TSS_ENTRY +{ + USHORT Backlink; + USHORT Reserved0; + ULONG Esp0; + USHORT Ss0; + USHORT Reserved1; + ULONG NotUsed1[4]; + ULONG CR3; + ULONG Eip; + ULONG NotUsed2[9]; + USHORT Es; + USHORT Reserved2; + USHORT Cs; + USHORT Reserved3; + USHORT Ss; + USHORT Reserved4; + USHORT Ds; + USHORT Reserved5; + USHORT Fs; + USHORT Reserved6; + USHORT Gs; + USHORT Reserved7; + USHORT LDT; + USHORT Reserved8; + USHORT Flags; + USHORT IoMapBase; + IO_ACCESS_MAP IoMaps[1]; + UCHAR IntDirectionMap[32]; +} TSS_ENTRY; + +// TODO: update for X64 +typedef struct _TSS16_ENTRY +{ + USHORT Backlink; + USHORT Sp0; + USHORT Ss0; + USHORT Sp1; + USHORT Ss1; + USHORT Sp2; + USHORT Ss3; + USHORT Ip; + USHORT Flags; + USHORT Ax; + USHORT Cx; + USHORT Dx; + USHORT Bx; + USHORT Sp; + USHORT Bp; + USHORT Si; + USHORT Di; + USHORT Es; + USHORT Cs; + USHORT Ss; + USHORT Ds; + USHORT LDT; +} TSS16_ENTRY; + +// TODO: update for X64 +typedef struct _GDT_ENTRY +{ + USHORT LimitLow; + USHORT BaseLow; + union { + struct { + UCHAR BaseMid; + UCHAR Flags1; + UCHAR Flags2; + UCHAR BaseHi; + } Bytes; + struct { + ULONG BaseMid : 8; + ULONG Type : 5; + ULONG Dpl : 2; + ULONG Pres : 1; + ULONG LimitHi : 4; + ULONG Sys : 1; + ULONG Reserved_0 : 1; + ULONG Default_Big : 1; + ULONG Granularity : 1; + ULONG BaseHi : 8; + } Bits; + } HighWord; +} GDT_ENTRY; + +BYTE *GetAbsoluteAddressFromSegment(BYTE Segment, DWORD Offset); +BYTE *GetAbsoluteAddressFromSelector(WORD Selector, DWORD Offset); + +#pragma pack(pop) +#ifdef __cplusplus +} +#endif +#endif // CPU_H \ No newline at end of file diff --git a/renderdoc/3rdparty/mhook/disasm-lib/disasm.c b/renderdoc/3rdparty/mhook/disasm-lib/disasm.c new file mode 100644 index 0000000000..43e7766b68 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/disasm.c @@ -0,0 +1,122 @@ +// Copyright (C) 2004, Matt Conover (mconover@gmail.com) +#undef NDEBUG +#include +#include +#include "disasm.h" + +#ifdef NO_SANITY_CHECKS +#define NDEBUG +#undef assert +#define assert(x) +#endif + +////////////////////////////////////////////////////////////////////// +// Global variables +////////////////////////////////////////////////////////////////////// + +ARCHITECTURE_FORMAT SupportedArchitectures[] = +{ + { ARCH_X86, &X86 }, + { ARCH_X86_16, &X86 }, + { ARCH_X64, &X86 }, + { ARCH_UNKNOWN, NULL } +}; + +typedef struct _DISASM_ARG_INFO +{ + INSTRUCTION *MatchedInstruction; + BOOL MatchPrefix; + U8 *Opcode; + U32 OpcodeLength; + INSTRUCTION_TYPE InstructionType; + U32 Count; +} DISASM_ARG_INFO; + +////////////////////////////////////////////////////////////////////// +// Function prototypes +////////////////////////////////////////////////////////////////////// + +BOOL InitInstruction(INSTRUCTION *Instruction, DISASSEMBLER *Disassembler); +struct _ARCHITECTURE_FORMAT *GetArchitectureFormat(ARCHITECTURE_TYPE Type); + +////////////////////////////////////////////////////////////////////// +// Disassembler setup +////////////////////////////////////////////////////////////////////// + +BOOL InitDisassembler(DISASSEMBLER *Disassembler, ARCHITECTURE_TYPE Architecture) +{ + ARCHITECTURE_FORMAT *ArchFormat; + + memset(Disassembler, 0, sizeof(DISASSEMBLER)); + Disassembler->Initialized = DISASSEMBLER_INITIALIZED; + + ArchFormat = GetArchitectureFormat(Architecture); + if (!ArchFormat) { assert(0); return FALSE; } + Disassembler->ArchType = ArchFormat->Type; + Disassembler->Functions = ArchFormat->Functions; + return TRUE; +} + +void CloseDisassembler(DISASSEMBLER *Disassembler) +{ + memset(Disassembler, 0, sizeof(DISASSEMBLER)); +} + +////////////////////////////////////////////////////////////////////// +// Instruction setup +////////////////////////////////////////////////////////////////////// + +BOOL InitInstruction(INSTRUCTION *Instruction, DISASSEMBLER *Disassembler) +{ + memset(Instruction, 0, sizeof(INSTRUCTION)); + Instruction->Initialized = INSTRUCTION_INITIALIZED; + Instruction->Disassembler = Disassembler; + memset(Instruction->String, ' ', MAX_OPCODE_DESCRIPTION-1); + Instruction->String[MAX_OPCODE_DESCRIPTION-1] = '\0'; + return TRUE; +} + +// If Decode = FALSE, only the following fields are valid: +// Instruction->Length, Instruction->Address, Instruction->Prefixes, Instruction->PrefixCount, +// Instruction->OpcodeBytes, Instruction->Instruction->OpcodeLength, Instruction->Groups, +// Instruction->Type, Instruction->OperandCount +// +// If Disassemble = TRUE, then Instruction->String is valid (also requires Decode = TRUE) +// +// WARNING: This will overwrite the previously obtained instruction +INSTRUCTION *GetInstruction(DISASSEMBLER *Disassembler, U64 VirtualAddress, U8 *Address, U32 Flags) +{ + if (Disassembler->Initialized != DISASSEMBLER_INITIALIZED) { assert(0); return NULL; } + assert(Address); + InitInstruction(&Disassembler->Instruction, Disassembler); + Disassembler->Instruction.Address = Address; + Disassembler->Instruction.VirtualAddressDelta = VirtualAddress - (U64)Address; + if (!Disassembler->Functions->GetInstruction(&Disassembler->Instruction, Address, Flags)) + { + assert(Disassembler->Instruction.Address == Address); + assert(Disassembler->Instruction.Length < MAX_INSTRUCTION_LENGTH); + + // Save the address that failed, in case the lower-level disassembler didn't + Disassembler->Instruction.Address = Address; + Disassembler->Instruction.ErrorOccurred = TRUE; + return NULL; + } + return &Disassembler->Instruction; +} + +/////////////////////////////////////////////////////////////////////////// +// Miscellaneous +/////////////////////////////////////////////////////////////////////////// + +ARCHITECTURE_FORMAT *GetArchitectureFormat(ARCHITECTURE_TYPE Type) +{ + ARCHITECTURE_FORMAT *Format; + for (Format = SupportedArchitectures; Format->Type != ARCH_UNKNOWN; Format++) + { + if (Format->Type == Type) return Format; + } + + assert(0); + return NULL; +} + diff --git a/renderdoc/3rdparty/mhook/disasm-lib/disasm.h b/renderdoc/3rdparty/mhook/disasm-lib/disasm.h new file mode 100644 index 0000000000..ea5cd3f55a --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/disasm.h @@ -0,0 +1,583 @@ +// Copyright (C) 2004, Matt Conover (mconover@gmail.com) +// +// WARNING: +// I wouldn't recommend changing any flags like OP_*, ITYPE_*, or *_MASK +// aside from those marked as UNUSED. This is because the flags parts of +// the flags are architecture independent and other are left to specific +// architectures to define, so unless you understand the relationships +// between them, I would leave them as is. + +#ifndef DISASM_H +#define DISASM_H +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include "misc.h" + +#pragma warning(disable: 4214) +#pragma warning(disable: 4324) + +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; +typedef signed long S32; +typedef unsigned long U32; +typedef LONG64 S64; +typedef ULONG64 U64; + +#ifdef SPEEDY +// On Visual Studio 6, making the internal functions inline makes compiling take forever +#define INTERNAL static _inline +#define INLINE _inline +#else +#define INTERNAL static +#define INLINE +#endif + +#define VALID_INSTRUCTION(i) ((i) && !((i)->ErrorOccurred)) +#define NEXT_INSTRUCTION(i) ((i)->Address + (i)->Length) +#define DISASM_ARCH_TYPE(dis) ((dis)->ArchType) +#define INS_ARCH_TYPE(ins) DISASM_ARCH_TYPE((ins)->Disassembler) + +// NOTE: these should be as big set to the maximum of the supported architectures +#define MAX_PREFIX_LENGTH 15 +#define MAX_OPERAND_COUNT 3 +#define MAX_INSTRUCTION_LENGTH 25 +#define MAX_OPCODE_LENGTH 3 +#define MAX_OPCODE_DESCRIPTION 256 + +///////////////////////////////////////////////////////////////////// +// Code branch +///////////////////////////////////////////////////////////////////// + +#define MAX_CODE_REFERENCE_COUNT 3 + +typedef struct _CODE_BRANCH +{ + U64 Addresses[MAX_CODE_REFERENCE_COUNT]; // NULL if multiple to addresses + U32 Count; + U8 IsLoop : 1; + U8 IsCall : 1; // branch if false + U8 IsIndirect : 1; // call/jmp [Address] + U8 AddressOffset: 5; + struct _INSTRUCTION_OPERAND *Operand; // the operand containg the address +} CODE_BRANCH; + +///////////////////////////////////////////////////////////////////// +// Data references +///////////////////////////////////////////////////////////////////// + +#define MAX_DATA_REFERENCE_COUNT 3 + +typedef struct _DATA_REFERENCE +{ + U64 Addresses[MAX_DATA_REFERENCE_COUNT]; // NULL if multiple to addresses + U32 Count; + ULONG_PTR DataSize; + struct _INSTRUCTION_OPERAND *Operand; // the operand containg the address +} DATA_REFERENCE; + +//////////////////////////////////////////////////////////////////// +// Instruction +///////////////////////////////////////////////////////////////////// + +// +// Instruction types (bits 0-7) +// Instruction groups (bits 8-26) +// +#define ITYPE_EXEC_OFFSET (1<<8) +#define ITYPE_ARITH_OFFSET (1<<9) +#define ITYPE_LOGIC_OFFSET (1<<10) +#define ITYPE_STACK_OFFSET (1<<11) +#define ITYPE_TESTCOND_OFFSET (1<<12) +#define ITYPE_LOAD_OFFSET (1<<13) +#define ITYPE_ARRAY_OFFSET (1<<14) +#define ITYPE_BIT_OFFSET (1<<15) +#define ITYPE_FLAG_OFFSET (1<<16) +#define ITYPE_FPU_OFFSET (1<<17) +#define ITYPE_TRAPS_OFFSET (1<<18) +#define ITYPE_SYSTEM_OFFSET (1<<19) +#define ITYPE_OTHER_OFFSET (1<<20) +#define ITYPE_UNUSED1_OFFSET (1<<21) +#define ITYPE_UNUSED2_OFFSET (1<<22) +#define ITYPE_UNUSED3_OFFSET (1<<23) +#define ITYPE_UNUSED4_OFFSET (1<<24) +#define ITYPE_UNUSED5_OFFSET (1<<25) +#define ITYPE_UNUSED6_OFFSET (1<<26) +#define ITYPE_EXT_UNUSED1 (1<<27) +#define ITYPE_EXT_UNUSED2 (1<<28) +#define ITYPE_EXT_UNUSED3 (1<<29) +#define ITYPE_EXT_UNUSED4 (1<<30) +#define ITYPE_EXT_UNUSED5 (1<<31) + +// +// X86-specific flags (bits 27-31) +// + +#define ITYPE_EXT_64 ITYPE_EXT_UNUSED1 // Use index 1 if in 64-bit mode and 0 otherwise +#define ITYPE_EXT_MODRM ITYPE_EXT_UNUSED2 // ModRM byte may extend the opcode +#define ITYPE_EXT_SUFFIX ITYPE_EXT_UNUSED3 // byte after ModRM/SIB/displacement is the third opcode +#define ITYPE_EXT_PREFIX ITYPE_EXT_UNUSED4 // prefix +#define ITYPE_EXT_FPU ITYPE_EXT_UNUSED5 // FPU instructions require special handling + +#define ITYPE_3DNOW_OFFSET ITYPE_UNUSED1_OFFSET +#define ITYPE_MMX_OFFSET ITYPE_UNUSED2_OFFSET +#define ITYPE_SSE_OFFSET ITYPE_UNUSED3_OFFSET +#define ITYPE_SSE2_OFFSET ITYPE_UNUSED4_OFFSET +#define ITYPE_SSE3_OFFSET ITYPE_UNUSED5_OFFSET + +// +// Instruction types +// + +#define ITYPE_TYPE_MASK 0x7FFFFFFF +#define ITYPE_GROUP_MASK 0x7FFFFF00 + +typedef enum _INSTRUCTION_TYPE +{ + // ITYPE_EXEC group + ITYPE_EXEC = ITYPE_EXEC_OFFSET, + ITYPE_BRANCH, + ITYPE_BRANCHCC, // conditional (not necessarily just flags) + ITYPE_CALL, + ITYPE_CALLCC, // conditional (not necessarily just flags) + ITYPE_RET, + ITYPE_LOOPCC, + + // ITYPE_ARITH group + ITYPE_ARITH = ITYPE_ARITH_OFFSET, + ITYPE_XCHGADD, + ITYPE_ADD, + ITYPE_SUB, + ITYPE_MUL, + ITYPE_DIV, + ITYPE_INC, + ITYPE_DEC, + ITYPE_SHL, + ITYPE_SHR, + ITYPE_ROL, + ITYPE_ROR, + + // ITYPE_LOGIC group + ITYPE_LOGIC=ITYPE_LOGIC_OFFSET, + ITYPE_AND, + ITYPE_OR, + ITYPE_XOR, + ITYPE_NOT, + ITYPE_NEG, + + // ITYPE_STACK group + ITYPE_STACK=ITYPE_STACK_OFFSET, + ITYPE_PUSH, + ITYPE_POP, + ITYPE_PUSHA, + ITYPE_POPA, + ITYPE_PUSHF, + ITYPE_POPF, + ITYPE_ENTER, + ITYPE_LEAVE, + + // ITYPE_TESTCOND group + ITYPE_TESTCOND=ITYPE_TESTCOND_OFFSET, + ITYPE_TEST, + ITYPE_CMP, + + // ITYPE_LOAD group + ITYPE_LOAD=ITYPE_LOAD_OFFSET, + ITYPE_MOV, + ITYPE_MOVCC, // conditional + ITYPE_LEA, + ITYPE_XCHG, + ITYPE_XCHGCC, // conditional + + // ITYPE_ARRAY group + ITYPE_ARRAY=ITYPE_ARRAY_OFFSET, + ITYPE_STRCMP, + ITYPE_STRLOAD, + ITYPE_STRMOV, + ITYPE_STRSTOR, + ITYPE_XLAT, + + // ITYPE_BIT group + ITYPE_BIT=ITYPE_BIT_OFFSET, + ITYPE_BITTEST, + ITYPE_BITSET, + ITYPE_BITCLR, + + // ITYPE_FLAG group + // PF = parify flag + // ZF = zero flag + // OF = overflow flag + // DF = direction flag + // SF = sign flag + ITYPE_FLAG=ITYPE_FLAG_OFFSET, + // clear + ITYPE_CLEARCF, + ITYPE_CLEARZF, + ITYPE_CLEAROF, + ITYPE_CLEARDF, + ITYPE_CLEARSF, + ITYPE_CLEARPF, + // set + ITYPE_SETCF, + ITYPE_SETZF, + ITYPE_SETOF, + ITYPE_SETDF, + ITYPE_SETSF, + ITYPE_SETPF, + // toggle + ITYPE_TOGCF, + ITYPE_TOGZF, + ITYPE_TOGOF, + ITYPE_TOGDF, + ITYPE_TOGSF, + ITYPE_TOGPF, + + // ITYPE_FPU group + ITYPE_FPU=ITYPE_FPU_OFFSET, + ITYPE_FADD, + ITYPE_FSUB, + ITYPE_FMUL, + ITYPE_FDIV, + ITYPE_FCOMP, + ITYPE_FEXCH, + ITYPE_FLOAD, + ITYPE_FLOADENV, + ITYPE_FSTORE, + ITYPE_FSTOREENV, + ITYPE_FSAVE, + ITYPE_FRESTORE, + ITYPE_FMOVCC, + + ITYPE_UNUSED1=ITYPE_UNUSED1_OFFSET, + ITYPE_UNUSED2=ITYPE_UNUSED2_OFFSET, + ITYPE_UNUSED3=ITYPE_UNUSED3_OFFSET, + + // ITYPE_MMX group + ITYPE_MMX=ITYPE_MMX_OFFSET, + ITYPE_MMX_MOV, + ITYPE_MMX_ADD, + ITYPE_MMX_SUB, + ITYPE_MMX_MUL, + ITYPE_MMX_DIV, + ITYPE_MMX_AND, + ITYPE_MMX_OR, + ITYPE_MMX_XOR, + ITYPE_MMX_CMP, + + // ITYPE_SSE group + ITYPE_SSE=ITYPE_SSE_OFFSET, + ITYPE_SSE_MOV, + ITYPE_SSE_ADD, + ITYPE_SSE_SUB, + ITYPE_SSE_MUL, + ITYPE_SSE_DIV, + ITYPE_SSE_AND, + ITYPE_SSE_OR, + ITYPE_SSE_XOR, + ITYPE_SSE_CMP, + + // ITYPE_SSE2 group + ITYPE_SSE2=ITYPE_SSE2_OFFSET, + ITYPE_SSE2_MOV, + ITYPE_SSE2_ADD, + ITYPE_SSE2_SUB, + ITYPE_SSE2_MUL, + ITYPE_SSE2_DIV, + ITYPE_SSE2_AND, + ITYPE_SSE2_OR, + ITYPE_SSE2_XOR, + ITYPE_SSE2_CMP, + + // ITYPE_SSE3 group + ITYPE_SSE3=ITYPE_SSE3_OFFSET, + ITYPE_SSE3_MOV, + ITYPE_SSE3_ADD, + ITYPE_SSE3_SUB, + ITYPE_SSE3_MUL, + ITYPE_SSE3_DIV, + ITYPE_SSE3_AND, + ITYPE_SSE3_OR, + ITYPE_SSE3_XOR, + ITYPE_SSE3_CMP, + + // ITYPE_3DNOW group + ITYPE_3DNOW=ITYPE_3DNOW_OFFSET, + ITYPE_3DNOW_ADD, + ITYPE_3DNOW_SUB, + ITYPE_3DNOW_MUL, + ITYPE_3DNOW_DIV, + ITYPE_3DNOW_CMP, + ITYPE_3DNOW_XCHG, + + // ITYPE_TRAP + ITYPE_TRAPS=ITYPE_TRAPS_OFFSET, + ITYPE_TRAP, // generate trap + ITYPE_TRAPCC, // conditional trap gen + ITYPE_TRAPRET, // return from trap + ITYPE_BOUNDS, // gen bounds trap + ITYPE_DEBUG, // gen breakpoint trap + ITYPE_TRACE, // gen single step trap + ITYPE_INVALID, // gen invalid instruction + ITYPE_OFLOW, // gen overflow trap + + // ITYPE_SYSTEM group + ITYPE_SYSTEM=ITYPE_SYSTEM_OFFSET, + ITYPE_HALT, // halt machine + ITYPE_IN, // input form port + ITYPE_OUT, // output to port + ITYPE_CPUID, // identify cpu + ITYPE_SETIF, // allow interrupts + ITYPE_CLEARIF, // block interrupts + ITYPE_SYSCALL, + ITYPE_SYSCALLRET, + + // ITYPE_OTHER group + ITYPE_OTHER = ITYPE_OTHER_OFFSET, + ITYPE_NOP, + ITYPE_BCDCONV, // convert to/from BCD + ITYPE_SZCONV // convert size of operand +} INSTRUCTION_TYPE; + +// +// Operand flags +// + +// Type = bits 0-6 (these are mutually exclusive -- bits 0-6 will always be a power of 2)) +#define OPTYPE_NONE 0x00 +#define OPTYPE_IMM 0x01 // immediate value +#define OPTYPE_OFFSET 0x02 // relative offset +#define OPTYPE_FLOAT 0x03 // floating point +#define OPTYPE_BCD 0x04 +#define OPTYPE_STRING 0x05 +#define OPTYPE_SPECIAL 0x06 +#define OPTYPE_MASK 0x7F + +// Flags = bits 7-23 (these can be combinations) +// These are used in the X86 opcode table +#define OP_REG (1<<7) // 0x80 +#define OP_SIGNED (1<<8) +#define OP_SYS (1<<9) // parameter is an index into some system structure +#define OP_CONDR (1<<10) +#define OP_CONDW (1<<11) +#define OP_UNUSED (1<<12) +#define OP_SRC (1<<13) // operand is source operand +#define OP_DST (1<<14) // operand is destination operand +#define OP_EXEC (1<<15) // operand is executed + +#define OP_CONDE OP_CONDR +#define OP_COND_EXEC (OP_CONDE|OP_EXEC) // executed only if the pre-conditions are met +#define OP_COND_SRC (OP_CONDR|OP_SRC) // set only if pre-conditions are met +#define OP_COND_DST (OP_CONDW|OP_DST) // set only if pre-conditions are met +#define OP_COND (OP_CONDR|OP_CONDW) + +// Bits 16-31 are available for use outside of the opcode table, but they can only +// be used in INSTRUCTION_OPERAND.Flags, they may conflit with the architecture specific +// operands. For example, bits 16-31 are used in X86 for AMODE_* and OPTYPE_* +#define OP_ADDRESS (1<<16) +#define OP_LOCAL (1<<17) +#define OP_PARAM (1<<18) +#define OP_GLOBAL (1<<19) +#define OP_FAR (1<<20) +#define OP_IPREL (1<<21) + +// +// X86-specific flags (bits 27-31) +// +#define OP_MSR (OP_SYS|OP_UNUSED) + +// +// Other architecture flags +// +#define OP_DELAY OP_UNUSED // delayed instruction (e.g., delayed branch that executes after the next instruction) + +///////////////////////////////////////////////////////////////////// +// Architectures +///////////////////////////////////////////////////////////////////// + +typedef enum _ARCHITECTURE_TYPE +{ + ARCH_UNKNOWN=0, + + // x86-based + ARCH_X86, // 32-bit x86 + ARCH_X86_16, // 16-bit x86 + ARCH_X64, // AMD64 and Intel EMD64 + + // everything else + ARCH_ALPHA, + ARCH_ARM, + ARCH_DOTNET, + ARCH_EFI, + ARCH_IA64, + ARCH_M68K, + ARCH_MIPS, + ARCH_PPC, + ARCH_SH3, + ARCH_SH4, + ARCH_SPARC, + ARCH_THUMB + +} ARCHITECTURE_TYPE; + +struct _INSTRUCTION; + +typedef BOOL (*INIT_INSTRUCTION)(struct _INSTRUCTION *Instruction); +typedef void (*DUMP_INSTRUCTION)(struct _INSTRUCTION *Instruction, BOOL ShowBytes, BOOL Verbose); +typedef BOOL (*GET_INSTRUCTION)(struct _INSTRUCTION *Instruction, U8 *Address, U32 Flags); +typedef U8 *(*FIND_FUNCTION_BY_PROLOGUE)(struct _INSTRUCTION *Instruction, U8 *StartAddress, U8 *EndAddress, U32 Flags); + +typedef struct _ARCHITECTURE_FORMAT_FUNCTIONS +{ + INIT_INSTRUCTION InitInstruction; + DUMP_INSTRUCTION DumpInstruction; + GET_INSTRUCTION GetInstruction; + FIND_FUNCTION_BY_PROLOGUE FindFunctionByPrologue; +} ARCHITECTURE_FORMAT_FUNCTIONS; + +typedef struct _ARCHITECTURE_FORMAT +{ + ARCHITECTURE_TYPE Type; + ARCHITECTURE_FORMAT_FUNCTIONS *Functions; +} ARCHITECTURE_FORMAT; + +#define DISASSEMBLER_INITIALIZED 0x1234566F +#define INSTRUCTION_INITIALIZED 0x1234567F + +#include "disasm_x86.h" + +typedef struct DECLSPEC_ALIGN(16) _S128 +{ + U64 Low; + S64 High; +} S128; +typedef struct DECLSPEC_ALIGN(16) _U128 +{ + U64 Low; + U64 High; +} U128; + +typedef struct _INSTRUCTION_OPERAND +{ + U32 Flags; + U8 Type : 6; + U8 Unused : 2; + U16 Length; + + + // If non-NULL, this indicates the target address of the instruction (e.g., a branch or + // a displacement with no base register). However, this address is only reliable if the + // image is mapped correctly (e.g., the executable is mapped as an image and fixups have + // been applied if it is not at its preferred image base). + // + // If disassembling a 16-bit DOS application, TargetAddress is in the context of + // X86Instruction->Segment. For example, if TargetAddress is the address of a code branch, + // it is in the CS segment (unless X86Instruction->HasSegmentOverridePrefix is set). If + // TargetAddress is a data pointer, it is in the DS segment (unless + // X86Instruction->HasSegmentOverridePrefix is set) + U64 TargetAddress; + U32 Register; + + union + { + // All 8/16/32-bit operands are extended to 64-bits automatically + // If you want to downcast, check whether Flags & OP_SIGNED is set + // Like this: + // U32 GetOperand32(OPERAND *Operand) + // { + // if (Operand->Flags & OP_SIGNED) return (S32)Operand->Value_S64; + // else return (U32)Operand->Value_U64; + //} + U64 Value_U64; + S64 Value_S64; + U128 Value_U128; + U128 Float128; + U8 Float80[80]; + U8 BCD[10]; + }; +} INSTRUCTION_OPERAND; + +typedef struct _INSTRUCTION +{ + U32 Initialized; + struct _DISASSEMBLER *Disassembler; + + char String[MAX_OPCODE_DESCRIPTION]; + U8 StringIndex; + U64 VirtualAddressDelta; + + U32 Groups; // ITYPE_EXEC, ITYPE_ARITH, etc. -- NOTE groups can be OR'd together + INSTRUCTION_TYPE Type; // ITYPE_ADD, ITYPE_RET, etc. -- NOTE there is only one possible type + + U8 *Address; + U8 *OpcodeAddress; + U32 Length; + + U8 Prefixes[MAX_PREFIX_LENGTH]; + U32 PrefixCount; + + U8 LastOpcode; // last byte of opcode + U8 OpcodeBytes[MAX_OPCODE_LENGTH]; + U32 OpcodeLength; // excludes any operands and prefixes + + INSTRUCTION_OPERAND Operands[MAX_OPERAND_COUNT]; + U32 OperandCount; + + X86_INSTRUCTION X86; + + DATA_REFERENCE DataSrc; + DATA_REFERENCE DataDst; + CODE_BRANCH CodeBranch; + + // Direction depends on which direction the stack grows + // For example, on x86 a push results in StackChange < 0 since the stack grows down + // This is only relevant if (Group & ITYPE_STACK) is true + // + // If Groups & ITYPE_STACK is set but StackChange = 0, it means that the change + // couldn't be determined (non-constant) + LONG StackChange; + + // Used to assist in debugging + // If set, the current instruction is doing something that requires special handling + // For example, popf can cause tracing to be disabled + + U8 StringAligned : 1; // internal only + U8 NeedsEmulation : 1; // instruction does something that re + U8 Repeat : 1; // instruction repeats until some condition is met (e.g., REP prefix on X86) + U8 ErrorOccurred : 1; // set if instruction is invalid + U8 AnomalyOccurred : 1; // set if instruction is anomalous + U8 LastInstruction : 1; // tells the iterator callback it is the last instruction + U8 CodeBlockFirst: 1; + U8 CodeBlockLast : 1; +} INSTRUCTION; + +typedef struct _DISASSEMBLER +{ + U32 Initialized; + ARCHITECTURE_TYPE ArchType; + ARCHITECTURE_FORMAT_FUNCTIONS *Functions; + INSTRUCTION Instruction; + U32 Stage1Count; // GetInstruction called + U32 Stage2Count; // Opcode fully decoded + U32 Stage3CountNoDecode; // made it through all checks when DISASM_DECODE is not set + U32 Stage3CountWithDecode; // made it through all checks when DISASM_DECODE is set +} DISASSEMBLER; + +#define DISASM_DISASSEMBLE (1<<1) +#define DISASM_DECODE (1<<2) +#define DISASM_SUPPRESSERRORS (1<<3) +#define DISASM_SHOWFLAGS (1<<4) +#define DISASM_ALIGNOUTPUT (1<<5) +#define DISASM_DISASSEMBLE_MASK (DISASM_ALIGNOUTPUT|DISASM_SHOWBYTES|DISASM_DISASSEMBLE) + +BOOL InitDisassembler(DISASSEMBLER *Disassembler, ARCHITECTURE_TYPE Architecture); +void CloseDisassembler(DISASSEMBLER *Disassembler); +INSTRUCTION *GetInstruction(DISASSEMBLER *Disassembler, U64 VirtualAddress, U8 *Address, U32 Flags); + +#ifdef __cplusplus +} +#endif +#endif // DISASM_H diff --git a/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86.c b/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86.c new file mode 100644 index 0000000000..9a16abe4a1 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86.c @@ -0,0 +1,4664 @@ +// Copyright (C) 2004, Matt Conover (mconover@gmail.com) +#undef NDEBUG +#include +#include "disasm.h" +#include "cpu.h" + +// Since addresses are internally represented as 64-bit, we need to specially handle +// cases where IP + Displacement wraps around for 16-bit/32-bit operand size +// Otherwise, ignorethe possibility of wraparounds +#define SUPPORT_WRAPAROUND + +#ifdef NO_SANITY_CHECKS +#undef NDEBUG +#undef DEBUG_DISASM +#undef assert +#define assert(x) +#endif + +#ifdef DEBUG_DISASM +#define DISASM_OUTPUT(x) printf x +#else +#define DISASM_OUTPUT(x) +#endif + +#include "disasm_x86_tables.h" + +#ifdef _WIN64 +#pragma warning(disable:4311 4312) +#endif + +#pragma warning(disable:4702) + +//////////////////////////////////////////////////////////////////////// +// Internal macros +//////////////////////////////////////////////////////////////////////// + +#define VIRTUAL_ADDRESS ((U64)Instruction->Address + Instruction->VirtualAddressDelta) + +#define AMD64_DIFF (AMD64_8BIT_OFFSET-X86_8BIT_OFFSET) +#define IS_AMD64() (INS_ARCH_TYPE(Instruction) == ARCH_X64) +#define IS_X86_32() (INS_ARCH_TYPE(Instruction) == ARCH_X86) +#define IS_X86_16() (INS_ARCH_TYPE(Instruction) == ARCH_X86_16) + +#define X86_BOUND 0x62 +#define X86_PUSH_REG 0x50 +#define X86_PUSH_CS 0x0e +#define X86_PUSH_DS 0x1e +#define X86_PUSH_SS 0x16 +#define X86_PUSH_ES 0x06 +#define X86_PUSH_FS 0xa0 +#define X86_PUSH_GS 0xa8 +#define X86_PUSH_U8 0x6a +#define X86_PUSH_U32 0x68 +#define X86_POP_DS 0x1f +#define X86_POP_ES 0x07 +#define X86_POP_SS 0x17 +#define X86_POP_FS 0xa1 +#define X86_POP_GS 0xa9 +#define X86_POP_REG 0x58 + +#define OPCSTR Instruction->String+Instruction->StringIndex +#define APPEND Instruction->StringIndex += (U8)_snprintf +#define APPENDPAD(x) \ +{ \ + if (Instruction->StringAligned) \ + { \ + if (Instruction->StringIndex > x) assert(0); \ + while (x != Instruction->StringIndex) APPENDB(' '); \ + } \ + else if (Instruction->StringIndex) \ + { \ + APPENDB(' '); \ + } \ +} + +#define APPENDB(a) Instruction->String[Instruction->StringIndex++] = a +#define APPENDS(a) APPEND(OPCSTR, SIZE_LEFT, a); + +#define SIZE_LEFT (MAX_OPCODE_DESCRIPTION-1 > Instruction->StringIndex ? MAX_OPCODE_DESCRIPTION-Instruction->StringIndex : 0) + +// If an address size prefix is used for an instruction that doesn't make sense, restore it +// to the default + +#define SANITY_CHECK_OPERAND_SIZE() \ +{ \ + if (!Instruction->AnomalyOccurred && X86Instruction->HasOperandSizePrefix) \ + { \ + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Unexpected operand size prefix\n", VIRTUAL_ADDRESS); \ + Instruction->AnomalyOccurred = TRUE; \ + X86Instruction->HasOperandSizePrefix = FALSE; \ + switch (X86Instruction->OperandSize) \ + { \ + case 4: X86Instruction->OperandSize = 2; break; \ + case 2: X86Instruction->OperandSize = 4; break; \ + default: assert(0); \ + } \ + } \ +} + +#define SANITY_CHECK_ADDRESS_SIZE() \ +{ \ + if (!Instruction->AnomalyOccurred && X86Instruction->HasAddressSizePrefix) \ + { \ + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Unexpected address size prefix\n", VIRTUAL_ADDRESS); \ + Instruction->AnomalyOccurred = TRUE; \ + } \ + X86Instruction->HasAddressSizePrefix = FALSE; \ + switch (INS_ARCH_TYPE(Instruction)) \ + { \ + case ARCH_X64: X86Instruction->AddressSize = 8; break; \ + case ARCH_X86: X86Instruction->AddressSize = 4; break; \ + case ARCH_X86_16: X86Instruction->AddressSize = 2; break; \ + } \ +} + +#define SANITY_CHECK_SEGMENT_OVERRIDE() \ + if (!Instruction->AnomalyOccurred && X86Instruction->HasSegmentOverridePrefix) \ + { \ + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Unexpected segment override\n", VIRTUAL_ADDRESS); \ + Instruction->AnomalyOccurred = TRUE; \ + } + +#define INSTR_INC(size) \ +{ \ + Instruction->Length += size; \ + Address += size; \ +} + +#define X86_SET_TARGET() \ +{ \ + if (X86Instruction->HasSelector) \ + { \ + if (!Instruction->AnomalyOccurred) \ + { \ + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: unexpected segment 0x%02X\n", VIRTUAL_ADDRESS, X86Instruction->Selector); \ + Instruction->AnomalyOccurred = TRUE; \ + } \ + } \ + else \ + { \ + switch (X86Instruction->Segment) \ + { \ + case SEG_CS: \ + case SEG_DS: \ + case SEG_SS: \ + case SEG_ES: \ + assert(!X86Instruction->HasSelector); \ + Operand->TargetAddress = (U64)X86Instruction->Displacement; \ + /* assert(!GetAbsoluteAddressFromSegment((BYTE)X86Instruction->Segment, (DWORD)X86Instruction->Displacement) || GetAbsoluteAddressFromSegment(X86Instruction->Segment, (DWORD)X86Instruction->Displacement) == Operand->TargetAddress); */ \ + break; \ + case SEG_FS: \ + case SEG_GS: \ + assert(!X86Instruction->HasSelector); \ + Operand->TargetAddress = (U64)GetAbsoluteAddressFromSegment((BYTE)X86Instruction->Segment, (DWORD)X86Instruction->Displacement); \ + break; \ + default: \ + assert(0); /* shouldn't be possible */ \ + break; \ + } \ + } \ +} + +#define X86_SET_SEG(reg) \ +{ \ + if (!X86Instruction->HasSegmentOverridePrefix && (reg == REG_EBP || reg == REG_ESP)) \ + { \ + assert(!X86Instruction->HasSelector); \ + X86Instruction->Segment = SEG_SS; \ + } \ +} + +#define X86_SET_ADDR() \ +{ \ + if (Operand->Flags & OP_DST) \ + { \ + assert(!X86Instruction->HasDstAddressing); \ + X86Instruction->HasDstAddressing = TRUE; \ + X86Instruction->DstOpIndex[X86Instruction->DstOpCount] = (U8)OperandIndex; \ + X86Instruction->DstOpCount++; \ + X86Instruction->DstAddressIndex = (U8)OperandIndex; \ + } \ + if (Operand->Flags & OP_SRC) \ + { \ + if (Instruction->Type != ITYPE_STRCMP) assert(!X86Instruction->HasSrcAddressing); \ + X86Instruction->HasSrcAddressing = TRUE; \ + X86Instruction->SrcOpIndex[X86Instruction->SrcOpCount] = (U8)OperandIndex; \ + X86Instruction->SrcOpCount++; \ + X86Instruction->SrcAddressIndex = (U8)OperandIndex; \ + } \ +} + +#define X86_SET_REG(reg) \ +{ \ + if (Operand->Flags & OP_DST) \ + { \ + X86Instruction->DstOpIndex[X86Instruction->DstOpCount] = (U8)OperandIndex; \ + X86Instruction->DstOpCount++; \ + assert(OperandIndex < 2); \ + if (Operand->Length > 1 && reg == REG_ESP) Instruction->Groups |= ITYPE_STACK; \ + } \ + if (Operand->Flags & OP_SRC) \ + { \ + X86Instruction->SrcOpIndex[X86Instruction->SrcOpCount] = (U8)OperandIndex; \ + X86Instruction->SrcOpCount++; \ + } \ +} + +#define CHECK_AMD64_REG() { if (IS_AMD64()) Operand->Register += AMD64_DIFF; } + +//////////////////////////////////////////////////////////////////////// +// Internal structures/variables +//////////////////////////////////////////////////////////////////////// + +ARCHITECTURE_FORMAT_FUNCTIONS X86 = +{ + X86_InitInstruction, + NULL, + X86_GetInstruction, + X86_FindFunctionByPrologue +}; + +char *X86_Registers[0xE0] = +{ + // Segments + "es", // 0x00 + "cs", // 0x01 + "ss", // 0x02 + "ds", // 0x03 + "fs", // 0x04 + "gs", // 0x05 + "flags", // 0x06 + "eflags", // 0x07 + "rflags", // 0x08 + "ip+ilen", // 0x09 + "eip+ilen", // 0x0A + "rip+ilen", // 0x0B + NULL, // 0x0C + NULL, // 0x0D + NULL, // 0x0E + NULL, // 0x0F + + // Test + "tr0", // 0x10 + "tr1", // 0x11 + "tr2", // 0x12 + "tr3", // 0x13 + "tr4", // 0x14 + "tr5", // 0x15 + "tr6", // 0x16 + "tr7", // 0x17 + "tr8", // 0x18 + "tr9", // 0x19 + "tr10", // 0x1A + "tr11", // 0x1B + "tr12", // 0x1C + "tr13", // 0x1D + "tr14", // 0x1E + "tr15", // 0x1F + + // Control + "cr0", // 0x20 + "cr1", // 0x21 + "cr2", // 0x22 + "cr3", // 0x23 + "cr4", // 0x24 + "cr5", // 0x25 + "cr6", // 0x26 + "cr7", // 0x27 + "cr8", // 0x18 + "cr9", // 0x19 + "cr10", // 0x1A + "cr11", // 0x1B + "cr12", // 0x1C + "cr13", // 0x1D + "cr14", // 0x1E + "cr15", // 0x1F + + // Debug + "dr0", // 0x30 + "dr1", // 0x31 + "dr2", // 0x32 + "dr3", // 0x33 + "dr4", // 0x34 + "dr5", // 0x35 + "dr6", // 0x36 + "dr7", // 0x37 + "dr8", // 0x38 + "dr9", // 0x39 + "dr10", // 0x3A + "dr11", // 0x3B + "dr12", // 0x3C + "dr13", // 0x3D + "dr14", // 0x3E + "dr15", // 0x3F + + // FPU + "st(0)", // 0x40 + "st(1)", // 0x41 + "st(2)", // 0x42 + "st(3)", // 0x43 + "st(4)", // 0x44 + "st(5)", // 0x45 + "st(6)", // 0x46 + "st(7)", // 0x47 + NULL, // 0x48 + NULL, // 0x49 + NULL, // 0x4A + NULL, // 0x4B + NULL, // 0x4C + NULL, // 0x4D + NULL, // 0x4E + NULL, // 0x4F + + // MMX + "mm0", // 0x50 + "mm1", // + "mm2", + "mm3", + "mm4", + "mm5", + "mm6", + "mm7", + NULL, // 0x58 + NULL, // 0x59 + NULL, // 0x5A + NULL, // 0x5B + NULL, // 0x5C + NULL, // 0x5D + NULL, // 0x5E + NULL, // 0x5F + + // XMM + "xmm0", // 0x60 + "xmm1", // 0x61 + "xmm2", // 0x62 + "xmm3", // 0x63 + "xmm4", // 0x64 + "xmm5", // 0x65 + "xmm6", // 0x66 + "xmm7", // 0x67 + "xmm8", // 0x68 + "xmm9", // 0x69 + "xmm10", // 0x6a + "xmm11", // 0x6b + "xmm12", // 0x6c + "xmm13", // 0x6d + "xmm14", // 0x6e + "xmm15", // 0x6f + + // 8-bit + "al", // 0x70 + "cl", // 0x71 + "dl", // 0x72 + "bl", // 0x73 + "ah", // 0x74 + "ch", // 0x75 + "dh", // 0x76 + "bh", // 0x77 + NULL, // 0x78 + NULL, // 0x79 + NULL, // 0x7A + NULL, // 0x7B + NULL, // 0x7C + NULL, // 0x7D + NULL, // 0x7E + NULL, // 0x7F + + // 16-bit + "ax", // 0x80 + "cx", // 0x81 + "dx", // 0x82 + "bx", // 0x83 + "sp", // 0x84 + "bp", // 0x85 + "si", // 0x86 + "di", // 0x87 + NULL, // 0x88 + NULL, // 0x89 + NULL, // 0x8A + NULL, // 0x8B + NULL, // 0x8C + NULL, // 0x8D + NULL, // 0x8E + NULL, // 0x8F + + // 32-bit + "eax", // 0x90 + "ecx", // 0x91 + "edx", // 0x92 + "ebx", // 0x93 + "esp", // 0x94 + "ebp", // 0x95 + "esi", // 0x96 + "edi", // 0x97 + NULL, // 0x98 + NULL, // 0x99 + NULL, // 0x9A + NULL, // 0x9B + NULL, // 0x9C + NULL, // 0x9D + NULL, // 0x9E + NULL, // 0x9F + + // X86-64 8-bit register + "al", // 0xA0 + "cl", // 0xA1 + "dl", // 0xA2 + "bl", // 0xA3 + "spl", // 0xA4 + "bpl", // 0xA5 + "sil", // 0xA6 + "dil", // 0xA7 + "r8b", // 0xA8 + "r9b", // 0xA9 + "r10b", // 0xAA + "r11b", // 0xAB + "r12b", // 0xAC + "r13b", // 0xAD + "r14b", // 0xAE + "r15b", // 0xAF + + // X86-64 16-bit register + "ax", // 0xB0 + "cx", // 0xB1 + "dx", // 0xB2 + "bx", // 0xB3 + "sp", // 0xB4 + "bp", // 0xB5 + "si", // 0xB6 + "di", // 0xB7 + "r8w", // 0xB8 + "r9w", // 0xB9 + "r10w", // 0xBA + "r11w", // 0xBB + "r12w", // 0xBC + "r13w", // 0xBD + "r14w", // 0xBE + "r15w", // 0xBF + + // X86-64 32-bit register + "eax", // 0xC0 + "ecx", // 0xC1 + "edx", // 0xC2 + "ebx", // 0xC3 + "esp", // 0xC4 + "ebp", // 0xC5 + "esi", // 0xC6 + "edi", // 0xC7 + "r8d", // 0xC8 + "r9d", // 0xC9 + "r10d", // 0xCA + "r11d", // 0xCB + "r12d", // 0xCC + "r13d", // 0xCD + "r14d", // 0xCE + "r15d", // 0xCF + + // X86-64 64-bit register + "rax", // 0xD0 + "rcx", // 0xD1 + "rdx", // 0xD2 + "rbx", // 0xD3 + "rsp", // 0xD4 + "rbp", // 0xD5 + "rsi", // 0xD6 + "rdi", // 0xD7 + "r8", // 0xD8 + "r9", // 0xD9 + "r10", // 0xDA + "r11", // 0xDB + "r12", // 0xDC + "r13", // 0xDD + "r14", // 0xDE + "r15" // 0xDF +}; + +void OutputBounds(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputGeneral(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputDescriptor(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputSegOffset(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputPackedReal(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputPackedBCD(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputScalarReal(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputScalarGeneral(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputFPUEnvironment(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputFPUState(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +void OutputCPUState(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); + +typedef void (*OUTPUT_OPTYPE)(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex); +#define OPTYPE_SHIFT 24 +#define MAX_OPTYPE_INDEX 26 +OUTPUT_OPTYPE OptypeHandlers[] = +{ + NULL, + OutputBounds, // 01 OPTYPE_a + OutputGeneral, // 02 OPTYPE_b + OutputGeneral, // 03 OPTYPE_d + OutputSegOffset, // 04 OPTYPE_p + OutputGeneral, // 05 OPTYPE_q + OutputDescriptor, // 06 OPTYPE_dt + OutputGeneral, // 07 OPTYPE_v + OutputGeneral, // 08 OPTYPE_w + OutputPackedReal, // 09 OPTYPE_ps + OutputPackedReal, // 0A OPTYPE_pd + OutputPackedBCD, // 0B OPTYPE_pb + OutputScalarReal, // 0C OPTYPE_ss + OutputScalarReal, // 0D OPTYPE_sd + OutputScalarReal, // 0E OPTYPE_se + OutputFPUEnvironment, // 0F OPTYPE_fev + OutputFPUState, // 10 OPTYPE_fst1 + OutputFPUState, // 11 OPTYPE_fst2 + OutputGeneral, // 12 OPTYPE_z + OutputGeneral, // 13 OPTYPE_o + OutputGeneral, // 14 OPTYPE_dq + OutputGeneral, // 15 OPTYPE_mw + OutputScalarGeneral, // 16 OPTYPE_sso + OutputScalarGeneral, // 17 OPTYPE_sdo + OutputCPUState, // 18 OPTYPE_cpu + OutputGeneral, // 19 OPTYPE_lea +}; + +#define OPTYPE_a 0x01000000 +#define OPTYPE_b 0x02000000 +#define OPTYPE_d 0x03000000 +#define OPTYPE_p 0x04000000 +#define OPTYPE_q 0x05000000 +#define OPTYPE_dt 0x06000000 +#define OPTYPE_v 0x07000000 +#define OPTYPE_w 0x08000000 +#define OPTYPE_ps 0x09000000 // packed 128-bit single real +#define OPTYPE_pd 0x0A000000 // packed 128-bit double real +#define OPTYPE_pb 0x0B000000 // packed BCD (10 bytes, 18-bit precision) +#define OPTYPE_ss 0x0C000000 // scalar single real +#define OPTYPE_sd 0x0D000000 // scalar double real +#define OPTYPE_se 0x0E000000 // scalar extended real +#define OPTYPE_fev 0x0F000000 // FPU environment (28 bytes if 32-bit modes, 14 bytes in 16-bit mode) +#define OPTYPE_fst1 0x10000000 // FPU state (108 bytes in 32-bit modes, 94 bytes in 16-bit real mode) +#define OPTYPE_fst2 0x11000000 // FPU/MMX/XMM/MXCSR state (512 bytes) +#define OPTYPE_z 0x12000000 +#define OPTYPE_o 0x13000000 +#define OPTYPE_dq 0x14000000 // OPTYPE_d or OPTYPE_o +#define OPTYPE_mw 0x15000000 // word if memory, register size otherwise +#define OPTYPE_sso 0x16000000 // OPTYPE_ss or OPTYPE_o +#define OPTYPE_sdo 0x17000000 // OPTYPE_ss or OPTYPE_o +#define OPTYPE_cpu 0x18000000 // pointer to CPU state structure +#define OPTYPE_lea 0x19000000 // size set by other operand + +//////////////////////////////////////////////////////////////////////// +// Internal functions +//////////////////////////////////////////////////////////////////////// + +#ifdef TEST_DISASM // TODO: remove +U32 X86_GetLength(INSTRUCTION *Instruction, U8 *Address); +#endif + +INTERNAL BOOL IsValidLockPrefix(X86_INSTRUCTION *Instruction, U8 Opcode, U32 OpcodeLength, U8 Group, U8 OpcodeExtension); +INTERNAL U8 *SetOperands(INSTRUCTION *Instruction, U8 *Address, U32 Flags); +INTERNAL U8 *SetModRM32(INSTRUCTION *Instruction, U8 *Address, INSTRUCTION_OPERAND *Operand, U32 OperandIndex, BOOL SuppressErrors); +INTERNAL U8 *SetModRM16(INSTRUCTION *Instruction, U8 *Address, INSTRUCTION_OPERAND *Operand, U32 OperandIndex, BOOL SuppressErrors); +INTERNAL U8 *SetSIB(INSTRUCTION *Instruction, U8 *Address, INSTRUCTION_OPERAND *Operand, U32 OperandIndex, BOOL SuppressErrors); +INTERNAL U64 ApplyDisplacement(U64 Address, INSTRUCTION *Instruction); + +////////////////////////////////////////////////////////// +// Instruction setup +////////////////////////////////////////////////////////// + +#define APPLY_OFFSET(addr) \ +{ \ + switch (X86Instruction->OperandSize) \ + { \ + case 8: addr = ((U64)(addr + Instruction->VirtualAddressDelta)); break; \ + case 4: addr = (U64)((U32)(addr + Instruction->VirtualAddressDelta)); break; \ + case 2: addr = (U64)((U8)(addr + Instruction->VirtualAddressDelta)); break; \ + default: assert(0); break; \ + } \ +} + +BOOL X86_InitInstruction(INSTRUCTION *Instruction) +{ + X86_INSTRUCTION *X86Instruction; +#ifdef NO_SANITY_CHECKS + assert(0); // be sure assertions are disabled +#endif + X86Instruction = &Instruction->X86; + memset(X86Instruction, 0, sizeof(X86_INSTRUCTION)); + + switch (INS_ARCH_TYPE(Instruction)) + { + case ARCH_X64: + X86Instruction->AddressSize = 8; + X86Instruction->OperandSize = 4; + break; + case ARCH_X86: + X86Instruction->AddressSize = 4; + X86Instruction->OperandSize = 4; + break; + case ARCH_X86_16: + X86Instruction->AddressSize = 2; + X86Instruction->OperandSize = 2; + break; + default: + assert(0); + return FALSE; + } + X86Instruction->Instruction = Instruction; + X86Instruction->Segment = SEG_DS; + return TRUE; +} + +//////////////////////////////////////////////////////////// +// Formatting +// You can change these to whatever you prefer +//////////////////////////////////////////////////////////// + +#define X86_WRITE_OPFLAGS() \ + if (Flags & DISASM_SHOWFLAGS) \ + { \ + APPENDB('{'); \ + assert(Operand->Flags & (OP_EXEC|OP_SRC|OP_DST)); \ + if (Operand->Flags & OP_IPREL) APPENDB('r'); \ + if (Operand->Flags & OP_FAR) APPENDB('f'); \ + if (Operand->Flags & OP_CONDR) APPENDB('c'); \ + if (Operand->Flags & OP_EXEC) APPENDB('X'); \ + else if (Operand->Flags & OP_SRC) APPENDB('R'); \ + if (Operand->Flags & OP_CONDW) APPENDB('c'); \ + if (Operand->Flags & OP_DST) APPENDB('W'); \ + if (Operand->Flags & OP_SYS) APPENDB('S'); \ + if (Operand->Flags & OP_ADDRESS) APPENDB('A'); \ + if (Operand->Flags & OP_PARAM) APPENDB('P'); \ + if (Operand->Flags & OP_LOCAL) APPENDB('L'); \ + if (Operand->Flags & OP_GLOBAL) APPENDB('G'); \ + APPENDB('}'); \ + } + +#define X86_WRITE_IMMEDIATE() \ +{ \ + switch (Operand->Length) \ + { \ + case 8: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%02I64X=", Operand->Value_U64); \ + if (Operand->Value_S64 >= 0 || !(Operand->Flags & OP_SIGNED)) APPEND(OPCSTR, SIZE_LEFT, "%I64u", Operand->Value_U64); \ + /*else APPEND(OPCSTR, SIZE_LEFT, "-0x%02I64X=%I64d", -Operand->Value_S64, Operand->Value_S64);*/ \ + else APPEND(OPCSTR, SIZE_LEFT, "%I64d", Operand->Value_S64); \ + break; \ + case 4: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%02lX=", (U32)Operand->Value_U64); \ + if (Operand->Value_S64 >= 0 || !(Operand->Flags & OP_SIGNED)) APPEND(OPCSTR, SIZE_LEFT, "%lu", (U32)Operand->Value_U64); \ + /*else APPEND(OPCSTR, SIZE_LEFT, "-0x%02lX=%ld", (U32)-Operand->Value_S64, (S32)Operand->Value_S64);*/ \ + else APPEND(OPCSTR, SIZE_LEFT, "%ld", (S32)Operand->Value_S64); \ + break; \ + case 2: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%02X=", (U16)Operand->Value_U64); \ + if (Operand->Value_S64 >= 0 || !(Operand->Flags & OP_SIGNED)) APPEND(OPCSTR, SIZE_LEFT, "%u", (U16)Operand->Value_U64); \ + /*else APPEND(OPCSTR, SIZE_LEFT, "-0x%02X=%d", (U16)-Operand->Value_S64, (S16)Operand->Value_S64);*/ \ + else APPEND(OPCSTR, SIZE_LEFT, "%d", (S16)Operand->Value_S64); \ + break; \ + case 1: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%02X=", (U8)Operand->Value_U64); \ + if (Operand->Value_S64 >= 0 || !(Operand->Flags & OP_SIGNED)) APPEND(OPCSTR, SIZE_LEFT, "%u", (U8)Operand->Value_U64); \ + /*else APPEND(OPCSTR, SIZE_LEFT, "-0x%02X=%d", (U8)-Operand->Value_S64, (S8)Operand->Value_S64);*/ \ + else APPEND(OPCSTR, SIZE_LEFT, "%d", (S8)Operand->Value_S64); \ + break; \ + default: assert(0); break; \ + } \ +} + +#define X86_WRITE_ABSOLUTE_DISPLACEMENT() \ +{ \ + switch (X86Instruction->AddressSize) \ + { \ + case 8: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%04I64X", X86Instruction->Displacement); \ + break; \ + case 4: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%04lX", (U32)X86Instruction->Displacement); \ + break; \ + case 2: \ + APPEND(OPCSTR, SIZE_LEFT, "0x%04X", (U16)X86Instruction->Displacement); \ + break; \ + default: assert(0); break; \ + } \ +} + +#define X86_WRITE_RELATIVE_DISPLACEMENT64() \ + if (X86Instruction->Displacement >= 0) APPEND(OPCSTR, SIZE_LEFT, "+0x%02I64X", X86Instruction->Displacement); \ + else APPEND(OPCSTR, SIZE_LEFT, "-0x%02I64X", -X86Instruction->Displacement); + +#define X86_WRITE_RELATIVE_DISPLACEMENT32() \ + if (X86Instruction->Displacement >= 0) APPEND(OPCSTR, SIZE_LEFT, "+0x%02lX", (U32)X86Instruction->Displacement); \ + else APPEND(OPCSTR, SIZE_LEFT, "-0x%02lX", (U32)-X86Instruction->Displacement); + +#define X86_WRITE_RELATIVE_DISPLACEMENT16() \ + if (X86Instruction->Displacement >= 0) APPEND(OPCSTR, SIZE_LEFT, "+0x%02X", (U16)X86Instruction->Displacement); \ + else APPEND(OPCSTR, SIZE_LEFT, "-0x%02X", (U16)-X86Instruction->Displacement); + +#define X86_WRITE_RELATIVE_DISPLACEMENT() \ +{ \ + switch (X86Instruction->AddressSize) \ + { \ + case 8: \ + X86_WRITE_RELATIVE_DISPLACEMENT64() \ + break; \ + case 4: \ + X86_WRITE_RELATIVE_DISPLACEMENT32() \ + break; \ + case 2: \ + X86_WRITE_RELATIVE_DISPLACEMENT16() \ + break; \ + default: assert(0); break; \ + } \ +} + +#define X86_WRITE_IP_OFFSET(op) \ +{ \ + switch (X86Instruction->OperandSize) \ + { \ + case 8: \ + APPENDS("[rip+ilen"); \ + assert((op)->TargetAddress); \ + X86_WRITE_RELATIVE_DISPLACEMENT64() \ + APPEND(OPCSTR, SIZE_LEFT, "]=0x%04I64X", (op)->TargetAddress+Instruction->VirtualAddressDelta); \ + break; \ + case 4: \ + APPENDS("[eip+ilen"); \ + assert((op)->TargetAddress); \ + X86_WRITE_RELATIVE_DISPLACEMENT32() \ + APPEND(OPCSTR, SIZE_LEFT, "]=0x%04lX", (U32)((op)->TargetAddress+Instruction->VirtualAddressDelta)); \ + break; \ + case 2: \ + APPENDS("[ip+ilen"); \ + X86_WRITE_RELATIVE_DISPLACEMENT16() \ + APPEND(OPCSTR, SIZE_LEFT, "]=0x%04X", (U16)((op)->TargetAddress+Instruction->VirtualAddressDelta)); \ + break; \ + default: assert(0); break; \ + } \ +} + +#define X86_WRITE_OFFSET(op) \ +{ \ + assert((op)->Length <= 8); \ + if (X86Instruction->HasSelector) \ + { \ + assert((op)->Flags & OP_FAR); \ + APPEND(OPCSTR, SIZE_LEFT, "%s 0x%02X:[", DataSizes[((op)->Length >> 1)], X86Instruction->Selector); \ + } \ + else \ + { \ + assert(!((op)->Flags & OP_FAR)); \ + assert(X86Instruction->Segment < SEG_MAX) ; \ + APPEND(OPCSTR, SIZE_LEFT, "%s %s:[", DataSizes[((op)->Length >> 1)], Segments[X86Instruction->Segment]); \ + } \ + X86_WRITE_ABSOLUTE_DISPLACEMENT() \ + APPENDB(']'); \ +} + +void OutputAddress(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + BOOL ShowDisplacement = FALSE; + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + + assert(!X86Instruction->HasSelector); + assert(X86Instruction->SrcAddressIndex == OperandIndex || X86Instruction->DstAddressIndex == OperandIndex); + if (Operand->Length > 16 || (Operand->Length > 1 && (Operand->Length & 1))) APPEND(OPCSTR, SIZE_LEFT, "%d_byte ptr ", Operand->Length); + else APPEND(OPCSTR, SIZE_LEFT, "%s ", DataSizes[Operand->Length >> 1]); + + // + // This attempts to display the address intelligently + // If it has a positive 32-bit displacement, it is shown as seg:Displacement[base+index*scale] + // If it is a negative displacement or 8-bit, it is shown as seg:[base+index*scale+displacement] + // + APPEND(OPCSTR, SIZE_LEFT, "%s:", Segments[X86Instruction->Segment]); + if (X86Instruction->HasBaseRegister) + { + if (X86Instruction->Displacement) + { + if (X86Instruction->HasFullDisplacement) X86_WRITE_ABSOLUTE_DISPLACEMENT() + else ShowDisplacement = TRUE; + } + APPEND(OPCSTR, SIZE_LEFT, "[%s", X86_Registers[X86Instruction->BaseRegister]); + if (X86Instruction->HasIndexRegister) + { + APPEND(OPCSTR, SIZE_LEFT, "+%s", X86_Registers[X86Instruction->IndexRegister]); + if (X86Instruction->Scale > 1) APPEND(OPCSTR, SIZE_LEFT, "*%d", X86Instruction->Scale); + } + if (ShowDisplacement) X86_WRITE_RELATIVE_DISPLACEMENT() + APPENDB(']'); + if (X86Instruction->Relative) + { + U64 Address = Operand->TargetAddress; + assert(Address); + APPLY_OFFSET(Address) + APPEND(OPCSTR, SIZE_LEFT, "=[0x%04I64X]", Address); + } + } + else if (X86Instruction->HasIndexRegister) + { + if (X86Instruction->Displacement) + { + if (X86Instruction->HasFullDisplacement) X86_WRITE_ABSOLUTE_DISPLACEMENT() + else ShowDisplacement = TRUE; + } + APPEND(OPCSTR, SIZE_LEFT, "[%s", X86_Registers[X86Instruction->IndexRegister]); + if (X86Instruction->Scale > 1) APPEND(OPCSTR, SIZE_LEFT, "*%d", X86Instruction->Scale); + if (ShowDisplacement) X86_WRITE_RELATIVE_DISPLACEMENT() + APPENDB(']'); + } + else // just a displacement + { + APPENDB('['); + X86_WRITE_ABSOLUTE_DISPLACEMENT() + APPENDB(']'); + } +} + +void OutputBounds(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + assert(X86Instruction->HasSrcAddressing); + assert(!(Operand->Length & 1)); + Operand->Length >>= 1; + APPENDB('('); + OutputAddress(Instruction, Operand, OperandIndex); + APPENDS(", "); + X86Instruction->Displacement += Operand->Length; + OutputAddress(Instruction, Operand, OperandIndex); + X86Instruction->Displacement -= Operand->Length; + APPENDB(')'); + Operand->Length <<= 1; +} + +void OutputGeneral(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + if ((X86Instruction->HasDstAddressing && X86Instruction->DstAddressIndex == OperandIndex) || + (X86Instruction->HasSrcAddressing && X86Instruction->SrcAddressIndex == OperandIndex)) + { + OutputAddress(Instruction, Operand, OperandIndex); + } + else + { + APPENDS(X86_Registers[Operand->Register]); + } +} + +void OutputDescriptor(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + assert(X86Instruction->HasSrcAddressing || X86Instruction->HasDstAddressing); + OutputAddress(Instruction, Operand, OperandIndex); +} + +void OutputPackedReal(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + if ((X86Instruction->HasDstAddressing && X86Instruction->DstAddressIndex == OperandIndex) || + (X86Instruction->HasSrcAddressing && X86Instruction->SrcAddressIndex == OperandIndex)) + { + OutputAddress(Instruction, Operand, OperandIndex); + } + else + { + APPENDS(X86_Registers[Operand->Register]); + } +} + +void OutputPackedBCD(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + if ((X86Instruction->HasDstAddressing && X86Instruction->DstAddressIndex == OperandIndex) || + (X86Instruction->HasSrcAddressing && X86Instruction->SrcAddressIndex == OperandIndex)) + { + OutputAddress(Instruction, Operand, OperandIndex); + } + else + { + APPENDS(X86_Registers[Operand->Register]); + } +} + +void OutputScalarReal(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + if ((X86Instruction->HasDstAddressing && X86Instruction->DstAddressIndex == OperandIndex) || + (X86Instruction->HasSrcAddressing && X86Instruction->SrcAddressIndex == OperandIndex)) + { + OutputAddress(Instruction, Operand, OperandIndex); + } + else + { + APPENDS(X86_Registers[Operand->Register]); + } +} + +void OutputScalarGeneral(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + if (Operand->Type == OPTYPE_FLOAT) + { + OutputScalarReal(Instruction, Operand, OperandIndex); + } + else + { + OutputGeneral(Instruction, Operand, OperandIndex); + } +} + +void OutputFPUEnvironment(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + assert(X86Instruction->HasSrcAddressing || X86Instruction->HasDstAddressing); + OutputAddress(Instruction, Operand, OperandIndex); +} + +void OutputFPUState(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + assert(X86Instruction->HasSrcAddressing || X86Instruction->HasDstAddressing); + OutputAddress(Instruction, Operand, OperandIndex); +} + +void OutputCPUState(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + assert(X86Instruction->HasSrcAddressing); + OutputAddress(Instruction, Operand, OperandIndex); +} + +void OutputSegOffset(INSTRUCTION *Instruction, INSTRUCTION_OPERAND *Operand, U32 OperandIndex) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + assert(X86Instruction->HasSrcAddressing); + OutputAddress(Instruction, Operand, OperandIndex); +} + +//////////////////////////////////////////////////////////// +// Prologue support +//////////////////////////////////////////////////////////// + +typedef struct _PROLOGUE +{ + char *Data; + U32 Length; +} PROLOGUE; + +PROLOGUE StandardPrologues[] = +{ + { "\x55\x8b\xec", 3 }, + { "\x55\x89\xe5", 3 }, + { "\x83\xec", 2 }, + { "\x81\xec", 2 }, + // TODO: add AMD64 prologues + // TODO: add VS2003/VS2003 prologues + // TODO: add any unique prologues from other compilers + { NULL, 0 } +}; + +// Find the first function between StartAddress and EndAddress +// +// This will match a standard prologue and then analyze the following instructions to verify +// it is a valid function +U8 *X86_FindFunctionByPrologue(INSTRUCTION *Instruction, U8 *StartAddress, U8 *EndAddress, U32 Flags) +{ + assert(0); // TODO + return NULL; +} + +////////////////////////////////////////////////////////// +// Instruction decoder +////////////////////////////////////////////////////////// + +BOOL X86_GetInstruction(INSTRUCTION *Instruction, U8 *Address, U32 Flags) +{ + BOOL SpecialExtension = FALSE; + U8 Opcode = 0, OpcodeExtension = 0, Group = 0, SSE_Prefix = 0, Suffix; + U32 i = 0, Result = 0, tmpScale; + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + X86_OPCODE *X86Opcode; +#ifdef TEST_DISASM + U32 InstructionLength = 0; +#endif + INSTRUCTION_OPERAND *Operand, *Operand1 = NULL; + DISASSEMBLER *Disassembler = Instruction->Disassembler; + BOOL Decode = Flags & DISASM_DECODE; + BOOL Disassemble = Flags & DISASM_DISASSEMBLE; + BOOL SuppressErrors = Flags & DISASM_SUPPRESSERRORS; + + if (Disassemble && !Decode) + { + assert(0); + Decode = TRUE; + } + + if (!Address || !X86_InitInstruction(Instruction)) + { + assert(0); + goto abort; + } + + assert(Instruction->Address == Address); + assert(!Instruction->StringIndex && !Instruction->Length); + + Disassembler->Stage1Count++; + if (Flags & DISASM_ALIGNOUTPUT) Instruction->StringAligned = TRUE; + + // + // Get prefixes or three byte opcode + // + while (TRUE) + { + Opcode = *Address; + INSTR_INC(1); // increment Instruction->Length and address + X86Opcode = &X86_Opcodes_1[Opcode]; + + // Handle a misplaced REX prefix -- AMD64 manual says it is just ignored + if (IS_AMD64() && (Opcode >= REX_PREFIX_START && Opcode <= REX_PREFIX_END) && X86_PREFIX((&X86_Opcodes_1[*Address]))) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: REX prefix before legacy prefix 0x%02X\n", VIRTUAL_ADDRESS, Opcode); + Instruction->AnomalyOccurred = TRUE; + } + continue; + } + + if (X86_PREFIX(X86Opcode)) + { + if (!Instruction->AnomalyOccurred) + { + for (i = 0; i < Instruction->PrefixCount; i++) + { + if (Instruction->Prefixes[i] == Opcode) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Duplicate prefix 0x%02X\n", VIRTUAL_ADDRESS, Opcode); + Instruction->AnomalyOccurred = TRUE; + break; + } + } + } + + switch (Opcode) + { + case PREFIX_REPNE: // may be three byte opcode + SSE_Prefix = Opcode; + if (!Instruction->AnomalyOccurred && X86Instruction->HasRepeatWhileEqualPrefix) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Conflicting prefix\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + Instruction->Repeat = TRUE; + X86Instruction->HasRepeatWhileEqualPrefix = FALSE; + X86Instruction->HasRepeatWhileNotEqualPrefix = TRUE; + break; + case PREFIX_REP: // may be three byte opcode + SSE_Prefix = Opcode; + if (!Instruction->AnomalyOccurred && X86Instruction->HasRepeatWhileNotEqualPrefix) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Conflicting prefix\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + + Instruction->Repeat = TRUE; + X86Instruction->HasRepeatWhileNotEqualPrefix = FALSE; + X86Instruction->HasRepeatWhileEqualPrefix = TRUE; + break; + + case PREFIX_OPERAND_SIZE: // may be three byte opcode + SSE_Prefix = Opcode; + if (!Instruction->AnomalyOccurred && X86Instruction->HasOperandSizePrefix) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Conflicting prefix\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + + if (X86Instruction->HasOperandSizePrefix) break; + else X86Instruction->HasOperandSizePrefix = TRUE; + switch (X86Instruction->OperandSize) + { + case 4: X86Instruction->OperandSize = 2; break; + case 2: X86Instruction->OperandSize = 4; break; + default: assert(0); goto abort; + } + break; + + case PREFIX_ADDRESS_SIZE: + if (!Instruction->AnomalyOccurred && X86Instruction->HasAddressSizePrefix) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Conflicting prefix\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + + if (X86Instruction->HasAddressSizePrefix) break; + else X86Instruction->HasAddressSizePrefix = TRUE; + switch (X86Instruction->AddressSize) + { + case 8: + X86Instruction->AddressSize = 4; + break; + case 4: + assert(!IS_AMD64()); // this should not be possible + X86Instruction->AddressSize = 2; + break; + case 2: + X86Instruction->AddressSize = 4; + break; + default: + assert(0); goto abort; + } + break; + + case PREFIX_SEGMENT_OVERRIDE_ES: + SANITY_CHECK_SEGMENT_OVERRIDE(); + if (!IS_AMD64()) + { + X86Instruction->HasSegmentOverridePrefix = TRUE; + X86Instruction->Segment = SEG_ES; + } + else if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Meaningless segment override\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + break; + case PREFIX_SEGMENT_OVERRIDE_CS: + SANITY_CHECK_SEGMENT_OVERRIDE(); + if (!IS_AMD64()) + { + X86Instruction->HasSegmentOverridePrefix = TRUE; + X86Instruction->Segment = SEG_CS; + } + else if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Meaningless segment override\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + break; + case PREFIX_SEGMENT_OVERRIDE_SS: + SANITY_CHECK_SEGMENT_OVERRIDE(); + if (!IS_AMD64()) + { + X86Instruction->HasSegmentOverridePrefix = TRUE; + X86Instruction->Segment = SEG_SS; + } + else if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Meaningless segment override\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + break; + case PREFIX_SEGMENT_OVERRIDE_DS: + SANITY_CHECK_SEGMENT_OVERRIDE(); + if (!IS_AMD64()) + { + X86Instruction->HasSegmentOverridePrefix = TRUE; + X86Instruction->Segment = SEG_DS; + } + else if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Meaningless segment override\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + break; + case PREFIX_SEGMENT_OVERRIDE_FS: + SANITY_CHECK_SEGMENT_OVERRIDE(); + X86Instruction->HasSegmentOverridePrefix = TRUE; + X86Instruction->Segment = SEG_FS; + break; + case PREFIX_SEGMENT_OVERRIDE_GS: + SANITY_CHECK_SEGMENT_OVERRIDE(); + X86Instruction->HasSegmentOverridePrefix = TRUE; + X86Instruction->Segment = SEG_GS; + break; + + case PREFIX_LOCK: + if (!Instruction->AnomalyOccurred && X86Instruction->HasLockPrefix) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Conflicting prefix\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->HasLockPrefix = TRUE; + break; + + default: + assert(0); + goto abort; + } + + if (Instruction->PrefixCount >= X86_MAX_INSTRUCTION_LEN) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Reached maximum prefix count %d\n", VIRTUAL_ADDRESS, X86_MAX_PREFIX_LENGTH); + goto abort; + } + else if (Instruction->PrefixCount == X86_MAX_PREFIX_LENGTH) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Reached maximum prefix count %d\n", VIRTUAL_ADDRESS, X86_MAX_PREFIX_LENGTH); + Instruction->AnomalyOccurred = TRUE; + } + + assert(Instruction->AnomalyOccurred || Instruction->PrefixCount < X86_MAX_PREFIX_LENGTH); + Instruction->Prefixes[Instruction->PrefixCount] = Opcode; + Instruction->PrefixCount++; + //DISASM_OUTPUT(("[0x%08I64X] Prefix 0x%02X (prefix count %d)\n", VIRTUAL_ADDRESS, Opcode, Instruction->PrefixCount)); + } + else + { + break; + } + } + + // Check for REX opcode + // This is checked here instead of the prefix loop above because it must be the + // last prefix + if (IS_AMD64() && (Opcode >= REX_PREFIX_START && Opcode <= REX_PREFIX_END)) + { + if (Instruction->PrefixCount >= X86_MAX_INSTRUCTION_LEN) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Reached maximum prefix count %d\n", VIRTUAL_ADDRESS, X86_MAX_PREFIX_LENGTH); + goto abort; + } + else if (!Instruction->AnomalyOccurred && Instruction->PrefixCount == AMD64_MAX_PREFIX_LENGTH) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Reached maximum prefix count %d\n", VIRTUAL_ADDRESS, X86_MAX_PREFIX_LENGTH); + Instruction->AnomalyOccurred = TRUE; + } + + assert(Instruction->AnomalyOccurred || Instruction->PrefixCount < AMD64_MAX_PREFIX_LENGTH); + + Instruction->Prefixes[Instruction->PrefixCount] = Opcode; + Instruction->PrefixCount++; + X86Instruction->rex_b = Opcode; + SET_REX(X86Instruction->rex, X86Instruction->rex_b); + DISASM_OUTPUT(("[0x%08I64X] REX prefix 0x%02X (prefix count %d, w=%d, r=%d, x=%d, b=%d)\n", VIRTUAL_ADDRESS, Opcode, Instruction->PrefixCount, X86Instruction->rex.w, X86Instruction->rex.r, X86Instruction->rex.x, X86Instruction->rex.b)); + + assert(X86Instruction->AddressSize >= 4); + if (X86Instruction->rex.w) + { + X86Instruction->OperandSize = 8; + X86Instruction->HasOperandSizePrefix = FALSE; + } + else if (X86Instruction->HasOperandSizePrefix) + { + assert(X86Instruction->OperandSize == 2); + } + else if (X86Instruction->rex_b == REX_PREFIX_START) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: meaningless REX prefix used\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->rex_b = 0; + } + + Opcode = *Address; + INSTR_INC(1); // increment Instruction->Length and address + + X86Opcode = &X86_Opcodes_1[Opcode]; + assert(!X86_PREFIX(X86Opcode)); + } + //DISASM_OUTPUT(("[0x%08I64X] OperandSize = %d, AddressSize = %d\n", VIRTUAL_ADDRESS, X86Instruction->OperandSize, X86Instruction->AddressSize)); + Instruction->LastOpcode = Opcode; + Instruction->OpcodeAddress = Address-1; + + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Invalid opcode 0x%02X\n", VIRTUAL_ADDRESS, Opcode); + goto abort; + } + + if (Opcode == X86_TWO_BYTE_OPCODE) + { + // + // Handle case that it is a group (with opcode extension), floating point, or two byte opcode + // + assert(!Instruction->OpcodeLength); + Instruction->LastOpcode = Opcode = *Address; + INSTR_INC(1); // increment Instruction->Length and address + assert(X86Opcode->Table == X86_Opcodes_2); + X86Opcode = &X86_Opcodes_2[Opcode]; + + // + // Check for errors + // + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Invalid two byte opcode 0x%02X 0x%02X\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode); + goto abort; + } + + if (X86Instruction->AddressSize == 8) + { + if (X86_Invalid_Addr64_2[Opcode]) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Opcode 0x%02X 0x%02X (\"%s\") illegal in 64-bit mode\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode, X86Opcode->Mnemonic); + goto abort; + } +#if 0 + if (X86Instruction->rex_b && + (GET_REX_B(X86Instruction->rex_b) && !GET_REX_B(X86_REX_2[Opcode]) || + GET_REX_X(X86Instruction->rex_b) && !GET_REX_X(X86_REX_2[Opcode]) || + GET_REX_R(X86Instruction->rex_b) && !GET_REX_R(X86_REX_2[Opcode]) || + GET_REX_W(X86Instruction->rex_b) && !GET_REX_W(X86_REX_2[Opcode]))) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal REX prefix 0x%02X for opcode 0x%02X 0x%02X\n", VIRTUAL_ADDRESS, X86Instruction->rex_b, X86_TWO_BYTE_OPCODE, Opcode); + assert(0); + goto abort; + } +#endif + } + + if (X86Instruction->OperandSize == 2 && X86_Invalid_Op16_2[Opcode]) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Opcode 0x%02X 0x%02X (\"%s\") illegal with 16-bit operand size\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode, X86Opcode->Mnemonic); + goto abort; + } + + X86Instruction->HasModRM = X86_ModRM_2[Opcode]; + if (X86Instruction->HasModRM) X86Instruction->modrm_b = *Address; + Instruction->OpcodeBytes[0] = X86_TWO_BYTE_OPCODE; + Instruction->OpcodeBytes[1] = Opcode; + Instruction->OpcodeLength = 2; + + if (X86_SPECIAL_EXTENSION(X86Opcode)) + { + DISASM_OUTPUT(("[0x%08I64X] Special opcode extension 0x%02X 0x%02X\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode)); + SpecialExtension = TRUE; + goto HasSpecialExtension; + } + else if (SSE_Prefix && !X86_INVALID(&X86_SSE[Opcode])) // SSEx instruction + { + Instruction->OpcodeLength = 3; + Instruction->OpcodeBytes[2] = SSE_Prefix; + assert(Instruction->OpcodeBytes[1] == Opcode); + + // Since the prefix was really an opcode extension, remove it from + // the prefix list + for (i = 0; i < Instruction->PrefixCount; i++) + { + if (Instruction->Prefixes[i]) break; + } + assert(i != Instruction->PrefixCount); + Instruction->PrefixCount--; + Instruction->Prefixes[i] = 0; + + // Slide any prefixes following the removed prefix down by 1 + memmove(&Instruction->Prefixes[i], &Instruction->Prefixes[i+1], Instruction->PrefixCount-i); + Instruction->Prefixes[Instruction->PrefixCount] = 0; + Instruction->Repeat = FALSE; + X86Instruction->HasRepeatWhileEqualPrefix = FALSE; + X86Instruction->HasRepeatWhileNotEqualPrefix = FALSE; + X86Instruction->HasOperandSizePrefix = FALSE; + if (SSE_Prefix == PREFIX_OPERAND_SIZE) + { + if (IS_AMD64() && X86Instruction->rex.w) X86Instruction->OperandSize = 8; + else X86Instruction->OperandSize = 4; + } + + if (IS_X86_16()) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: SSE invalid in 16-bit mode\n", VIRTUAL_ADDRESS); + goto abort; + } + + assert(X86Instruction->HasModRM); + switch (SSE_Prefix) + { + case PREFIX_OPERAND_SIZE: X86Opcode = &X86_SSE[0x000+Opcode]; break; + case PREFIX_REPNE: X86Opcode = &X86_SSE[0x100+Opcode]; break; + case PREFIX_REP: X86Opcode = &X86_SSE[0x200+Opcode]; break; + } + + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal SSE instruction opcode 0x%02X 0x%02X + prefix 0x%02X\n", VIRTUAL_ADDRESS, Instruction->OpcodeBytes[0], Instruction->OpcodeBytes[1], Instruction->OpcodeBytes[2]); + goto abort; + } + else if (X86_EXTENDED_OPCODE(X86Opcode)) + { + // SSE in group (13, 14, or 15) + OpcodeExtension = GET_MODRM_EXT(X86Instruction->modrm_b); + Group = X86_Groups_2[Opcode]; + X86Instruction->Group = (U8)Group; + assert(Group >= 13 && Group <= 15 && X86Opcode->Table); + switch (SSE_Prefix) + { + case PREFIX_OPERAND_SIZE: X86Opcode = &X86Opcode->Table[0x00+OpcodeExtension]; break; + case PREFIX_REPNE: X86Opcode = &X86Opcode->Table[0x08+OpcodeExtension]; break; + case PREFIX_REP: X86Opcode = &X86Opcode->Table[0x10+OpcodeExtension]; break; + } + + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal SSE instruction opcode 0x%02X 0x%02X + prefix 0x%02X + extension %d\n", VIRTUAL_ADDRESS, Instruction->OpcodeBytes[0], Instruction->OpcodeBytes[1], Instruction->OpcodeBytes[2], OpcodeExtension); + goto abort; + } + } + + Instruction->Repeat = FALSE; + X86Instruction->HasRepeatWhileEqualPrefix = FALSE; + X86Instruction->HasRepeatWhileNotEqualPrefix = FALSE; + X86Instruction->HasOperandSizePrefix = FALSE; + switch (X86_GET_CATEGORY(X86Opcode)) + { + case ITYPE_SSE: case ITYPE_SSE2: case ITYPE_SSE3: break; + default: assert(0); goto abort; + } + } + else if (X86_EXTENDED_OPCODE(X86Opcode)) // 2 byte group + { + assert(!X86Opcode->MnemonicFlags); + OpcodeExtension = GET_MODRM_EXT(X86Instruction->modrm_b); + + assert(X86Opcode->Table); + X86Opcode = &X86Opcode->Table[OpcodeExtension]; + if (X86_INVALID(X86Opcode)) + { + Instruction->Length++; + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Invalid group opcode 0x%02X 0x%02X extension 0x%02X\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode, OpcodeExtension); + goto abort; + } + + assert(!X86_SPECIAL_EXTENSION(X86Opcode)); + Group = X86_Groups_2[Opcode]; + X86Instruction->Group = (U8)Group; + assert(Group > 0 && Group <= 19); + assert(X86Opcode->Mnemonic); + DISASM_OUTPUT(("[0x%08I64X] Group %d (bytes 0x%02X 0x%02X) extension 0x%02X (\"%s\")\n", VIRTUAL_ADDRESS, Group, X86_TWO_BYTE_OPCODE, Opcode, OpcodeExtension, X86Opcode->Mnemonic)); + } + else + { + assert(X86Opcode->Mnemonic); + DISASM_OUTPUT(("[0x%08I64X] Two byte opcode 0x%02X 0x%02X (\"%s\")\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode, X86Opcode->Mnemonic)); + X86Instruction->HasModRM = X86_ModRM_2[Opcode]; + if (X86Instruction->HasModRM) X86Instruction->modrm_b = *Address; + } + } + else // 1-byte opcode + { + if (X86Instruction->AddressSize == 8) + { + if (X86_Invalid_Addr64_1[Opcode]) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Opcode 0x%02X (\"%s\") illegal in 64-bit mode\n", VIRTUAL_ADDRESS, Opcode, X86Opcode->Mnemonic); + goto abort; + } + +#if 0 + if (X86Instruction->rex_b && + (GET_REX_B(X86Instruction->rex_b) && !GET_REX_B(X86_REX_1[Opcode]) || + GET_REX_X(X86Instruction->rex_b) && !GET_REX_X(X86_REX_1[Opcode]) || + GET_REX_R(X86Instruction->rex_b) && !GET_REX_R(X86_REX_1[Opcode]) || + GET_REX_W(X86Instruction->rex_b) && !GET_REX_W(X86_REX_1[Opcode]))) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal REX prefix 0x%02X for opcode 0x%02X\n", VIRTUAL_ADDRESS, X86Instruction->rex_b, Opcode); + assert(0); + goto abort; + } +#endif + } + + if (X86Instruction->OperandSize == 2 && X86_Invalid_Op16_1[Opcode]) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Opcode 0x%02X (\"%s\") illegal with 16-bit operand size\n", VIRTUAL_ADDRESS, Opcode, X86Opcode->Mnemonic); + goto abort; + } + + Instruction->OpcodeBytes[0] = Opcode; + Instruction->OpcodeLength = 1; + X86Instruction->HasModRM = X86_ModRM_1[Opcode]; + if (X86Instruction->HasModRM) X86Instruction->modrm_b = *Address; + + if (X86_EXTENDED_OPCODE(X86Opcode)) // a group + { + assert(X86Instruction->HasModRM); + OpcodeExtension = GET_MODRM_EXT(*Address); // leave Address pointing at ModRM byte + + if (X86_SPECIAL_EXTENSION(X86Opcode)) + { + DISASM_OUTPUT(("[0x%08I64X] Special opcode extension 0x%02X 0x%02X\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode)); + SpecialExtension = TRUE; + goto HasSpecialExtension; + } + + assert(X86Opcode->Table); + X86Opcode = &X86Opcode->Table[OpcodeExtension]; + if (X86_INVALID(X86Opcode)) + { + Instruction->Length++; + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Invalid group opcode 0x%02X extension 0x%02X\n", VIRTUAL_ADDRESS, Opcode, OpcodeExtension); + goto abort; + } + + Group = X86_Groups_1[Opcode]; + X86Instruction->Group = (U8)Group; + DISASM_OUTPUT(("[0x%08I64X] Group %d (byte 0x%02X) extension 0x%02X (\"%s\")\n", VIRTUAL_ADDRESS, Group, Opcode, OpcodeExtension, X86Opcode->Mnemonic)); + assert(Group > 0 && Group <= 17); + assert(X86Opcode->Mnemonic); + } + else + { + if (X86_SPECIAL_EXTENSION(X86Opcode)) + { + DISASM_OUTPUT(("[0x%08I64X] Special opcode extension 0x%02X\n", VIRTUAL_ADDRESS, Opcode)); + SpecialExtension = TRUE; + goto HasSpecialExtension; + } + + DISASM_OUTPUT(("[0x%08I64X] One byte opcode 0x%02X (\"%s\")\n", VIRTUAL_ADDRESS, Opcode, X86Opcode->Mnemonic)); + } + } + +HasSpecialExtension: + if (SpecialExtension) + { + if (X86Opcode->MnemonicFlags & ITYPE_EXT_MODRM) + { + assert(X86Opcode->Table); + assert(Instruction->OpcodeLength == 2); + assert(X86Instruction->HasModRM); + X86Opcode = &X86Opcode->Table[*Address]; + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal opcode 0x%02X 0x%02X + modrm 0x%02X\n", VIRTUAL_ADDRESS, Instruction->OpcodeBytes[0], Instruction->OpcodeBytes[1], *Address); + goto abort; + } + else if (X86_EXTENDED_OPCODE(X86Opcode)) + { + assert(!X86Opcode->MnemonicFlags); + OpcodeExtension = GET_MODRM_EXT(X86Instruction->modrm_b); + + assert(X86Opcode->Table); + X86Opcode = &X86Opcode->Table[OpcodeExtension]; + if (X86_INVALID(X86Opcode)) + { + Instruction->Length++; + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Invalid group opcode 0x%02X 0x%02X extension 0x%02X\n", VIRTUAL_ADDRESS, X86_TWO_BYTE_OPCODE, Opcode, OpcodeExtension); + goto abort; + } + + assert(!X86_SPECIAL_EXTENSION(X86Opcode)); + Group = X86_Groups_2[Opcode]; + X86Instruction->Group = (U8)Group; + assert(Group > 0 && Group <= 19); + assert(X86Opcode->Mnemonic); + DISASM_OUTPUT(("[0x%08I64X] Group %d (bytes 0x%02X 0x%02X) extension 0x%02X (\"%s\")\n", VIRTUAL_ADDRESS, Group, X86_TWO_BYTE_OPCODE, Opcode, OpcodeExtension, X86Opcode->Mnemonic)); + } + else if (!X86_OPERAND_COUNT(X86Opcode)) + { + INSTR_INC(1); // increment Instruction->Length and address + } + } + else if (X86Opcode->MnemonicFlags & ITYPE_EXT_FPU) + { + assert(X86Opcode->Table); + if (X86Instruction->modrm_b < 0xC0) + { + // It is an opcode extension, use the X86Opcode->Table + OpcodeExtension = GET_MODRM_EXT(X86Instruction->modrm_b); + X86Opcode = &X86Opcode->Table[OpcodeExtension]; + } + else + { + // The whole ModRM byte is used, these start at index 0x08 in X86Opcode->Table + OpcodeExtension = (X86Instruction->modrm_b & 0x3F); + X86Opcode = &X86Opcode->Table[0x08 + OpcodeExtension]; + } + + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Invalid FPU opcode 0x%02X + modrm extension 0x%02X (index 0x%02X)\n", VIRTUAL_ADDRESS, Opcode, X86Instruction->modrm_b, 0x08 + OpcodeExtension); + goto abort; + } + + DISASM_OUTPUT(("[0x%08I64X] FPU instruction is (\"%s\"): 0x%02X + modrm 0x%02X (index 0x%02X)\n", VIRTUAL_ADDRESS, X86Opcode->Mnemonic, Opcode, X86Instruction->modrm_b, 0x08 + OpcodeExtension)); + if (!X86_OPERAND_COUNT(X86Opcode)) INSTR_INC(1); // increment Instruction->Length and address + } + else if (X86Opcode->MnemonicFlags & ITYPE_EXT_SUFFIX) + { + if (X86Instruction->HasOperandSizePrefix) + { + if (!Instruction->AnomalyOccurred && X86Opcode->Table == X86_3DNOW_0F) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: operand size prefix used with 3DNOW instruction\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->HasOperandSizePrefix = FALSE; + X86Instruction->OperandSize = 4; + } + Instruction->OperandCount = X86_OPERAND_COUNT(X86Opcode); + assert(Instruction->OpcodeLength == 2 && X86Instruction->HasModRM && Instruction->OperandCount == 2); + memcpy(&X86Instruction->Opcode, X86Opcode, sizeof(X86_OPCODE)); + Instruction->Operands[0].Flags = X86Opcode->OperandFlags[0] & X86_OPFLAGS_MASK; + Instruction->Operands[1].Flags = X86Opcode->OperandFlags[1] & X86_OPFLAGS_MASK; + Instruction->Operands[2].Flags = X86Opcode->OperandFlags[2] & X86_OPFLAGS_MASK; + assert(Address == Instruction->Address + Instruction->Length); + if (!SetOperands(Instruction, Address, Flags & DISASM_SUPPRESSERRORS)) goto abort; + Suffix = Instruction->Address[Instruction->Length++]; + Instruction->OpcodeBytes[2] = Suffix; + Instruction->OpcodeLength = 3; + X86Opcode = &X86Opcode->Table[Suffix]; + + if (X86_INVALID(X86Opcode)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal opcode 0x%02X 0x%02X + suffix 0x%02X\n", VIRTUAL_ADDRESS, Instruction->OpcodeBytes[0], Instruction->OpcodeBytes[1], Suffix); + goto abort; + } + assert(Instruction->Length >= 4 + Instruction->PrefixCount); + } + else if (X86Opcode->MnemonicFlags & ITYPE_EXT_64) + { + assert(X86Opcode->Table); + if (IS_AMD64()) X86Opcode = &X86Opcode->Table[1]; + else X86Opcode = &X86Opcode->Table[0]; + assert(!X86_INVALID(X86Opcode)); + } + } + + // Detect incompatibilities + if (IS_X86_16() && X86Opcode->CPU > CPU_I386) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Instruction \"%s\" (opcode 0x%02X) can't be used in 16-bit X86\n", VIRTUAL_ADDRESS, X86Opcode->Mnemonic, Instruction->LastOpcode); + goto abort; + } + if (!IS_AMD64() && X86Opcode->CPU >= CPU_AMD64) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Instruction \"%s\" (opcode 0x%02X) can only be used in X86-64\n", VIRTUAL_ADDRESS, X86Opcode->Mnemonic, Instruction->LastOpcode); + goto abort; + } + + // Copy the opcode into the local structure and set the fields + assert(Instruction->OpcodeLength && !X86_INVALID(X86Opcode)); + memcpy(&X86Instruction->Opcode, X86Opcode, sizeof(X86_OPCODE)); + Instruction->Groups |= X86_GET_CATEGORY(X86Opcode); + assert(Instruction->Groups); + Instruction->Type |= X86_GET_TYPE(X86Opcode); + assert((U32)Instruction->Type >= Instruction->Groups); + Instruction->OperandCount = X86_OPERAND_COUNT(X86Opcode); + + // + // Sanity check prefixes now that opcode is known and prefixes are resolved + // + + // Instructions that implicitly reference the CS/DS can't have segment override prefixes + switch (Instruction->Type) + { + case ITYPE_PUSHF: case ITYPE_POPF: + case ITYPE_ENTER: case ITYPE_LEAVE: + SANITY_CHECK_SEGMENT_OVERRIDE(); + X86Instruction->HasSegmentOverridePrefix = FALSE; + X86Instruction->Segment = SEG_SS; + break; + case ITYPE_RET: case ITYPE_DEBUG: + case ITYPE_OFLOW: case ITYPE_TRAP: + case ITYPE_TRAPRET: + SANITY_CHECK_SEGMENT_OVERRIDE(); + X86Instruction->HasSegmentOverridePrefix = FALSE; + X86Instruction->Segment = SEG_CS; + break; + } + + // Check illegal prefixes used with FPU/MMX/SSEx + if (Instruction->Groups & (ITYPE_FPU|ITYPE_MMX|ITYPE_SSE|ITYPE_SSE2|ITYPE_SSE3)) + { + // Check for prefixes that produce unpredictable results + for (i = 0; i < Instruction->PrefixCount; i++) + { + switch (Instruction->Prefixes[i]) + { + case PREFIX_OPERAND_SIZE: + switch (Instruction->Type) + { + case ITYPE_FSTOREENV: case ITYPE_FLOADENV: case ITYPE_FSAVE: case ITYPE_FRESTORE: continue; + default: break; + } + + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: operand size prefix used with FPU/MMX/SSEx\n", VIRTUAL_ADDRESS); + goto abort; + } + X86Instruction->HasOperandSizePrefix = FALSE; + if (X86Instruction->OperandSize == 2) X86Instruction->OperandSize = 2; + break; + + case PREFIX_REPNE: + case PREFIX_REP: + if (Instruction->Groups & ITYPE_FPU) { assert(Instruction->Repeat); continue; } + // The Intel manual says this results in unpredictable behavior -- it's not even + // clear which SSE prefix is used as the third opcode byte in this case + // (e.g., is it the first or last SSE prefix?) + if (!SuppressErrors) printf("[0x%08I64X] ERROR: rep/repne used with MMX/SSEx\n", VIRTUAL_ADDRESS); + goto abort; + + default: + break; + } + } + } + + // Check for conflicts involving operand size + if (IS_AMD64()) + { + // Check for use of rex.w=1 with an operand size prefix + if (X86Instruction->rex.w) + { + assert(X86Instruction->OperandSize == 8); + for (i = 0; i < Instruction->PrefixCount; i++) + { + if (Instruction->Prefixes[i] == PREFIX_OPERAND_SIZE) + { + X86Instruction->HasOperandSizePrefix = FALSE; + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: use of operand size prefix meaningless when REX.w=1\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + } + } + } + + // Set default operand size to 64 instead of 32 for some instructions + switch (Instruction->Type) + { + case ITYPE_PUSH: case ITYPE_POP: + case ITYPE_PUSHF: case ITYPE_POPF: + case ITYPE_ENTER: case ITYPE_LEAVE: + case ITYPE_CALL: case ITYPE_BRANCH: + case ITYPE_LOOPCC: case ITYPE_RET: + X86Instruction->HasDefault64Operand = TRUE; + break; + + case ITYPE_SYSTEM: + if (Instruction->OpcodeLength != 2) break; + + // lgdt/lidt/lldt/ltr + if ((Instruction->LastOpcode == 0x00 || Instruction->LastOpcode == 0x01) && + (OpcodeExtension == 0x02 || OpcodeExtension == 0x03)) + { + X86Instruction->HasDefault64Operand = TRUE; + } + break; + + default: + break; + } + + if (X86Instruction->HasDefault64Operand) + { + if (X86Instruction->rex.w) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: use of REX.w is meaningless (default operand size is 64)\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->rex_b &= ~8; + X86Instruction->rex.w = 0; + } + + if (X86Instruction->HasOperandSizePrefix) + { + assert(X86Instruction->OperandSize == 2); + X86Instruction->HasDefault64Operand = FALSE; + } + else + { + assert(X86Instruction->OperandSize >= 4); + X86Instruction->OperandSize = 8; + } + } + } + + // Make sure rep/repe/repne is set correctly based on instruction + if (Instruction->Repeat) + { + switch (Instruction->Type) + { + case ITYPE_IN: + case ITYPE_OUT: + case ITYPE_STRMOV: + case ITYPE_STRSTOR: + case ITYPE_STRLOAD: + if (X86Instruction->HasRepeatWhileNotEqualPrefix) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: REPNE should only be used with cmps/scas\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + // Treat it as just a "rep" + X86Instruction->HasRepeatWhileNotEqualPrefix = FALSE; + X86Instruction->HasRepeatWhileEqualPrefix = TRUE; + } + break; + case ITYPE_STRCMP: + break; + default: + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Repeat prefix used with non-string instruction\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + Instruction->Repeat = FALSE; + X86Instruction->HasRepeatWhileEqualPrefix = FALSE; + X86Instruction->HasRepeatWhileNotEqualPrefix = FALSE; + break; + } + } + + if (Disassemble) + { + assert(!Instruction->StringIndex); + if (X86Instruction->HasRepeatWhileEqualPrefix) + { + if (Instruction->Type == ITYPE_STRCMP) { APPENDS("repe "); } + else { APPENDS("rep "); } + } + if (X86Instruction->HasRepeatWhileNotEqualPrefix) APPENDS("repne "); + if (X86Instruction->HasLockPrefix) APPENDS("lock "); + if (X86Instruction->HasBranchTakenPrefix) APPENDS("hinttake "); + if (X86Instruction->HasBranchNotTakenPrefix) APPENDS("hintskip "); + APPENDPAD(12); + APPEND(OPCSTR, SIZE_LEFT, "%s", X86Opcode->Mnemonic); + APPENDPAD(24); + } + + if (Instruction->OperandCount) + { + Instruction->Operands[0].Flags = X86Opcode->OperandFlags[0] & X86_OPFLAGS_MASK; + Instruction->Operands[1].Flags = X86Opcode->OperandFlags[1] & X86_OPFLAGS_MASK; + Instruction->Operands[2].Flags = X86Opcode->OperandFlags[2] & X86_OPFLAGS_MASK; + Address = SetOperands(Instruction, Address, Flags); + if (!Address) goto abort; + assert(!(Instruction->Operands[0].Flags & 0x7F)); + assert(!(Instruction->Operands[1].Flags & 0x7F)); + assert(!(Instruction->Operands[2].Flags & 0x7F)); + } + + Disassembler->Stage2Count++; + +#ifdef TEST_DISASM + ////////////////////////////////////////////////////////////////////// + // Test against other disassemblers + ////////////////////////////////////////////////////////////////////// + + if (IS_X86_32()) + { + InstructionLength = X86_GetLength(Instruction, Instruction->Address); + if (InstructionLength && Instruction->Length != InstructionLength) + { + printf("[0x%08I64X] WARNING: instruction lengths differ (%d vs %d)\n", VIRTUAL_ADDRESS, Instruction->Length, InstructionLength); + DumpInstruction(Instruction, TRUE, TRUE); + assert(0); + } + } + else if (IS_AMD64()) + { + // TODO: need other amd64 (x86-64) disassembler to test against + } + else if (IS_X86_16()) + { + // TODO: need other x86 16-bit disassembler to test against + } +#endif + + ////////////////////////////////////////////////////////////////////// + // Post-operand sanity checks + ////////////////////////////////////////////////////////////////////// + + if (!X86Instruction->HasDstAddressing && !X86Instruction->HasSrcAddressing) + { + if (X86Instruction->HasAddressSizePrefix) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: address size prefix used with no addressing\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->HasAddressSizePrefix = FALSE; + } + + if (X86Instruction->HasSegmentOverridePrefix) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: segment override used with no addressing\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->HasSegmentOverridePrefix = FALSE; + } + } + + // Detect use of unusual segments + if (!Instruction->AnomalyOccurred && !IS_X86_16()) + { + switch (X86Instruction->Segment) + { + case SEG_CS: case SEG_DS: case SEG_SS: + break; + case SEG_ES: + switch (Instruction->Type) + { + case ITYPE_IN: case ITYPE_STRMOV: case ITYPE_STRCMP: case ITYPE_STRSTOR: + break; + default: + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: use of unexpected segment ES\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + break; + } + break; + case SEG_FS: + if (IS_X86_32() && !(Instruction->Groups & ITYPE_EXEC)) break; + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: use of unexpected segment FS\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + break; + case SEG_GS: + if (IS_AMD64() && !(Instruction->Groups & ITYPE_EXEC)) break; + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: use of unexpected segment GS\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + break; + default: + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: unexpected segment 0x%02X\n", VIRTUAL_ADDRESS, X86Instruction->Selector); + Instruction->AnomalyOccurred = TRUE; + break; + } + } + + if ((X86Opcode->OperandFlags[0] & OP_COND_EXEC) == OP_COND_EXEC) + { + assert(Instruction->Type == ITYPE_BRANCHCC || Instruction->Type == ITYPE_LOOPCC); + for (i = 0; i < Instruction->PrefixCount; i++) + { + switch (Instruction->Prefixes[i]) + { + case PREFIX_BRANCH_NOT_TAKEN: + if (!Instruction->AnomalyOccurred && X86Instruction->Segment != SEG_CS) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Segment override used with conditional branch\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->HasSegmentOverridePrefix = FALSE; + X86Instruction->Segment = SEG_CS; + X86Instruction->HasBranchNotTakenPrefix = TRUE; + break; + case PREFIX_BRANCH_TAKEN: + if (!Instruction->AnomalyOccurred && X86Instruction->Segment != SEG_DS) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Segment override used with conditional branch\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + X86Instruction->HasSegmentOverridePrefix = FALSE; + X86Instruction->Segment = SEG_CS; + X86Instruction->HasBranchTakenPrefix = TRUE; + break; + } + } + } + + // + // If lock prefix is enabled, verify it is valid + // + if (X86Instruction->HasLockPrefix && + !IsValidLockPrefix(X86Instruction, Opcode, Instruction->OpcodeLength, Group, OpcodeExtension)) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: Illegal use of lock prefix for instruction \"%s\"\n", VIRTUAL_ADDRESS, X86Opcode->Mnemonic); + goto abort; + } + + ////////////////////////////////////////////////////////////////////// + // Generate disassembly output + ////////////////////////////////////////////////////////////////////// + + if (Disassemble) + { + if ((Flags & DISASM_SHOWFLAGS) && + (X86Instruction->Opcode.Preconditions || X86Instruction->Opcode.FlagsChanged || X86Instruction->Opcode.ResultsIfTrue)) + { + APPENDPAD(124); + if (X86Instruction->Opcode.Preconditions) + { + Result = X86Instruction->Opcode.Preconditions; + APPENDS("COND:{ "); + if (Result & COND_L) APPENDS("L "); + if (Result & COND_NL) APPENDS("NL "); + if (Result & COND_LE) APPENDS("LE "); + if (Result & COND_NLE) APPENDS("NLE "); + if (Result & COND_G) APPENDS("G "); + if (Result & COND_NG) APPENDS("NG "); + if (Result & COND_GE) APPENDS("GE "); + if (Result & COND_NGE) APPENDS("NGE "); + if (Result & COND_A) APPENDS("A "); + if (Result & COND_NA) APPENDS("NA "); + if (Result & COND_AE) APPENDS("AE "); + if (Result & COND_NAE) APPENDS("NAE "); + if (Result & COND_B) APPENDS("B "); + if (Result & COND_NB) APPENDS("NB "); + if (Result & COND_BE) APPENDS("BE "); + if (Result & COND_NBE) APPENDS("NBE "); + if (Result & COND_E) APPENDS("E "); + if (Result & COND_NE) APPENDS("NE "); + if (Result & COND_C) APPENDS("C "); + if (Result & COND_NC) APPENDS("NC "); + if (Result & COND_Z) APPENDS("Z "); + if (Result & COND_NZ) APPENDS("NZ "); + if (Result & COND_P) APPENDS("P "); + if (Result & COND_NP) APPENDS("NP "); + if (Result & COND_PE) APPENDS("PE "); + if (Result & COND_PO) APPENDS("PO "); + if (Result & COND_O) APPENDS("O "); + if (Result & COND_NO) APPENDS("NO "); + if (Result & COND_U) APPENDS("U "); + if (Result & COND_NU) APPENDS("NU "); + if (Result & COND_S) APPENDS("S "); + if (Result & COND_NS) APPENDS("NS "); + if (Result & COND_D) APPENDS("D "); + APPENDB('}'); + } + + if (X86Instruction->Opcode.FlagsChanged) + { + Result = X86Instruction->Opcode.FlagsChanged; + + if (Result & FLAG_SET_MASK) + { + APPENDS("SET:{ "); + if (Result & FLAG_CF_SET) APPENDS("C "); + if (Result & FLAG_DF_SET) APPENDS("D "); + if (Result & FLAG_IF_SET) APPENDS("I "); + APPENDB('}'); + } + + if (Result & FLAG_CLR_MASK) + { + APPENDS("CLR:{ "); + if (Result & FLAG_SF_CLR) APPENDS("S "); + if (Result & FLAG_ZF_CLR) APPENDS("Z "); + if (Result & FLAG_AF_CLR) APPENDS("A "); + if (Result & FLAG_CF_CLR) APPENDS("C "); + if (Result & FLAG_DF_CLR) APPENDS("D "); + if (Result & FLAG_IF_CLR) APPENDS("I "); + if (Result & FLAG_OF_CLR) APPENDS("O "); + if ((Result & FPU_ALL_CLR) == FPU_ALL_CLR) + { + APPENDS("FPU_ALL "); + } + else + { + if (Result & FPU_C0_CLR) APPENDS("FPU_C0 "); + if (Result & FPU_C1_CLR) APPENDS("FPU_C1 "); + if (Result & FPU_C2_CLR) APPENDS("FPU_C2 "); + if (Result & FPU_C3_CLR) APPENDS("FPU_C3 "); + } + APPENDB('}'); + } + + if ((Result & FLAG_MOD_MASK) == FLAG_MOD_MASK) + { + APPENDS("MOD:{ "); + if ((Result & FLAG_ALL_MOD) == FLAG_ALL_MOD) + { + APPENDS("FLAGS_ALL "); + } + else if ((Result & FLAG_COMMON_MOD) == FLAG_COMMON_MOD) + { + APPENDS("FLAGS_COMMON "); + } + else + { + if (Result & FLAG_OF_MOD) APPENDS("O "); + if (Result & FLAG_SF_MOD) APPENDS("S "); + if (Result & FLAG_ZF_MOD) APPENDS("Z "); + if (Result & FLAG_AF_MOD) APPENDS("A "); + if (Result & FLAG_PF_MOD) APPENDS("P "); + if (Result & FLAG_CF_MOD) APPENDS("C "); + if (Result & FLAG_DF_MOD) APPENDS("D "); + if (Result & FLAG_IF_MOD) APPENDS("I "); + } + if ((Result & FPU_ALL_MOD) == FPU_ALL_MOD) + { + APPENDS("FPU_ALL "); + } + else + { + if (Result & FPU_C0_MOD) APPENDS("FPU_C0 "); + if (Result & FPU_C1_MOD) APPENDS("FPU_C1 "); + if (Result & FPU_C2_MOD) APPENDS("FPU_C2 "); + if (Result & FPU_C3_MOD) APPENDS("FPU_C3 "); + } + APPENDB('}'); + } + + if (Result & FLAG_TOG_MASK) + { + APPENDS("TOG:{ "); + if (Result & FLAG_CF_TOG) APPENDS("C "); + APPENDB('}'); + } + } + } + + APPENDS("\n"); + } + else + { + Instruction->String[0] = '\0'; + } + + if (!Instruction->Length || Instruction->Length > X86_MAX_INSTRUCTION_LEN) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: maximum instruction length reached (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + + if (!Decode) + { + Disassembler->Stage3CountNoDecode++; + return TRUE; // all work is done + } + + ////////////////////////////////////////////////////////////////////// + // Detect particularly interesting intructions + ////////////////////////////////////////////////////////////////////// + + Operand1 = &Instruction->Operands[0]; + if (Instruction->Groups & ITYPE_EXEC) + { + // If it is a negative offset with a 1-byte or 2-byte offset, assume it is a loop + if (Operand1->Type == OPTYPE_OFFSET && + Operand1->Length <= 2 && X86Instruction->Displacement < 0) + { + Instruction->CodeBranch.IsLoop = TRUE; + Instruction->CodeBranch.Operand = Operand1; + } + + if (!Instruction->AnomalyOccurred && + Operand1->TargetAddress >= (U64)Instruction->Address && + Operand1->TargetAddress < (U64)Instruction->Address + Instruction->Length) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: branch into the middle of an instruction\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + + switch (Instruction->Type) + { + case ITYPE_BRANCH: + Operand1->Flags |= OP_ADDRESS; + assert(Instruction->OperandCount == 1); + if (!(Operand1->Flags & (OP_GLOBAL|OP_FAR))) + { + assert(!X86Instruction->HasSelector); + X86Instruction->Segment = SEG_CS; + } + + if (Operand1->TargetAddress) + { + assert(!Instruction->CodeBranch.AddressOffset); + Instruction->CodeBranch.Count = 1; + Instruction->CodeBranch.Addresses[0] = Operand1->TargetAddress; + Instruction->CodeBranch.Operand = Operand1; + } + // If there is both a base and index register, the Result will probably be too wrong + // to even guess + else if (X86Instruction->HasFullDisplacement && + ((X86Instruction->HasBaseRegister && !X86Instruction->HasIndexRegister) || + (!X86Instruction->HasBaseRegister && X86Instruction->HasIndexRegister))) + { + assert(Operand1->Length <= 0xFF); + if (!X86Instruction->Scale) + { + if (Operand1->Length) X86Instruction->Scale = (U8)Operand1->Length; + else X86Instruction->Scale = X86Instruction->OperandSize; + } + assert(Operand1->Length <= 0xFF); + tmpScale = MAX(X86Instruction->Scale, Operand1->Length); + + assert(tmpScale <= 16); + Instruction->CodeBranch.AddressOffset = (U8)tmpScale; + for (i = 0; i < MAX_CODE_REFERENCE_COUNT; i++) Instruction->CodeBranch.Addresses[i] = (U64)X86Instruction->Displacement + (i * tmpScale); + Instruction->CodeBranch.Count = i; + Instruction->CodeBranch.IsIndirect = TRUE; + Instruction->CodeBranch.Operand = Operand1; + } + break; + + case ITYPE_CALL: + Instruction->Groups |= ITYPE_STACK; + Instruction->CodeBranch.IsCall = TRUE; + Operand1->Flags |= OP_ADDRESS; + assert(Instruction->OperandCount == 1); + if (!(Operand1->Flags & (OP_GLOBAL|OP_FAR))) + { + assert(!X86Instruction->HasSelector); + X86Instruction->Segment = SEG_CS; + } + + if (Operand1->TargetAddress) + { + assert(!Instruction->CodeBranch.AddressOffset); + Instruction->CodeBranch.Count = 1; + Instruction->CodeBranch.Addresses[0] = Operand1->TargetAddress; + Instruction->CodeBranch.Operand = Operand1; + } + // If there is both a base and index register, the Result will probably be too wrong + // to even guess + else if (X86Instruction->HasFullDisplacement && + ((X86Instruction->HasBaseRegister && !X86Instruction->HasIndexRegister) || + (!X86Instruction->HasBaseRegister && X86Instruction->HasIndexRegister))) + { + //DISASM_OUTPUT(("[0x%08I64X] Scale %d, displacement 0x%08I64x\n", VIRTUAL_ADDRESS, X86Instruction->Scale, X86Instruction->Displacement)); + if (!X86Instruction->Scale) + { + assert(Operand1->Length <= 0xFF); + if (Operand1->Length) X86Instruction->Scale = (U8)Operand1->Length; + else X86Instruction->Scale = X86Instruction->OperandSize; + } + tmpScale = MAX(X86Instruction->Scale, Operand1->Length); + + assert(tmpScale <= 16); + Instruction->CodeBranch.AddressOffset = (U8)tmpScale; + assert(X86Instruction->Scale > 1); + for (i = 0; i < MAX_CODE_REFERENCE_COUNT; i++) Instruction->CodeBranch.Addresses[i] = (U64)X86Instruction->Displacement + (i * tmpScale); + Instruction->CodeBranch.Count = i; + Instruction->CodeBranch.IsIndirect = TRUE; + Instruction->CodeBranch.Operand = Operand1; + } + break; + + case ITYPE_BRANCHCC: + assert(Instruction->OperandCount == 1); + assert(Operand1->Flags & OP_ADDRESS); + assert(Operand1->Type == OPTYPE_OFFSET); + if (!(Operand1->Flags & (OP_GLOBAL|OP_FAR))) + { + assert(!X86Instruction->HasSelector); + X86Instruction->Segment = SEG_CS; + } + + if (Operand1->TargetAddress) + { + assert(!Instruction->CodeBranch.AddressOffset); + Instruction->CodeBranch.Count = 2; + Instruction->CodeBranch.Addresses[0] = Operand1->TargetAddress; + Instruction->CodeBranch.Addresses[1] = (U64)Instruction->Address + Instruction->Length; + Instruction->CodeBranch.Operand = Operand1; + } + break; + + case ITYPE_LOOPCC: + Instruction->CodeBranch.IsLoop = TRUE; + assert(Instruction->OperandCount == 1); + assert(Operand1->Flags & OP_ADDRESS); + assert(Operand1->Type == OPTYPE_OFFSET); + assert(!(Operand1->Flags & (OP_GLOBAL|OP_FAR))); + if (Operand1->TargetAddress) + { + assert(!Instruction->CodeBranch.AddressOffset); + Instruction->CodeBranch.Count = 2; + Instruction->CodeBranch.Addresses[0] = Operand1->TargetAddress; + Instruction->CodeBranch.Addresses[1] = (U64)Instruction->Address + Instruction->Length; + Instruction->CodeBranch.Operand = Operand1; + } + break; + + case ITYPE_RET: + Instruction->Groups |= ITYPE_STACK; + break; + + default: + break; // do nothing + } + } + else // possible data instruction + { + for (i = 0, Operand = Instruction->Operands; i < Instruction->OperandCount; i++, Operand++) + { + if (Operand->TargetAddress) + { + if (Operand->Flags & OP_DST) + { + assert(!Instruction->DataDst.Count); + Instruction->DataDst.Count = 1; + Instruction->DataDst.Addresses[0] = Operand->TargetAddress; + Instruction->DataDst.DataSize = Operand->Length; + Instruction->DataDst.Operand = Operand; + DISASM_OUTPUT(("[0x%08I64X] Write of size %d to 0x%04I64X\n", VIRTUAL_ADDRESS, Operand->Length, Operand->TargetAddress)); + } + if (Operand->Flags & OP_SRC) + { + assert(!Instruction->DataSrc.Count); + Instruction->DataSrc.Count = 1; + Instruction->DataSrc.Addresses[0] = Operand->TargetAddress; + Instruction->DataSrc.DataSize = Operand->Length; + Instruction->DataSrc.Operand = Operand; + DISASM_OUTPUT(("[0x%08I64X] Read of size %d to 0x%04I64X\n", VIRTUAL_ADDRESS, Operand->Length, Operand->TargetAddress)); + } + } + + // If there is both a base and index register, the Result will probably be too wrong + // to even guess + else if (Operand->Flags & OP_GLOBAL && + ((X86Instruction->HasBaseRegister && !X86Instruction->HasIndexRegister) || + (!X86Instruction->HasBaseRegister && X86Instruction->HasIndexRegister))) + { + DISASM_OUTPUT(("[0x%08I64X] Data reference (scale %d, size %d, displacement 0x%08I64x)\n", VIRTUAL_ADDRESS, X86Instruction->Scale, Operand->Length, X86Instruction->Displacement)); + if (!X86Instruction->Scale) + { + assert(Operand->Length <= 0xFF); + if (Operand->Length) X86Instruction->Scale = (U8)Operand->Length; + else X86Instruction->Scale = X86Instruction->OperandSize; + } + tmpScale = MAX(X86Instruction->Scale, Operand->Length); + + assert(X86Instruction->HasFullDisplacement); + if (Operand->Flags & OP_DST) + { + assert(!Instruction->DataDst.Count); + assert(tmpScale <= 16); + Instruction->CodeBranch.AddressOffset = (U8)tmpScale; + for (i = 0; i < MAX_DATA_REFERENCE_COUNT; i++) Instruction->DataDst.Addresses[i] = (U64)X86Instruction->Displacement + (i * tmpScale); + Instruction->DataDst.Count = i; + Instruction->DataDst.DataSize = Operand->Length; + Instruction->DataDst.Operand = Operand; + } + if (Operand->Flags & OP_SRC) + { + assert(!Instruction->DataSrc.Count); + assert(tmpScale <= 16); + Instruction->CodeBranch.AddressOffset = (U8)tmpScale; + for (i = 0; i < MAX_DATA_REFERENCE_COUNT; i++) Instruction->DataSrc.Addresses[i] = (U64)X86Instruction->Displacement + (i * tmpScale); + Instruction->DataSrc.Count = i; + Instruction->DataSrc.DataSize = Operand->Length; + Instruction->DataSrc.Operand = Operand; + } + } + } + } + + if (Instruction->Groups & ITYPE_STACK) + { + switch (Instruction->Type) + { + case ITYPE_PUSH: + assert(Instruction->OperandCount == 1 && Operand1->Length); + Instruction->StackChange = -Operand1->Length; + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_POP: + assert(Instruction->OperandCount == 1 && Operand1->Length); + Instruction->StackChange = Operand1->Length; + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_PUSHA: + Instruction->StackChange = -(X86Instruction->OperandSize * 8); // xAX, xCX, xDX, xBX, xBP, xSP, xSI, xDI + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_POPA: + Instruction->StackChange = X86Instruction->OperandSize * 8; // xDI, xSI, xSP, xBP, xBX, xDX, xCX, xAX + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_PUSHF: + Instruction->StackChange = -Operand1->Length; + Instruction->NeedsEmulation = TRUE; + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_POPF: + Instruction->StackChange = Operand1->Length; + Instruction->NeedsEmulation = TRUE; + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_ENTER: + if (!Instruction->AnomalyOccurred) + { + if (Instruction->Operands[1].Value_U64 & 3) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: ENTER has invalid operand 2\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + if (Instruction->Operands[2].Value_U64 & ~0x1F) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: ENTER has invalid operand 3\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + } + SANITY_CHECK_ADDRESS_SIZE(); + Instruction->Operands[2].Value_U64 &= 0x1F; + + // frame pointer + stack space + i = Operand1->Length + (U32)Instruction->Operands[1].Value_U64; + Instruction->StackChange = -((LONG)i); + i = (U32)Instruction->Operands[2].Value_U64 * Operand1->Length; + Instruction->StackChange -= i; + break; + + case ITYPE_LEAVE: + // This will do "mov esp, ebp; pop ebp" so the StackChange size is dynamic + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_CALL: + Instruction->StackChange = -X86Instruction->OperandSize; + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_RET: + Instruction->StackChange = X86Instruction->OperandSize; + + switch (Opcode) + { + case 0xC3: // ret with no args + break; + + case 0xC2: // ret with 1 arg + if (!Instruction->AnomalyOccurred && (Operand1->Value_U64 & 3)) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: ret has invalid operand 1\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + Instruction->StackChange += (LONG)Operand1->Value_U64; + break; + + case 0xCB: // far ret with no args + Instruction->StackChange *= 2; // account for segment + Instruction->StackChange += (LONG)Operand1->Value_U64; + break; + + case 0xCA: // far ret with 1 arg + if (!Instruction->AnomalyOccurred && (Operand1->Value_U64 & 3)) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: retf has invalid operand 1\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + Instruction->StackChange *= 2; // account for segment + Instruction->StackChange += (LONG)Operand1->Value_U64; + break; + } + SANITY_CHECK_ADDRESS_SIZE(); + break; + + case ITYPE_ADD: + case ITYPE_XCHGADD: + if (Instruction->Operands[1].Value_S64) Instruction->StackChange = (LONG)(Instruction->Operands[1].Value_S64); + break; + case ITYPE_SUB: + if (Instruction->Operands[1].Value_S64) Instruction->StackChange = (LONG)(-Instruction->Operands[1].Value_S64); + break; + case ITYPE_MOV: + case ITYPE_AND: + break; + + default: + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Instruction \"%s\" is modifying the stack\n", VIRTUAL_ADDRESS, X86Opcode->Mnemonic); + Instruction->AnomalyOccurred = TRUE; + } + break; + } + + if (!Instruction->AnomalyOccurred && + ((X86Instruction->OperandSize != 2 && (Instruction->StackChange & 3)) || (Instruction->StackChange & 1))) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: \"%s\" has invalid stack change 0x%02X\n", VIRTUAL_ADDRESS, X86Opcode->Mnemonic, Instruction->StackChange); + Instruction->AnomalyOccurred = TRUE; + } + } + + if (Instruction->Groups & ITYPE_TRAPS) + { + switch (Instruction->Type) + { + case ITYPE_TRAP: + case ITYPE_TRAPCC: + case ITYPE_TRAPRET: + case ITYPE_BOUNDS: + case ITYPE_DEBUG: + case ITYPE_TRACE: + case ITYPE_INVALID: + case ITYPE_OFLOW: + Instruction->NeedsEmulation = TRUE; + break; + default: + assert(0); + break; + } + } + + if (Instruction->Groups & ITYPE_SYSTEM) + { + switch (Instruction->Type) + { + case ITYPE_CPUID: + case ITYPE_SYSCALL: + case ITYPE_SYSCALLRET: + // This doesn't require privileges + break; + + case ITYPE_HALT: + case ITYPE_IN: + case ITYPE_OUT: + default: + Instruction->NeedsEmulation = TRUE; + break; + } + } + + Disassembler->Stage3CountWithDecode++; + return TRUE; + +abort: + if (!SuppressErrors) + { +#ifdef TEST_DISASM + printf("Dump of 0x%04I64X:\n", VIRTUAL_ADDRESS); + __try { DumpAsBytes(stdout, Instruction->Address, (ULONG_PTR)VIRTUAL_ADDRESS, 16, TRUE); } + __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {} +#endif + fflush(stdout); + } + return FALSE; +} + +// Address = address to first byte after the opcode (e.g., first byte of ModR/M byte or +// immediate value +// +// Returns the address immediately following the operand (e.g., the next operand or the +// start of the next instruction +INTERNAL U8 *SetOperands(INSTRUCTION *Instruction, U8 *Address, U32 Flags) +{ + INSTRUCTION_OPERAND *Operand; + U32 Index, OperandIndex; + S64 Displacement = 0; + U8 Register; + U32 OperandFlags, OperandType, AddressMode, Segment; + U8 Opcode; + MODRM modrm; + REX rex; + REX_MODRM rex_modrm; + X86_OPCODE *X86Opcode; + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + BOOL Decode = Flags & DISASM_DECODE; + BOOL Disassemble = Flags & DISASM_DISASSEMBLE; + BOOL SuppressErrors = Flags & DISASM_SUPPRESSERRORS; + + Opcode = Instruction->LastOpcode; + X86Opcode = &X86Instruction->Opcode; + + // Setup Mod R/M byte + if (X86Instruction->HasModRM) + { + SET_MODRM(X86Instruction->modrm, X86Instruction->modrm_b); + modrm = X86Instruction->modrm; + rex = X86Instruction->rex; + SET_REX_MODRM(X86Instruction->rex_modrm, rex, modrm); + rex_modrm = X86Instruction->rex_modrm; + //DISASM_OUTPUT(("[0x%08I64X] ModRM = 0x%02X (mod=%d, reg=%d, rm=%d)\n", VIRTUAL_ADDRESS, X86Instruction->modrm_b, modrm.mod, rex_modrm.reg, rex_modrm.rm)); + INSTR_INC(1); // increment Instruction->Length and address + } + else + { + // initialize them to 0 + modrm = X86Instruction->modrm; + rex = X86Instruction->rex; + rex_modrm = X86Instruction->rex_modrm; + } + + for (OperandIndex = 0; OperandIndex < Instruction->OperandCount; OperandIndex++) + { + Operand = &Instruction->Operands[OperandIndex]; + assert(!(Operand->Flags & 0x7F)); + + OperandFlags = X86Opcode->OperandFlags[OperandIndex] & X86_OPFLAGS_MASK; + OperandType = X86Opcode->OperandFlags[OperandIndex] & X86_OPTYPE_MASK; + AddressMode = X86Opcode->OperandFlags[OperandIndex] & X86_AMODE_MASK; + if (Decode && OperandIndex != 0) APPENDS(", "); + + switch (OperandType) + { + //////////////////////////////////////////////////////////// + // Special operand types with no associated addressing mode + //////////////////////////////////////////////////////////// + + case OPTYPE_0: + if (!Decode) continue; + Operand->Value_U64 = 0; + Operand->Type = OPTYPE_IMM; + //DISASM_OUTPUT(("[SetOperand] const 0\n")); + if (Disassemble) + { + APPENDS("<0>"); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_1: + if (!Decode) continue; + Operand->Value_U64 = 1; + Operand->Type = OPTYPE_IMM; + //DISASM_OUTPUT(("[SetOperand] const 1\n")); + if (Disassemble) + { + APPENDS("<1>"); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FF: + if (!Decode) continue; + Operand->Value_U64 = 0xFF; + Operand->Type = OPTYPE_IMM; + //DISASM_OUTPUT(("[SetOperand] const 0xff\n")); + if (Disassemble) + { + APPENDS("<0xFF>"); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_TSC: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] TSC\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_CS_MSR: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] CS MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_EIP_MSR: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] EIP MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_ESP_MSR: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] ESP MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_KERNELBASE_MSR: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] KernelBase MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_STAR_MSR: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] KernelBase MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_CSTAR_MSR: + assert(!IS_AMD64()); + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] CSTAR MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_LSTAR_MSR: + assert(IS_AMD64()); + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] LSTAR MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FMASK_MSR: + if (!Decode) continue; + Operand->Length = 8; + Operand->Type = OPTYPE_SPECIAL; + //DISASM_OUTPUT(("[SetOperand] FMASK MSR\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OP_REG: + if (!Decode) continue; + // The reg field is included in the opcode + Operand->Length = X86Instruction->OperandSize; + Register = X86_GET_REG64(Opcode); + switch (X86Instruction->OperandSize) + { + case 8: + Operand->Register = AMD64_64BIT_OFFSET + Register; + break; + case 4: + Operand->Register = X86_32BIT_OFFSET + Register; + CHECK_AMD64_REG(); + break; + case 2: + Operand->Register = X86_16BIT_OFFSET + Register; + CHECK_AMD64_REG(); + break; + case 1: + Operand->Register = X86_8BIT_OFFSET + Register; + if (X86Instruction->rex_b) CHECK_AMD64_REG(); + break; + default: + assert(0); + return NULL; + } + X86_SET_REG(Register); + + //DISASM_OUTPUT(("[SetOperand] OP_REG %s\n", X86_Registers[Operand->Register])); + if (Disassemble) + { + APPENDB('<'); APPENDS(X86_Registers[Operand->Register]); APPENDB('>'); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_REG8: + if (!Decode) continue; + // The reg field is included in the opcode + Operand->Length = 1; + Register = X86_GET_REG64(Opcode); + Operand->Register = X86_8BIT_OFFSET + Register; + CHECK_AMD64_REG(); + X86_SET_REG(Register); + + //DISASM_OUTPUT(("[SetOperand] OP_REG %s\n", X86_Registers[Operand->Register])); + if (Disassemble) + { + APPENDB('<'); APPENDS(X86_Registers[Operand->Register]); APPENDB('>'); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_REG_AL: + if (!Decode) continue; + Operand->Length = 1; + Operand->Register = X86_REG_AL; + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] reg AL\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_REG_CL: + if (!Decode) continue; + Operand->Length = 1; + Operand->Register = X86_REG_CL; + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] reg CL\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_REG_AH: + if (!Decode) continue; + Operand->Length = 1; + Operand->Register = X86_REG_AH; + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] reg AH\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_REG_AX: + if (!Decode) continue; + Operand->Length = 2; + Operand->Register = X86_REG_AX; + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] reg AX\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_REG_DX: + if (!Decode) continue; + Operand->Length = 2; + Operand->Register = X86_REG_DX; + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] reg DX\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_REG_ECX: + if (!Decode) continue; + Operand->Length = 4; + Operand->Register = X86_REG_ECX; + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] reg ECX\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_REG_xBP: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize; + switch (X86Instruction->OperandSize) + { + case 8: Operand->Register = AMD64_REG_RBP; break; + case 4: Operand->Register = X86_REG_EBP; break; + case 2: Operand->Register = X86_REG_BP; break; + default: assert(0); return NULL; + } + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] xAX_BIG (size = %d)\n", Operand->Length)); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_REG_xAX_BIG: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize; + switch (X86Instruction->OperandSize) + { + case 8: Operand->Register = AMD64_REG_RAX; break; + case 4: Operand->Register = X86_REG_EAX; break; + case 2: Operand->Register = X86_REG_AX; break; + default: assert(0); return NULL; + } + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] xAX_BIG (size = %d)\n", Operand->Length)); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_REG_xAX_SMALL: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize >> 1; + switch (X86Instruction->OperandSize) + { + case 8: Operand->Register = X86_REG_EAX; break; + case 4: Operand->Register = X86_REG_AX; break; + case 2: Operand->Register = X86_REG_AL; break; + default: assert(0); return NULL; + } + X86_SET_REG(0); + //DISASM_OUTPUT(("[SetOperand] xAX_SMALL (size = %d)\n", Operand->Length)); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_xCX_HI_xBX_LO: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize << 1; + if (Disassemble) + { + switch (X86Instruction->OperandSize) + { + case 8: APPENDS(""); break; + case 4: APPENDS(""); break; + case 2: APPENDS(""); break; + default: assert(0); return NULL; + } + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] xCX_BIG:xBX_BIG (size = %d)\n", Operand->Length)); + continue; + case OPTYPE_xDX_HI_xAX_LO: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize << 1; + if (Disassemble) + { + switch (X86Instruction->OperandSize) + { + case 8: APPENDS(""); break; + case 4: APPENDS(""); break; + case 2: APPENDS(""); break; + default: assert(0); return NULL; + } + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] xDX_BIG:xAX_BIG (size = %d)\n", Operand->Length)); + continue; + + case OPTYPE_EDX_HI_EAX_LO: + if (!Decode) continue; + Operand->Length = 8; + //DISASM_OUTPUT(("[SetOperand] EDX:EAX\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_EDX_ECX_EBX_EAX: + Operand->Length = 32; + //DISASM_OUTPUT(("[SetOperand] EDX:ECX:EBX:EAX\n")); + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_FLAGS: + if (!Decode) continue; + Operand->Length = 2; + Operand->Flags |= OP_REG; + Operand->Register = X86_REG_FLAGS; + //DISASM_OUTPUT(("[SetOperand] reg FLAGS\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_xFLAGS: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize; + Operand->Flags |= OP_REG; + switch (X86Instruction->OperandSize) + { + case 8: Operand->Register = AMD64_REG_RFLAGS; break; + case 4: Operand->Register = X86_REG_EFLAGS; break; + case 2: Operand->Register = X86_REG_FLAGS; break; + default: assert(0); return NULL; + } + //DISASM_OUTPUT(("[SetOperand] reg xFLAGS (size = %d)\n", Operand->Length)); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_CS: + if (!Decode) continue; + if (Instruction->Type != ITYPE_PUSH && Instruction->Type != ITYPE_POP) Operand->Length = 2; + else Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_SEG_CS; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] seg CS\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_DS: + if (!Decode) continue; + if (Instruction->Type != ITYPE_PUSH && Instruction->Type != ITYPE_POP) Operand->Length = 2; + else Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_SEG_DS; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] seg DS\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_ES: + if (!Decode) continue; + if (Instruction->Type != ITYPE_PUSH && Instruction->Type != ITYPE_POP) Operand->Length = 2; + else Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_SEG_ES; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] seg ES\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FS: + if (!Decode) continue; + if (Instruction->Type != ITYPE_PUSH && Instruction->Type != ITYPE_POP) Operand->Length = 2; + else Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_SEG_FS; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] seg FS\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_GS: + if (!Decode) continue; + if (Instruction->Type != ITYPE_PUSH && Instruction->Type != ITYPE_POP) Operand->Length = 2; + else Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_SEG_GS; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] seg GS\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_SS: + if (!Decode) continue; + if (Instruction->Type != ITYPE_PUSH && Instruction->Type != ITYPE_POP) Operand->Length = 2; + else Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_SEG_SS; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] seg SS\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_CR0: + if (!Decode) continue; + Operand->Length = X86Instruction->OperandSize; + Operand->Register = X86_REG_CR0; + Operand->Flags |= OP_REG; + //DISASM_OUTPUT(("[SetOperand] reg CR0\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_STx: + if (!Decode) continue; + Operand->Length = 10; + Operand->Type = OPTYPE_FLOAT; + Operand->Flags |= OP_REG; + Register = X86_GET_REG(X86Instruction->modrm_b); + Operand->Register = X86_FPU_OFFSET + Register; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_STx: reg st(%d)\n", Register)); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_ST0: + if (!Decode) continue; + Operand->Length = 10; + Operand->Type = OPTYPE_FLOAT; + Operand->Flags |= OP_REG; + Operand->Register = X86_REG_ST0; + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_ST1: + if (!Decode) continue; + Operand->Length = 10; + Operand->Type = OPTYPE_FLOAT; + Operand->Flags |= OP_REG; + Operand->Register = X86_REG_ST1; + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "<%s>", X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_FPU_STATUS: + if (!Decode) continue; + Operand->Length = 2; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_FPU_CONTROL: + if (!Decode) continue; + Operand->Length = 2; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_FPU_TAG: + if (!Decode) continue; + Operand->Length = 2; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + case OPTYPE_FLDZ: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS("<0.0>"); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FLD1: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS("<1.0>"); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FLDPI: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FLDL2T: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FLDL2E: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FLDLG2: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + case OPTYPE_FLDLN2: + if (!Decode) continue; + Operand->Type = OPTYPE_FLOAT; + Operand->Length = 10; + if (Disassemble) + { + APPENDS(""); + X86_WRITE_OPFLAGS(); + } + continue; + + //////////////////////////////////////////////////////////// + // Fixed sizes regardless of operand size + //////////////////////////////////////////////////////////// + + case OPTYPE_b: // byte regardless of operand size + Operand->Length = 1; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_b (size 1, signed %d)\n", ((OperandFlags & OP_SIGNED) != 0))); + break; + + case OPTYPE_w: // word regardless of operand size + Operand->Length = 2; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_w (size 2)\n")); + break; + + case OPTYPE_d: // dword regardless of operand size + Operand->Length = 4; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_d (size 4)\n")); + break; + + case OPTYPE_q: // qword regardless of operand size + Operand->Length = 8; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_q (size 8)\n")); + break; + + case OPTYPE_o: // oword regardless of operand size + Operand->Length = 16; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_o (size 16)\n")); + break; + + case OPTYPE_dt: // 6-byte or 10-byte pseudo descriptor (sgdt, lgdt, sidt, lidt) + if (IS_AMD64()) Operand->Length = 10; + else Operand->Length = 6; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_dt (%d bytes)\n", Operand->Length)); + break; + + case OPTYPE_cpu: + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Undocumented loadall instruction?\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + Operand->Length = 204; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_cpu (size 204)\n")); + break; + + //////////////////////////////////////////////////////////// + // Sizes depending on the operand size + //////////////////////////////////////////////////////////// + + case OPTYPE_z: // word if operand size is 16 bits and dword otherwise + switch (X86Instruction->OperandSize) + { + case 8: case 4: Operand->Length = 4; break; + case 2: Operand->Length = 2; break; + default: assert(0); return NULL; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_z (length %d)\n", Operand->Length)); + break; + + case OPTYPE_v: // word, dword, or qword + Operand->Length = X86Instruction->OperandSize; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_v (size %d, signed = %d)\n", Operand->Length, ((OperandFlags & OP_SIGNED) != 0))); + break; + + case OPTYPE_a: // two word or dword operands in memory (used only by bound) + assert(Instruction->OpcodeBytes[0] == X86_BOUND); + switch (X86Instruction->OperandSize) + { + case 8: case 4: Operand->Length = 8; break; + case 2: Operand->Length = 4; break; + default: assert(0); return NULL; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_a (size %d)\n", Operand->Length)); + break; + + case OPTYPE_p: // 32-bit or 48-bit pointer depending on operand size + if (!Instruction->AnomalyOccurred && X86Instruction->HasSegmentOverridePrefix) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Segment override used when segment is explicit\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + switch (X86Instruction->OperandSize) + { + case 8: case 4: Operand->Length = 6; break; + case 2: Operand->Length = 4; break; + default: assert(0); return NULL; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_p (length %d)\n", Operand->Length)); + break; + + case OPTYPE_dq: // dword or qword + //DISASM_OUTPUT(("[SetOperand] OPTYPE_dq (size 4 or 8)\n")); + switch (X86Instruction->OperandSize) + { + case 8: Operand->Length = 8; break; + case 4: case 2: Operand->Length = 4; break; + default: assert(0); return NULL; + } + break; + + case OPTYPE_mw: // a word if the destination operand is memory + //DISASM_OUTPUT(("[SetOperand] OPTYPE_mw (size 0)\n")); + assert(X86Instruction->HasModRM); + if (modrm.mod == 3) Operand->Length = X86Instruction->OperandSize; // using register + else Operand->Length = 2; // using memory + break; + + case OPTYPE_lea: + //DISASM_OUTPUT(("[SetOperand] OPTYPE_lea (size 0)\n")); + assert(OperandIndex == 1); + Operand->Length = Instruction->Operands[0].Length; + break; + + //////////////////////////////////////////////////////////// + // FPU types + //////////////////////////////////////////////////////////// + + case OPTYPE_ps: // packed single real + Operand->Length = 4; + Operand->Type = OPTYPE_FLOAT; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_ps (packed single real)\n")); + break; + case OPTYPE_pd: // packed double real + Operand->Length = 8; + Operand->Type = OPTYPE_FLOAT; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_pd (packed double real)\n")); + break; + case OPTYPE_pb: // packed BCD + Operand->Length = 10; + Operand->Type = OPTYPE_BCD; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_pb (packed BCD)\n")); + break; + case OPTYPE_ss: // scalar single real + Operand->Length = 4; + Operand->Type = OPTYPE_FLOAT; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_ss (single real)\n")); + break; + case OPTYPE_sd: // scalar double real + Operand->Length = 8; + Operand->Type = OPTYPE_FLOAT; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_sd (double real)\n")); + break; + case OPTYPE_se: // extended real + Operand->Length = 10; + Operand->Type = OPTYPE_FLOAT; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_se (extended real)\n")); + break; + + case OPTYPE_fev: // FPU environment (28 bytes in 32-bit modes, 14 bytes in 16-bit real mode) + switch (X86Instruction->OperandSize) + { + case 8: case 4: Operand->Length = 28; break; + case 2: Operand->Length = 14; break; + default: assert(0); return NULL; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_fev (FPU environment, length %d)\n", Operand->Length)); + break; + + case OPTYPE_fst1: // FPU state (108 bytes in 32-bit modes, 94 bytes in 16-bit real mode) + switch (X86Instruction->OperandSize) + { + case 8: case 4: Operand->Length = 108; break; + case 2: Operand->Length = 94; break; + default: assert(0); return NULL; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_fst1 (FPU state, length %d)\n", Operand->Length)); + break; + + case OPTYPE_fst2: // 512 bytes for FPU state (FPU + MMX + XXM + MXCSR) + Operand->Length = 512; + //DISASM_OUTPUT(("[SetOperand] OPTYPE_fst2 (FPU + MMX + XXM + MXCSR state, length 512)\n")); + break; + + case OPTYPE_sso: + if (modrm.mod == 3) // from register + { + Operand->Length = 16; + } + else // from memory + { + Operand->Length = 4; + Operand->Type = OPTYPE_FLOAT; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_sso (single real or oword)\n")); + break; + + case OPTYPE_sdo: + if (modrm.mod == 3) // from register + { + Operand->Length = 16; + } + else // from memory + { + Operand->Length = 8; + Operand->Type = OPTYPE_FLOAT; + } + //DISASM_OUTPUT(("[SetOperand] OPTYPE_sso (double real or oword)\n")); + break; + + default: + assert(0); + return NULL; + } + + switch (AddressMode) + { + //////////////////////////////////////////////////////////// + // Special types + //////////////////////////////////////////////////////////// + + case AMODE_xlat: // DS:[EBX+AL] + if (!Decode) continue; + assert(Operand->Length == 1); + Operand->Flags |= OP_ADDRESS | OP_REG; + Operand->Type = OPTYPE_STRING; + + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_REG_RBX; break; + case 4: Operand->Register = X86_REG_EBX; break; + case 2: Operand->Register = X86_REG_BX; break; + default: assert(0); return NULL; + } + X86_SET_ADDR(); + X86Instruction->Scale = 1; + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + X86Instruction->IndexRegister = X86_REG_AL; + X86Instruction->HasIndexRegister = TRUE; + + //DISASM_OUTPUT(("[SetOperand] AMODE_xlat (DS:[EBX+AL])\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "%s:[%s]", + Segments[X86Instruction->Segment], X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + //////////////////////////////////////////////////////////// + // Without mod R/M byte + //////////////////////////////////////////////////////////// + + case AMODE_I: // immediate value + if (Decode) + { + Operand->Type = OPTYPE_IMM; + switch (Operand->Length) + { + case 8: + if (OperandFlags & OP_SIGNED) Operand->Value_S64 = (S64)*((S64 *)Address); + else Operand->Value_U64 = (U64)*((U64 *)Address); + break; + case 4: + if (!(OperandFlags & OP_SIGNED) && OperandIndex == 1 && + (Instruction->Operands[0].Flags & (OP_REG|OP_ADDRESS)) && + Instruction->Operands[0].Length == 8) + { + // For some opcodes the second operand is a sign-extended imm32 value + assert(X86Instruction->OperandSize == 8); + switch (Instruction->Type) + { + case ITYPE_AND: + case ITYPE_ADD: + case ITYPE_XCHGADD: + case ITYPE_CMP: + case ITYPE_MOV: + case ITYPE_SUB: + case ITYPE_TEST: + case ITYPE_OR: + case ITYPE_XOR: + assert(OperandIndex == 1); + Operand->Value_S64 = (S64)*((S32 *)Address); + break; + default: + assert(0); + if (OperandFlags & OP_SIGNED) Operand->Value_S64 = (S64)*((S32 *)Address); + else Operand->Value_U64 = (U64)*((U32 *)Address); + break; + } + } + else + { + if (OperandFlags & OP_SIGNED) Operand->Value_S64 = (S64)*((S32 *)Address); + else Operand->Value_U64 = (U64)*((U32 *)Address); + } + break; + case 2: + if (OperandFlags & OP_SIGNED) Operand->Value_S64 = (S64)*((S16 *)Address); + else Operand->Value_U64 = (U64)*((U16 *)Address); + break; + case 1: + if (OperandFlags & OP_SIGNED) Operand->Value_S64 = (S64)*((S8 *)Address); + else Operand->Value_U64 = (U64)*((U8 *)Address); + break; + default: + assert(0); + return NULL; + } + } + INSTR_INC(Operand->Length); // increment Instruction->Length and address + assert(X86Instruction->OperandSize >= Operand->Length); + if (Instruction->Type == ITYPE_PUSH) Operand->Length = X86Instruction->OperandSize; + + //DISASM_OUTPUT(("[SetOperand] AMODE_I (immediate data)\n")); + if (Disassemble) + { + X86_WRITE_IMMEDIATE(); + X86_WRITE_OPFLAGS(); + } + continue; + + case AMODE_J: // IP-relative jump offset + SANITY_CHECK_ADDRESS_SIZE(); + if (Decode) + { + Operand->Flags |= OP_IPREL | OP_SIGNED | OP_REG | OP_ADDRESS; + Operand->Type = OPTYPE_OFFSET; + switch (X86Instruction->OperandSize) + { + case 8: Operand->Register = AMD64_REG_RIP; break; + case 4: Operand->Register = X86_REG_EIP; break; + case 2: Operand->Register = X86_REG_IP; break; + default: assert(0); return NULL; + } + switch (Operand->Length) + { + case 8: X86Instruction->Displacement = *((S64 *)Address); break; + case 4: X86Instruction->Displacement = (S64)*((S32 *)Address); break; + case 2: X86Instruction->Displacement = (S64)*((S16 *)Address); break; + case 1: X86Instruction->Displacement = (S64)*((S8 *)Address); break; + default: assert(0); return NULL; + } + + Operand->Value_S64 = X86Instruction->Displacement; + X86Instruction->Relative = TRUE; + + if ((Operand->Flags & OP_COND) && !X86Instruction->Displacement) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Both conditions of branch go to same address\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + } + + INSTR_INC(Operand->Length); // increment Instruction->Length and address + if (!Decode) continue; + + assert((Operand->Flags & OP_EXEC) && (Instruction->Groups & ITYPE_EXEC)); + Operand->TargetAddress = ApplyDisplacement((U64)Address, Instruction); + X86Instruction->Relative = TRUE; + X86_SET_ADDR(); + SANITY_CHECK_SEGMENT_OVERRIDE(); + X86Instruction->HasSegmentOverridePrefix = FALSE; + X86Instruction->Segment = SEG_CS; + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + assert(Instruction->OperandCount == 1); + //DISASM_OUTPUT(("[SetOperand] AMODE_J (branch with relative offset)\n")); + if (Disassemble) + { + X86_WRITE_IP_OFFSET(Operand); + X86_WRITE_OPFLAGS(); + } + continue; + + case AMODE_O: // word/dword offset + Operand->Type = OPTYPE_OFFSET; + Operand->Flags |= OP_ADDRESS; + SANITY_CHECK_OPERAND_SIZE(); + switch (X86Instruction->AddressSize) + { + case 8: + if (Operand->Flags & OP_SIGNED) X86Instruction->Displacement = *((S64 *)Address); + else X86Instruction->Displacement = (S64)*((U64 *)Address); + break; + case 4: + if (Operand->Flags & OP_SIGNED) X86Instruction->Displacement = (S64)*((S32 *)Address); + else X86Instruction->Displacement = (S64)*((U32 *)Address); + break; + case 2: + if (Operand->Flags & OP_SIGNED) X86Instruction->Displacement = (S64)*((S16 *)Address); + else X86Instruction->Displacement = (S64)*((U16 *)Address); + break; + default: + assert(0); + return FALSE; + } + + INSTR_INC(X86Instruction->AddressSize); // increment Instruction->Length and address + if (!Decode) continue; + + X86Instruction->HasFullDisplacement = TRUE; + X86_SET_ADDR(); + X86_SET_TARGET(); + assert(X86Instruction->Segment == SEG_DS || X86Instruction->HasSegmentOverridePrefix); + //DISASM_OUTPUT(("[SetOperand] AMODE_O (offset)\n")); + if (Disassemble) + { + X86_WRITE_OFFSET(Operand); + X86_WRITE_OPFLAGS(); + } + continue; + + case AMODE_A: // absolute address + Operand->Flags |= OP_ADDRESS | OP_FAR; + SANITY_CHECK_ADDRESS_SIZE(); + SANITY_CHECK_SEGMENT_OVERRIDE(); + X86Instruction->HasSelector = TRUE; + X86Instruction->HasSegmentOverridePrefix = FALSE; + switch (Operand->Length) + { + case 6: + X86Instruction->Segment = *((U16 *)Address); INSTR_INC(2); + X86Instruction->Displacement = (S64)*((S32 *)Address); INSTR_INC(4); + break; + case 4: + X86Instruction->Segment = *((U16 *)Address); INSTR_INC(2); + X86Instruction->Displacement = (S64)*((S16 *)Address); INSTR_INC(2); + break; + default: + assert(0); + return FALSE; + } + if (!Decode) continue; + X86Instruction->HasFullDisplacement = TRUE; + X86_SET_ADDR(); + X86_SET_TARGET(); + //DISASM_OUTPUT(("[SetOperand] AMODE_A (absolute address)\n")); + if (Disassemble) + { + X86_WRITE_OFFSET(Operand); + X86_WRITE_OPFLAGS(); + } + continue; + + case AMODE_X: // DS:[ESI] + if (!Decode) continue; + Operand->Flags |= OP_ADDRESS | OP_REG; + Operand->Type = OPTYPE_STRING; + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_REG_RSI; break; + case 4: Operand->Register = X86_REG_ESI; break; + case 2: Operand->Register = X86_REG_SI; break; + default: assert(0); return NULL; + } + + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + X86_SET_ADDR(); + if (!X86Instruction->HasSegmentOverridePrefix) X86Instruction->Segment = SEG_DS; + + //DISASM_OUTPUT(("[SetOperand] AMODE_X (addressing via DS:[ESI])\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "%s:[%s]", + Segments[X86Instruction->Segment], X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + case AMODE_Y: // ES:[EDI] + if (!Decode) continue; + Operand->Flags |= OP_ADDRESS | OP_REG; + Operand->Type = OPTYPE_STRING; + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_REG_RDI; break; + case 4: Operand->Register = X86_REG_EDI; break; + case 2: Operand->Register = X86_REG_DI; break; + default: assert(0); return NULL; + } + + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + X86_SET_ADDR(); + if (X86Instruction->HasSegmentOverridePrefix) + { + if (!Instruction->AnomalyOccurred) + { + if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: segment override used with AMODE_Y\n", VIRTUAL_ADDRESS); + Instruction->AnomalyOccurred = TRUE; + } + Segment = X86Instruction->DstSegment = SEG_ES; + X86Instruction->HasDstSegment = TRUE; + } + else + { + Segment = X86Instruction->Segment = SEG_ES; + } + + //DISASM_OUTPUT(("[SetOperand] AMODE_Y (addressing via ES:[EDI])\n")); + if (Disassemble) + { + APPEND(OPCSTR, SIZE_LEFT, "%s:[%s]", + Segments[Segment], X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + continue; + + //////////////////////////////////////////////////////////// + // Mod R/M byte with only registers + // Handle that case here since it is straightforward + //////////////////////////////////////////////////////////// + + case AMODE_PR: // modrm.rm = mmx register and modrm.mod = 11 + assert(X86Instruction->HasModRM); + if (modrm.mod != 3) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: mod != 3 for AMODE_PR (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + else if (rex_modrm.rm > 7) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: invalid mmx register %d for AMODE_PR (\"%s\")\n", VIRTUAL_ADDRESS, rex_modrm.rm, X86Instruction->Opcode.Mnemonic); + goto abort; + } + else if (X86Instruction->OperandSize == 2) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: AMODE_PR illegal in 16-bit mode (\"%s\")\n", VIRTUAL_ADDRESS, rex_modrm.rm, X86Instruction->Opcode.Mnemonic); + goto abort; + } + if (!Decode) continue; + + Operand->Flags |= OP_REG; + Operand->Register = X86_MMX_OFFSET + rex_modrm.rm; + X86_SET_REG(0); + + if (Disassemble) + { + assert(X86_Registers[Operand->Register]); + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_PR (MMX register)\n")); + continue; + + case AMODE_VR: // modrm.rm = xmm register and modrm.mod = 11 + assert(X86Instruction->HasModRM); + if (modrm.mod != 3) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: mod != 3 for AMODE_VR (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + else if (X86Instruction->OperandSize == 2) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: AMODE_VR illegal in 16-bit mode (\"%s\")\n", VIRTUAL_ADDRESS, rex_modrm.rm, X86Instruction->Opcode.Mnemonic); + goto abort; + } + if (!Decode) continue; + + Operand->Flags |= OP_REG; + Operand->Register = X86_XMM_OFFSET + rex_modrm.rm; + X86_SET_REG(0); + + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_VR (XMM register)\n")); + continue; + + case AMODE_P: // modrm.reg = mmx register + assert(X86Instruction->HasModRM); + if (rex_modrm.reg > 7) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: invalid mmx register %d for AMODE_P (\"%s\")\n", VIRTUAL_ADDRESS, rex_modrm.reg, X86Instruction->Opcode.Mnemonic); + goto abort; + } + else if (X86Instruction->OperandSize == 2) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: AMODE_P illegal in 16-bit mode (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + if (!Decode) continue; + + Operand->Flags |= OP_REG; + Operand->Register = X86_MMX_OFFSET + rex_modrm.reg; + X86_SET_REG(0); + + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_P (MMX register)\n")); + continue; + + case AMODE_V: // modrm.reg = xmm register + assert(X86Instruction->HasModRM); + if (X86Instruction->OperandSize == 2) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: AMODE_P illegal in 16-bit mode (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + if (!Decode) continue; + + Operand->Flags |= OP_REG; + Operand->Register = X86_XMM_OFFSET + rex_modrm.reg; break; + X86_SET_REG(0); + + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_V (XMM register)\n")); + continue; + + case AMODE_R: // modrm.rm is general register and modrm.mod = 11 + assert(X86Instruction->HasModRM); + if (modrm.mod != 3) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: mod != 3 for AMODE_R (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + if (!Decode) continue; + Operand->Flags |= OP_REG; + switch (Operand->Length) + { + case 8: Operand->Register = AMD64_64BIT_OFFSET + rex_modrm.rm; break; + case 4: Operand->Register = X86_32BIT_OFFSET, rex_modrm.rm; CHECK_AMD64_REG(); break; + case 2: Operand->Register = X86_16BIT_OFFSET, rex_modrm.rm; CHECK_AMD64_REG(); break; + case 1: Operand->Register = X86_8BIT_OFFSET, rex_modrm.rm; if (X86Instruction->rex_b) CHECK_AMD64_REG(); break; + default: assert(0); return NULL; + } + X86_SET_REG(rex_modrm.rm); + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_R (general register)\n")); + continue; + + case AMODE_G: // modrm.reg = general register + assert(X86Instruction->HasModRM); + if (!Decode) continue; + Operand->Flags |= OP_REG; + switch (Operand->Length) + { + case 8: Operand->Register = AMD64_64BIT_OFFSET + rex_modrm.reg; break; + case 4: Operand->Register = X86_32BIT_OFFSET + rex_modrm.reg; CHECK_AMD64_REG(); break; + case 2: Operand->Register = X86_16BIT_OFFSET + rex_modrm.reg; CHECK_AMD64_REG(); break; + case 1: Operand->Register = X86_8BIT_OFFSET + rex_modrm.reg; if (X86Instruction->rex_b) CHECK_AMD64_REG(); break; + default: assert(0); return NULL; + } + X86_SET_REG(rex_modrm.reg); + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_G (general register)\n")); + continue; + + case AMODE_S: // modrm.reg = segment register + assert(X86Instruction->HasModRM); + if (!Decode) continue; + Operand->Flags |= OP_REG; + switch (X86Instruction->OperandSize) + { + case 8: + case 4: + case 2: + if (rex_modrm.reg <= 5) Operand->Register = X86_SEGMENT_OFFSET + rex_modrm.reg; + break; + default: + assert(0); + return NULL; + } + + X86_SET_REG(0); + if (Disassemble) + { + if (rex_modrm.reg > 5) APPEND(OPCSTR, SIZE_LEFT, "seg_%02X", rex_modrm.reg); + else APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_S (segment register)\n")); + continue; + + case AMODE_T: // modrm.reg = test register + assert(X86Instruction->HasModRM); + if (!Decode) continue; + Instruction->Groups |= ITYPE_SYSTEM; + Instruction->NeedsEmulation = TRUE; + Operand->Flags |= OP_REG; + switch (X86Instruction->OperandSize) + { + case 8: + case 4: + case 2: + Operand->Register = X86_TEST_OFFSET + rex_modrm.reg; + break; + default: + assert(0); + return NULL; + } + + X86_SET_REG(0); + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_T (test register)\n")); + continue; + + case AMODE_C: // modrm.reg = control register + assert(X86Instruction->HasModRM); + assert(Instruction->Type == ITYPE_MOV); + if (!Decode) continue; + Instruction->Groups |= ITYPE_SYSTEM; + Instruction->NeedsEmulation = TRUE; + Operand->Flags |= OP_REG; + if (IS_AMD64()) X86Instruction->OperandSize = 8; + switch (X86Instruction->OperandSize) + { + case 8: + case 4: + case 2: + Operand->Register = X86_CONTROL_OFFSET + rex_modrm.reg; + break; + default: + assert(0); + return NULL; + } + + X86_SET_REG(0); + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_C (control register)\n")); + continue; + + case AMODE_D: // modrm.reg = debug register + assert(X86Instruction->HasModRM); + assert(Instruction->Type == ITYPE_MOV); + if (!Decode) continue; + Instruction->NeedsEmulation = TRUE; + Operand->Flags |= OP_REG; + Instruction->Groups |= ITYPE_SYSTEM; + Instruction->NeedsEmulation = TRUE; + if (IS_AMD64()) X86Instruction->OperandSize = 8; + switch (X86Instruction->OperandSize) + { + case 8: + case 4: + case 2: + Operand->Register = X86_DEBUG_OFFSET + rex_modrm.reg; + break; + default: + assert(0); + return NULL; + } + + X86_SET_REG(0); + if (Disassemble) + { + APPENDS(X86_Registers[Operand->Register]); + X86_WRITE_OPFLAGS(); + } + //DISASM_OUTPUT(("[SetOperand] AMODE_D (debug register)\n")); + continue; + + //////////////////////////////////////////////////////////// + // Mod R/M byte with memory or register + //////////////////////////////////////////////////////////// + + case AMODE_M: // memory only + assert(X86Instruction->HasModRM); + if (modrm.mod == 3) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: mod = 3 for AMODE_M (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + assert(X86Instruction->Segment == SEG_DS || X86Instruction->HasSegmentOverridePrefix); + //DISASM_OUTPUT(("[SetOperand] AMODE_M (memory only)\n")); + Address = SetModRM32(Instruction, Address, Operand, OperandIndex, SuppressErrors); + if (!Address) return NULL; + break; + + case AMODE_E: // general register or memory + assert(X86Instruction->HasModRM); + if (OperandType == OPTYPE_p && modrm.mod == 3) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: mod = 3 for AMODE_E with OPTYPE_p (\"%s\")\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic); + goto abort; + } + + //DISASM_OUTPUT(("[SetOperand] AMODE_E (general register or memory)\n")); + Address = SetModRM32(Instruction, Address, Operand, OperandIndex, SuppressErrors); + if (!Address) return NULL; + if (Decode && (Instruction->Type == ITYPE_PUSH || Instruction->Type == ITYPE_POP)) + { + assert(X86Instruction->OperandSize >= Operand->Length); + Operand->Length = X86Instruction->OperandSize; + } + break; + + case AMODE_Q: // mmx register or memory address + assert(X86Instruction->HasModRM); + //DISASM_OUTPUT(("[SetOperand] AMODE_Q (MMX register or memory address)\n")); + if (modrm.mod == 3) // it is a register + { + if (rex_modrm.rm > 7) + { + if (!SuppressErrors) printf("[0x%08I64X] ERROR: invalid mmx register %d for AMODE_P (\"%s\")\n", VIRTUAL_ADDRESS, rex_modrm.rm, X86Instruction->Opcode.Mnemonic); + goto abort; + } + Operand->Register = X86_MMX_OFFSET + rex_modrm.rm; + Operand->Flags |= OP_REG; + X86_SET_REG(0); + } + else + { + Address = SetModRM32(Instruction, Address, Operand, OperandIndex, SuppressErrors); + if (!Address) return NULL; + } + break; + + case AMODE_W: // xmm register or memory address + assert(X86Instruction->HasModRM); + //DISASM_OUTPUT(("[SetOperand] AMODE_W (XMM register or memory address)\n")); + if (modrm.mod == 3) // it is a register + { + Operand->Register = X86_XMM_OFFSET + rex_modrm.rm; + Operand->Flags |= OP_REG; + X86_SET_REG(0); + } + else + { + Address = SetModRM32(Instruction, Address, Operand, OperandIndex, SuppressErrors); + if (!Address) return NULL; + } + break; + + default: + assert(0); + return NULL; + } + + if (!Decode) continue; + + // If this is reached then SetModRM32 was called + if ((Operand->Flags & OP_ADDRESS)) + { + assert(Operand->Length); + switch (Operand->Register) + { + case X86_REG_BP: + case X86_REG_EBP: + case AMD64_REG_RBP: + if (X86Instruction->Displacement > 0) Operand->Flags |= OP_PARAM; + else Operand->Flags |= OP_LOCAL; + break; + default: + break; + } + } + + if (Disassemble) + { + Index = OperandType >> OPTYPE_SHIFT; + assert(Index > 0 && Index < MAX_OPTYPE_INDEX && OptypeHandlers[Index]); + OptypeHandlers[Index](Instruction, Operand, OperandIndex); + X86_WRITE_OPFLAGS(); + } + } + + return Address; + +abort: + if (!SuppressErrors) + { +#ifdef TEST_DISASM + printf("Dump of 0x%04I64X:\n", VIRTUAL_ADDRESS); + __try { DumpAsBytes(stdout, Instruction->Address, (ULONG_PTR)VIRTUAL_ADDRESS, 16, TRUE); } + __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {} +#endif + fflush(stdout); + } + return NULL; +} + +// NOTE: Address points one byte after ModRM +INTERNAL U8 *SetModRM16(INSTRUCTION *Instruction, U8 *Address, INSTRUCTION_OPERAND *Operand, U32 OperandIndex, BOOL SuppressErrors) +{ + MODRM modrm; + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + + DISASM_OUTPUT(("[SetModRM16] Current instruction length = %d\n", Instruction->Length)); + modrm = X86Instruction->modrm; + assert(!X86Instruction->rex_b); + + // + // Both operands are registers + // Condition: mod = 3 + // + if (modrm.mod == 3) + { + //DISASM_OUTPUT(("[SetModRM16] Both regs (rm_reg %d)\n", modrm.rm)); + switch (Operand->Length) + { + case 4: Operand->Register = X86_32BIT_OFFSET + modrm.rm; break; + case 2: Operand->Register = X86_16BIT_OFFSET + modrm.rm; break; + case 1: Operand->Register = X86_8BIT_OFFSET + modrm.rm; break; + default: assert(0); return NULL; + } + Operand->Flags |= OP_REG; + } + + // + // Address is an absolute address (technically a 16-bit offset from DS:0) + // Condition: mod = 0 and rm = 6 + // + else if (modrm.mod == 0 && modrm.rm == 6) + { + //DISASM_OUTPUT(("[SetModRM16] Absolute addressing (displacement 0x%04X)\n", *(S16 *)Address)); + X86Instruction->Displacement = (S64)(*((S16 *)Address)); + if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + X86Instruction->HasFullDisplacement = TRUE; + X86_SET_TARGET(); + Operand->Flags |= OP_GLOBAL; + } + X86_SET_ADDR(); + Operand->Flags |= OP_ADDRESS; + INSTR_INC(2); + } + + // Conditions: + // (1) mod = 0 and rm != 6 + // (2) mod = 1-2 and rm = 0-7 + else + { + switch (modrm.mod) + { + case 0: // no displacement + //DISASM_OUTPUT(("[SetModRM16] Indirect addressing (no displacement)\n")); + break; + case 1: // 8-bit signed displacement + //DISASM_OUTPUT(("[SetModRM16] Indirect addressing (displacement = 0x%02X, reg_rm = %d)\n", *(S8 *)Address, modrm.rm)); + X86Instruction->Displacement = (S64)(*((S8 *)Address)); + INSTR_INC(1); // increment Instruction->Length and address + break; + case 2: // 16-bit displacement + //DISASM_OUTPUT(("[SetModRM16] Indirect addressing (displacement = 0x%04X, reg_rm = %d)\n", *(S16 *)Address, modrm.rm)); + X86Instruction->Displacement = (S64)(*((S16 *)Address)); + if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + Operand->Flags |= OP_GLOBAL; + X86Instruction->HasFullDisplacement = TRUE; + } + INSTR_INC(2); + break; + } + + switch (modrm.rm) + { + case 0: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [BX+SI]\n")); + X86Instruction->BaseRegister = X86_REG_BX; + X86Instruction->IndexRegister = X86_REG_SI; + X86Instruction->HasIndexRegister = TRUE; + break; + case 1: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [BX+DI]\n")); + X86Instruction->BaseRegister = X86_REG_BX; + X86Instruction->IndexRegister = X86_REG_DI; + X86Instruction->HasIndexRegister = TRUE; + break; + case 2: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [BP+SI]\n")); + X86Instruction->BaseRegister = X86_REG_BP; + X86Instruction->IndexRegister = X86_REG_SI; + X86Instruction->HasIndexRegister = TRUE; + X86_SET_SEG(REG_BP); + break; + case 3: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [BP+DI]\n")); + X86Instruction->BaseRegister = X86_REG_BP; + X86Instruction->IndexRegister = X86_REG_DI; + X86Instruction->HasIndexRegister = TRUE; + X86_SET_SEG(REG_BP); + break; + case 4: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [SI]\n")); + X86Instruction->BaseRegister = X86_REG_SI; + break; + case 5: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [DI]\n")); + X86Instruction->BaseRegister = X86_REG_DI; + break; + case 6: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [BP]\n")); + X86Instruction->BaseRegister = X86_REG_BP; + break; + case 7: + //DISASM_OUTPUT(("[SetModRM16] Addressing mode [BX]\n")); + X86Instruction->BaseRegister = X86_REG_BX; + break; + } + + X86Instruction->HasBaseRegister = TRUE; + Operand->Flags |= OP_ADDRESS | OP_REG; + X86_SET_ADDR(); + } + + return Address; +} + +// NOTE: Address points one byte after ModRM +INTERNAL U8 *SetModRM32(INSTRUCTION *Instruction, U8 *Address, INSTRUCTION_OPERAND *Operand, U32 OperandIndex, BOOL SuppressErrors) +{ + MODRM modrm; + REX_MODRM rex_modrm; + U32 i, ImmediateSize = 0; + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + + if (X86Instruction->AddressSize == 2) + { + return SetModRM16(Instruction, Address, Operand, OperandIndex, SuppressErrors); + } + + //DISASM_OUTPUT(("[SetModRM32] Length %d, modrm = 0x%02X\n", Instruction->Length, X86Instruction->modrm_b)); + modrm = X86Instruction->modrm; + rex_modrm = X86Instruction->rex_modrm; + + // + // Both operands are registers + // Condition: mod = 3 + // + if (modrm.mod == 3) + { + switch (Operand->Length) + { + case 8: Operand->Register = AMD64_64BIT_OFFSET + rex_modrm.rm; break; + case 4: Operand->Register = X86_32BIT_OFFSET + rex_modrm.rm; CHECK_AMD64_REG(); break; + case 2: Operand->Register = X86_16BIT_OFFSET + rex_modrm.rm; CHECK_AMD64_REG(); break; + case 1: Operand->Register = X86_8BIT_OFFSET + rex_modrm.rm; if (X86Instruction->rex_b) CHECK_AMD64_REG(); break; + default: assert(0); return NULL; + } + X86_SET_REG(rex_modrm.rm); + Operand->Flags |= OP_REG; + } + + // + // Address is an absolute address (technically a 32-bit offset from DS:0) + // mod = 0 and rm = 5 + // + else if (modrm.mod == 0 && modrm.rm == 5) + { + //DISASM_OUTPUT(("[SetModRM32] Absolute addressing (displacement 0x%08lX)\n", *(S32 *)Address)); + Operand->Flags |= OP_ADDRESS; + X86Instruction->Displacement = (S64)*((S32 *)Address); + INSTR_INC(4); // increment Instruction->Length and address + + if (IS_AMD64()) + { + // RIP-relative addressing always replaced Disp32, even when using a 32-bit address space + // (via address size override prefix) + switch (X86Instruction->OperandSize) + { + case 8: Operand->Register = AMD64_REG_RIP; break; + case 4: Operand->Register = X86_REG_EIP; break; + case 2: Operand->Register = X86_REG_IP; break; + default: assert(0); return NULL; + } + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + X86Instruction->Relative = TRUE; + Operand->Flags |= OP_IPREL | OP_SIGNED | OP_REG; + SANITY_CHECK_SEGMENT_OVERRIDE(); + if (!X86Instruction->HasSegmentOverridePrefix) X86Instruction->Segment = SEG_CS; + X86Instruction->HasFullDisplacement = TRUE; + + // Since there may be an immediate value to follow, it is necessary + // to determine the length in order get the proper offset + // + // Maybe there is a better way to do this, since this is wasteful + // (the size of the immediate value will have to be decoded again later + // in SetOperands) + + for (ImmediateSize = 0, i = OperandIndex+1; i < Instruction->OperandCount; i++) + { + if ((X86Instruction->Opcode.OperandFlags[i] & X86_AMODE_MASK) != AMODE_I) continue; + else assert(!ImmediateSize); + switch (X86Instruction->Opcode.OperandFlags[i] & X86_OPTYPE_MASK) + { + case OPTYPE_v: + ImmediateSize = X86Instruction->OperandSize; + break; + case OPTYPE_z: + switch (X86Instruction->OperandSize) + { + case 8: case 4: ImmediateSize = 4; break; + case 2: ImmediateSize = 2; break; + default: assert(0); return NULL; + } + break; + case OPTYPE_b: + ImmediateSize = 1; + break; + case OPTYPE_w: + ImmediateSize = 2; + break; + case OPTYPE_1: + break; + default: + assert(0); + break; + } + } + + Operand->TargetAddress = ApplyDisplacement((U64)Address + ImmediateSize, Instruction); + } + else if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + X86_SET_TARGET(); + Operand->Flags |= OP_GLOBAL; + X86Instruction->HasFullDisplacement = TRUE; + } + + X86_SET_ADDR(); + } + + // + // Addressing mode indicated by SIB byte + // Condition: mod = 0-2 and rm = 4 + // + else if (modrm.rm == 4) + { + // The X86_SET_*() is called from within SetSIB() + Address = SetSIB(Instruction, Address, Operand, OperandIndex, SuppressErrors); + if (!Address) + { + assert(0); + return NULL; + } + + if (X86Instruction->sib.base != 5) // if base == 5, the displacement is handled in SetSIB + { + switch (modrm.mod) + { + case 1: // 8-bit displacement + //DISASM_OUTPUT(("[SetModRM32] After SIB: displacement 0x%02X\n", *((S8 *)Address))); + X86Instruction->Displacement = (S64)(*((S8 *)Address)); + INSTR_INC(1); // increment Instruction->Length and address + break; + case 2: // 32-bit displacement + //DISASM_OUTPUT(("[SetModRM32] After SIB: displacement 0x%08lX\n", *((S32 *)Address))); + X86Instruction->Displacement = (S64)*((S32 *)Address); + if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + Operand->Flags |= OP_GLOBAL; + X86Instruction->HasFullDisplacement = TRUE; + } + INSTR_INC(4); // increment Instruction->Length and address + break; + } + } + } + + // Indirect addressing + // Conditions: + // (1) mod = 0 and (rm = 0-3 or 6-7) + // (2) mod = 1-2 and rm != 4 + else + { + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_64BIT_OFFSET + rex_modrm.rm; break; + case 4: Operand->Register = X86_32BIT_OFFSET + rex_modrm.rm; CHECK_AMD64_REG(); break; + default: assert(0); return NULL; + } + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + Operand->Flags |= OP_ADDRESS | OP_REG; + X86_SET_SEG(rex_modrm.rm); + X86_SET_ADDR(); + + switch (modrm.mod) + { + case 0: // no displacement + //DISASM_OUTPUT(("[SetModRM32] Indirect addressing (no displacement, reg_rm = %d)\n", rex_modrm.rm)); + break; + case 1: // 8-bit signed displacement + //DISASM_OUTPUT(("[SetModRM32] Indirect addressing (displacement = 0x%02X, reg_rm = %d)\n", *(S8 *)Address, rex_modrm.rm)); + X86Instruction->Displacement = (S64)(*((S8 *)Address)); + INSTR_INC(1); // increment Instruction->Length and address + break; + case 2: // 32-bit displacement + //DISASM_OUTPUT(("[SetModRM32] Indirect addressing (displacement = 0x%08lX, reg_rm = %d)\n", *(S32 *)Address, rex_modrm.rm)); + X86Instruction->Displacement = (S64)*((S32 *)Address); + if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + Operand->Flags |= OP_GLOBAL; + X86Instruction->HasFullDisplacement = TRUE; + } + INSTR_INC(4); // increment Instruction->Length and address + break; + } + } + + return Address; +} + +// NOTE: Address points at SIB +INTERNAL U8 *SetSIB(INSTRUCTION *Instruction, U8 *Address, INSTRUCTION_OPERAND *Operand, U32 OperandIndex, BOOL SuppressErrors) +{ + REX rex; + SIB sib; + REX_SIB rex_sib; + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + + X86Instruction->sib_b = *Address; + SET_SIB(X86Instruction->sib, *Address); + sib = X86Instruction->sib; + rex = X86Instruction->rex; + SET_REX_SIB(X86Instruction->rex_sib, rex, sib); + rex_sib = X86Instruction->rex_sib; + + //if (!X86Instruction->rex_b) DISASM_OUTPUT(("[0x%08I64X] SIB = 0x%02X (scale=%d, index=%d, base=%d)\n", VIRTUAL_ADDRESS, *Address, sib.scale, sib.index, sib.base)); \ + //else DISASM_OUTPUT(("[0x%08I64X] SIB = 0x%02X (scale=%d, index=%d, base=%d)\n", VIRTUAL_ADDRESS, *Address, sib.scale, rex_sib.index, rex_sib.base)); \ + //DISASM_OUTPUT(("[SetSIB] Current instruction length = %d\n", Instruction->Length)); + + Operand->Flags |= OP_ADDRESS; + X86_SET_ADDR(); + INSTR_INC(1); // increment Instruction->Length and address + + if (sib.base == 5) + { + switch (X86Instruction->modrm.mod) + { + case 0: + X86Instruction->Displacement = (S64)*((S32 *)Address); + if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + X86Instruction->HasFullDisplacement = TRUE; + X86_SET_TARGET(); + Operand->Flags |= OP_GLOBAL; + } + INSTR_INC(4); + break; + case 1: + X86Instruction->Displacement = (S64)(*((S8 *)Address)); + if (rex_sib.base == 5) + { + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_REG_RBP; break; + case 4: Operand->Register = X86_REG_EBP; break; + default: assert(0); return NULL; + } + X86_SET_SEG(REG_EBP); + } + else + { + Operand->Register = AMD64_REG_R13; + } + + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + Operand->Flags |= OP_REG; + INSTR_INC(1); + break; + case 2: + X86Instruction->Displacement = (S64)*((S32 *)Address); + if (rex_sib.base == 5) + { + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_REG_RBP; break; + case 4: Operand->Register = X86_REG_EBP; break; + default: assert(0); return NULL; + } + X86_SET_SEG(REG_EBP); + } + else + { + Operand->Register = AMD64_REG_R13; + } + + if (IS_VALID_ADDRESS(X86Instruction->Displacement)) + { + Operand->Flags |= OP_GLOBAL; + X86Instruction->HasFullDisplacement = TRUE; + } + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + Operand->Flags |= OP_REG; + INSTR_INC(4); + break; + } + } + else + { + switch (X86Instruction->AddressSize) + { + case 8: Operand->Register = AMD64_64BIT_OFFSET + rex_sib.base; break; + case 4: Operand->Register = X86_32BIT_OFFSET + rex_sib.base; CHECK_AMD64_REG(); break; + default: assert(0); return NULL; + } + X86Instruction->BaseRegister = Operand->Register; + X86Instruction->HasBaseRegister = TRUE; + X86_SET_SEG(rex_sib.base); + Operand->Flags |= OP_REG; + } + + if (rex_sib.index != 4) + { + switch (X86Instruction->AddressSize) + { + case 8: + X86Instruction->IndexRegister = AMD64_64BIT_OFFSET + rex_sib.index; + break; + case 4: + X86Instruction->IndexRegister = X86_32BIT_OFFSET + rex_sib.index; + break; + default: + fflush(stdout); + assert(0); + return NULL; + } + + Operand->TargetAddress = 0; + X86Instruction->HasIndexRegister = TRUE; + //DISASM_OUTPUT(("[SetSIB] Index register = %s\n", X86_Registers[X86_32BIT_OFFSET + rex_sib.index])); + + switch (sib.scale) + { + case 0: X86Instruction->Scale = 1; break; + case 1: X86Instruction->Scale = 2; break; + case 2: X86Instruction->Scale = 4; break; + case 3: X86Instruction->Scale = 8; break; + } + //DISASM_OUTPUT(("[SetSIB] Scale = %d\n", X86Instruction->Scale)); + } + + return Address; +} + +INTERNAL U64 ApplyDisplacement(U64 Address, INSTRUCTION *Instruction) +{ + X86_INSTRUCTION *X86Instruction = &Instruction->X86; + +#ifdef SUPPORT_WRAPAROUND + U64 VirtualAddress = Address + Instruction->VirtualAddressDelta; + switch (X86Instruction->OperandSize) + { + case 8: + { + U64 PreAddr = VirtualAddress; + U64 PostAddr = PreAddr + X86Instruction->Displacement; + return Address + (PostAddr - PreAddr); + } + case 4: + { + // We have to do this carefully... + // If EIP = FFFFF000 and Displacement=2000 then the final IP should be 1000 + // due to wraparound + U32 PreAddr = (U32)VirtualAddress; + U32 PostAddr = PreAddr + (S32)X86Instruction->Displacement; + return Address + (PostAddr - PreAddr); + } + case 2: + { + // We have to do this carefully... + // If IP = F000 and Displacement=2000 then the final IP should be 1000 + // due to wraparound + U16 PreAddr = (U16)VirtualAddress; + U16 PostAddr = PreAddr + (S16)X86Instruction->Displacement; + return Address + (PostAddr - PreAddr); + } + default: + assert(0); + return 0; + } +#else + return (Address + X86Instruction->Displacement); +#endif +} + + + +INTERNAL BOOL IsValidLockPrefix(X86_INSTRUCTION *X86Instruction, U8 Opcode, U32 OpcodeLength, U8 Group, U8 OpcodeExtension) +{ + switch (OpcodeLength) + { + case 1: + switch (X86_LockPrefix_1[Opcode]) + { + case 0: // instruction can't be locked + return FALSE; + case 1: // instruction can be locked + break; + case GR: + assert(Group); + if (!X86_LockPrefix_Groups[Group-1][OpcodeExtension]) return FALSE; + break; + default: + assert(0); + return FALSE; + } + break; + + case 2: + case 3: + switch (X86_LockPrefix_2[Opcode]) + { + case 0: // lock prefix is not acceptable + return FALSE; + case 1: // lock prefix allowed + break; + case GR: + assert(Group); + if (!X86_LockPrefix_Groups[Group-1][OpcodeExtension]) return FALSE; + break; + default: + assert(0); + return FALSE; + } + break; + + default: + assert(0); + return FALSE; + } + + if (!X86Instruction->HasModRM || X86Instruction->modrm.mod == 3 || !X86Instruction->HasDstAddressing) + { + DISASM_OUTPUT(("[0x%08I64X] ERROR: Instruction \"%s\" with LOCK prefix has invalid ModRM addressing\n", VIRTUAL_ADDRESS, X86Instruction->Opcode.Mnemonic, X86Instruction->Instruction->Address)); + return FALSE; + } + + return TRUE; +} diff --git a/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86.h b/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86.h new file mode 100644 index 0000000000..7a9f0d75a3 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86.h @@ -0,0 +1,839 @@ +// Copyright (C) 2004, Matt Conover (mconover@gmail.com) +#ifndef X86_DISASM_H +#define X86_DISASM_H +#ifdef __cplusplus +extern "C" { +#endif + +#pragma warning(disable: 4201) + +// NOTE: the processor may actually accept less than this amount (officially 15) +// #define AMD64_MAX_INSTRUCTION_LEN 15 // theoretical max 25=5+2+1+1+8+8 +#define AMD64_MAX_PREFIX_LENGTH 5 // 4 legacy + 1 rex +#define AMD64_MAX_ADDRESS_LENGTH 18 // modrm + sib + 8 byte displacement + 8 byte immediate value + +// NOTE: the processor may actually accept less than this amount (officially 15) +#define X86_MAX_INSTRUCTION_LEN 15 // theoretical 16=4+2+1+1+4+4 +#define X86_MAX_PREFIX_LENGTH 4 +#define X86_MAX_OPCODE_LENGTH 3 // third byte is either a suffix or prefix +#define X86_MAX_ADDRESS_LENGTH 10 // modrm + sib + 4 byte displacement + 4 byte immediate value +#define X86_MAX_OPERANDS 3 + +#define X86_PREFIX(a) ((a)->MnemonicFlags == ITYPE_EXT_PREFIX) +#define X86_SPECIAL_EXTENSION(a) ((a)->MnemonicFlags & (ITYPE_EXT_MODRM|ITYPE_EXT_FPU|ITYPE_EXT_SUFFIX|ITYPE_EXT_64)) +#define X86_EXTENDED_OPCODE(a) ((a)->Table) +#define X86_INVALID(a) (!(a)->MnemonicFlags && !(a)->Table) +#define X86_OPERAND_COUNT(a) ((a)->OperandFlags[0] ? ((a)->OperandFlags[1] ? ((a)->OperandFlags[2] ? 3 : 2) : 1) : 0) +#define X86_GET_CATEGORY(p) ((p)->MnemonicFlags & ITYPE_GROUP_MASK) +#define X86_GET_TYPE(p) ((p)->MnemonicFlags & ITYPE_TYPE_MASK) + +// Various instructions being specially decoded +#define X86_TWO_BYTE_OPCODE 0x0f +#define PREFIX_SEGMENT_OVERRIDE_ES 0x26 +#define PREFIX_SEGMENT_OVERRIDE_CS 0x2e +#define PREFIX_BRANCH_NOT_TAKEN 0x2e // used only with conditional jumps +#define PREFIX_SEGMENT_OVERRIDE_SS 0x36 +#define PREFIX_SEGMENT_OVERRIDE_DS 0x3e +#define PREFIX_BRANCH_TAKEN 0x3e // used only with conditional jumps +#define PREFIX_SEGMENT_OVERRIDE_FS 0x64 +#define PREFIX_SEGMENT_OVERRIDE_GS 0x65 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNE 0xf2 +#define PREFIX_REP 0xf3 + +////////////////////////////////////////////////////////////////// +// Implicit operand handling +////////////////////////////////////////////////////////////////// + +#define X86_AMODE_MASK 0x00FF0000 // bits 16-23 (AMODE_*) +#define X86_OPFLAGS_MASK 0x0000FF80 // bits 7-15 (OPTYPE_*) +#define X86_OPTYPE_MASK 0xFF0000FF // bits 0-7 (OPTYPE_* below + OP_REG) and 24-31 (OPTYPE_* above) + +#define OPTYPE_0 0x01 +#define OPTYPE_1 0x02 +#define OPTYPE_FF 0x03 +//... +#define OPTYPE_CS 0x10 +#define OPTYPE_DS 0x11 +#define OPTYPE_ES 0x12 +#define OPTYPE_FS 0x13 +#define OPTYPE_GS 0x14 +#define OPTYPE_SS 0x15 +#define OPTYPE_CR0 0x16 +#define OPTYPE_TSC 0x17 // time stamp counter +//... +#define OPTYPE_FLAGS 0x20 +#define OPTYPE_xFLAGS 0x21 // RFLAGS/EFLAGS (depending on operand size) +#define OPTYPE_xCX_HI_xBX_LO 0x22 // represented by 2 registers CX:BX or ECX:EBX (depending on operand size) +#define OPTYPE_xDX_HI_xAX_LO 0x23 // DX:AX or EDX:EAX (depending on operand size) +#define OPTYPE_EDX_HI_EAX_LO 0x24 // DX:AX or EDX:EAX (depending on operand size) +#define OPTYPE_EDX_ECX_EBX_EAX 0x25 // all registers are set +//... +#define OPTYPE_STx 0x30 +#define OPTYPE_ST0 0x31 +#define OPTYPE_ST1 0x32 +#define OPTYPE_FPU_STATUS 0x33 +#define OPTYPE_FPU_CONTROL 0x34 +#define OPTYPE_FPU_TAG 0x35 +#define OPTYPE_FLDZ 0x36 // 0 +#define OPTYPE_FLD1 0x37 // 1 +#define OPTYPE_FLDPI 0x38 // pi +#define OPTYPE_FLDL2T 0x39 // lg 10 +#define OPTYPE_FLDL2E 0x3A // lg e +#define OPTYPE_FLDLG2 0x3B // log_10 2 +#define OPTYPE_FLDLN2 0x3C // log_e 2 +//... +#define OPTYPE_CS_MSR 0x40 +#define OPTYPE_EIP_MSR 0x41 +#define OPTYPE_ESP_MSR 0x42 +#define OPTYPE_KERNELBASE_MSR 0x43 +#define OPTYPE_FMASK_MSR 0x44 +#define OPTYPE_STAR_MSR 0x45 +#define OPTYPE_CSTAR_MSR 0x46 // 32-bit mode +#define OPTYPE_LSTAR_MSR 0x47 // 64-bit mode + + +// NOTE: OPTYPES >= 0x80 reserved for registers (OP_REG+XX) +#define OPTYPE_REG_AL OP_REG+0x01 +#define OPTYPE_REG_CL OP_REG+0x02 +#define OPTYPE_REG_AH OP_REG+0x03 +#define OPTYPE_REG_AX OP_REG+0x04 +#define OPTYPE_REG_DX OP_REG+0x05 +#define OPTYPE_REG_ECX OP_REG+0x06 +#define OPTYPE_REG8 OP_REG+0x07 + +// If address size is 2, use BP +// If address size is 4, use EBP +// If address size is 8, use RBP +#define OPTYPE_REG_xBP OP_REG+0x08 + +// If address size is 2, use BP +// If address size is 4, use EBP +// If address size is 8, use RBP +#define OPTYPE_REG_xSP OP_REG+0x09 + +// If operand size is 2, take 8-bit register +// If operand size is 4, take 16-bit register +// If operand size is 8, take 32-bit register +#define OPTYPE_REG_xAX_SMALL OP_REG+0x0a + +// If operand size is 2, take 16-bit register +// If operand size is 4, take 32-bit register +// If operand size is 8, take 64-bit register +#define OPTYPE_REG_xAX_BIG OP_REG+0x0b + +typedef enum _CPU_TYPE +{ + CPU_UNKNOWN=0, + + /////////////////////////////////////// + // 1st generation + /////////////////////////////////////// + // 1978 + //CPU_8086 = 1MB address limit, 16-bit registers + // 1982 + //CPU_i186 + + /////////////////////////////////////// + // 2nd generation + /////////////////////////////////////// + // 1982 + //CPU_I286 // 16MB limit, 16-bit registers, added protected mode + CPU_I287, // CPU_I286 + math coprocessor + + /////////////////////////////////////// + // 3rd generation + /////////////////////////////////////// + // 1985 + CPU_I386, // 32-bit registers, 4GB memory limit + // 1988 + CPU_I387, // CPU_I386 + math coprocessor + + /////////////////////////////////////// + // 4th generation (1989) + /////////////////////////////////////// + CPU_I486, + + /////////////////////////////////////// + // 5th generation + /////////////////////////////////////// + // 1993 + CPU_PENTIUM, // superscalar architecture + // 1997 + //CPU_PENTIUM_MMX + + /////////////////////////////////////// + // 6th generation (1995) + /////////////////////////////////////// + CPU_PENTIUM_PRO, // P6 architecture, no MMX, out-of-order execution, speculative execution + //CPU_CYRIX_6X86, + //CPU_AMD_K5 // RISC processor + // 1997 + CPU_PENTIUM2, // Pentium Pro architecture + MMX + //CPU_AMD_K6, + //CPU_CYRIX_6X86MX, // Cyrix 6x86 + MMX + // 1998 + CPU_AMD_K6_2, // added 3DNow! (MMX) + // 1999 + // CPU_AMD_K6_3 // added SSE + + /////////////////////////////////////// + // 7th generation + /////////////////////////////////////// + // 1999 + CPU_PENTIUM3, // introduced SSE + // CPU_AMD_K7 // aka Athlon + // 2000 + CPU_PENTIUM4, // introduced SSE2 and hyperthreading + + // 2004? 2005? + CPU_PRESCOTT, // introduced SSE3 + + /////////////////////////////////////// + // 8th generation (X86-64) + // IA32 instruction set with 64-bit extensions, >4GB RAM + /////////////////////////////////////// + + // 2003 + CPU_AMD64, // includes Athlon 64 and Opteron aka X86-64 + + // 2004? + //CPU_EMD64 // Intel's version of AMD64 + CPU_IA64 // aka Itanium: new instruction set -- adds JMPE to IA32 mode to return to IA64 native code + +} CPU_TYPE; + +////////////////////////////////////////////////////////////////// +// Conditions (these can be OR'd) +////////////////////////////////////////////////////////////////// + +// Used for Flags.Preconditions +#define COND_O (1<<0) // overflow (signed) +#define COND_C (1<<1) // below (unsigned) +#define COND_Z (1<<2) // equal (unsigned) +#define COND_S (1<<3) // sign set (signed) +#define COND_P (1<<4) // parity even +#define COND_BE (1<<5) // CF or ZF is set (unsigned) +#define COND_L (1<<6) // (SF && !OF) || (OF && !SF) +#define COND_LE (1<<7) // ZF || (SF && !OF) || (OF && !SF) (signed) +#define COND_NO (1<<8) // !O +#define COND_NC (1<<9) // !C (not below, above or equal to) +#define COND_NZ (1<<10) // !Z (not equal) +#define COND_NS (1<<11) // !S +#define COND_NP (1<<12) // !P (parity odd) +#define COND_NL (1<<13) // (!SF && !OF) || (SF && OF) +#define COND_G (1<<14) // !ZF && ((!SF && !OF) || (SF && OF)) +#define COND_D (1<<15) // DF +#define COND_REG_xCX_BIG_Z (1<<16) // CX/ECX/RCX (depending on address size) == 0 +#define COND_REG_xCX_BIG_NZ (1<<17) // CX/ECX/RCX (depending on address size) != 0 +#define COND_OP1_EQ_OP2 (1<<18) +#define COND_OP1_EQ_OP3 (1<<19) +#define COND_B COND_C +#define COND_NAE COND_C +#define COND_E COND_Z +#define COND_NA COND_BE +#define COND_PE COND_P +#define COND_U COND_P +#define COND_NGE COND_L +#define COND_NG COND_LE +#define COND_PO COND_NP +#define COND_NU COND_NP +#define COND_NE COND_NZ +#define COND_NB COND_NC +#define COND_AE COND_NC +#define COND_NE COND_NZ +#define COND_A (COND_NC|COND_NZ) +#define COND_NBE COND_A +#define COND_GE COND_NL +#define COND_NLE COND_G + +// Used for Opcode.FlagsChanged +#define FLAG_CF_SET (1<<0) +#define FLAG_DF_SET (1<<1) +#define FLAG_IF_SET (1<<2) +#define FLAG_SET_MASK (FLAG_CF_SET|FLAG_DF_SET|FLAG_IF_SET) + +#define FLAG_SF_CLR (1<<3) +#define FLAG_ZF_CLR (1<<4) +#define FLAG_AF_CLR (1<<5) +#define FLAG_CF_CLR (1<<6) +#define FLAG_DF_CLR (1<<7) +#define FLAG_IF_CLR (1<<8) +#define FLAG_OF_CLR (1<<9) +#define FPU_C0_CLR (1<<19) +#define FPU_C1_CLR (1<<20) +#define FPU_C2_CLR (1<<21) +#define FPU_C3_CLR (1<<22) +#define FPU_ALL_CLR (FPU_C0_CLR|FPU_C1_CLR|FPU_C2_CLR|FPU_C3_CLR) +#define FLAG_CLR_MASK (FLAG_SF_CLR|FLAG_ZF_CLR|FLAG_AF_CLR|FLAG_CF_CLR|FLAG_DF_CLR|FLAG_IF_CLR|FLAG_OF_CLR|FPU_ALL_CLR) + +#define FLAG_OF_MOD (1<<10) +#define FLAG_SF_MOD (1<<11) +#define FLAG_ZF_MOD (1<<12) +#define FLAG_AF_MOD (1<<13) +#define FLAG_PF_MOD (1<<14) +#define FLAG_CF_MOD (1<<15) +#define FLAG_DF_MOD (1<<16) +#define FLAG_IF_MOD (1<<17) +#define FLAG_ALL_MOD (FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD|FLAG_CF_MOD|FLAG_DF_MOD|FLAG_IF_MOD) +#define FLAG_COMMON_MOD (FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD|FLAG_CF_MOD) +#define FPU_C0_MOD (1<<23) +#define FPU_C1_MOD (1<<24) +#define FPU_C2_MOD (1<<25) +#define FPU_C3_MOD (1<<26) +#define FPU_ALL_MOD (FPU_C0_MOD|FPU_C1_MOD|FPU_C2_MOD|FPU_C3_MOD) +#define FLAG_MOD_MASK (FLAG_ALL_MOD|FPU_ALL_MOD) + +#define FLAG_CF_TOG (1<<18) +#define FLAG_TOG_MASK FLAG_CF_TOG + +// Used for Opcode.ResultsIfTrue and Opcode.ResultsIfFalse +#define OP1_DST (1<<0) +#define OP2_DST (1<<1) +#define OP3_DST (1<<2) +#define OP1_SRC (1<<3) +#define OP2_SRC (1<<4) +#define OP3_SRC (1<<5) +#define FPU_STACK_INC (1<<6) +#define FPU_STACK_INC2 (1<<7) +#define FPU_STACK_DEC (1<<8) +#define SERIALIZE_WRITE (1<<9) +#define SERIALIZE_READ (1<<10) +#define xCX_DEC (1<<11) +#define xCX_REP_DEC (1<<12) +#define xDI_DEC (1<<13) +#define xDI_INC (1<<14) +#define xSI_DEC (1<<15) +#define xSI_INC (1<<16) +#define xDI_DECx (1<<17) +#define xDI_INCx (1<<18) +#define xSI_DECx (1<<19) +#define xSI_INCx (1<<20) +#define FPU_STACK_PUSH FPU_STACK_DEC +#define FPU_STACK_POP FPU_STACK_INC +#define FPU_STACK_POP2 FPU_STACK_INC2 +#define SERIALIZE_ALL (SERIALIZE_WRITE|SERIALIZE_READ) + +#define X86_SEGMENT_OFFSET 0x00 +#define X86_TEST_OFFSET 0x10 +#define X86_CONTROL_OFFSET 0x20 +#define X86_DEBUG_OFFSET 0x30 +#define X86_FPU_OFFSET 0x40 +#define X86_MMX_OFFSET 0x50 +#define X86_XMM_OFFSET 0x60 +#define X86_8BIT_OFFSET 0x70 +#define X86_16BIT_OFFSET 0x80 +#define X86_32BIT_OFFSET 0x90 +#define AMD64_8BIT_OFFSET 0xA0 +#define AMD64_16BIT_OFFSET 0xB0 +#define AMD64_32BIT_OFFSET 0xC0 +#define AMD64_64BIT_OFFSET 0xD0 + +typedef enum _X86_REGISTER +{ + // Segments + X86_SEG_ES = X86_SEGMENT_OFFSET, + X86_SEG_CS, + X86_SEG_SS, + X86_SEG_DS, + X86_SEG_FS, + X86_SEG_GS, + + // Miscellaneous + X86_REG_FLAGS, + X86_REG_EFLAGS, + AMD64_REG_RFLAGS, + X86_REG_IP, + X86_REG_EIP, + AMD64_REG_RIP, + + // Test registers + X86_REG_TR0 = X86_TEST_OFFSET, + X86_REG_TR1, + X86_REG_TR2, + X86_REG_TR3, + X86_REG_TR4, + X86_REG_TR5, + X86_REG_TR6, + X86_REG_TR7, + X86_REG_TR8, + X86_REG_TR9, + X86_REG_TR10, + X86_REG_TR11, + X86_REG_TR12, + X86_REG_TR13, + X86_REG_TR14, + X86_REG_TR15, + + // Control registers + X86_REG_CR0=X86_CONTROL_OFFSET, + X86_REG_CR1, + X86_REG_CR2, + X86_REG_CR3, + X86_REG_CR4, + X86_REG_CR5, + X86_REG_CR6, + X86_REG_CR7, + X86_REG_CR8, + X86_REG_CR9, + X86_REG_CR10, + X86_REG_CR11, + X86_REG_CR12, + X86_REG_CR13, + X86_REG_CR14, + X86_REG_CR15, + + // Debug registers + X86_REG_DR0=X86_DEBUG_OFFSET, + X86_REG_DR1, + X86_REG_DR2, + X86_REG_DR3, + X86_REG_DR4, + X86_REG_DR5, + X86_REG_DR6, + X86_REG_DR7, + X86_REG_DR8, + X86_REG_DR9, + X86_REG_DR10, + X86_REG_DR11, + X86_REG_DR12, + X86_REG_DR13, + X86_REG_DR14, + X86_REG_DR15, + + // FPU registers + X86_REG_ST0=X86_FPU_OFFSET, + X86_REG_ST1, + X86_REG_ST2, + X86_REG_ST3, + X86_REG_ST4, + X86_REG_ST5, + X86_REG_ST6, + X86_REG_ST7, + + // MMX registers + X86_REG_MM0=X86_MMX_OFFSET, + X86_REG_MM1, + X86_REG_MM2, + X86_REG_MM3, + X86_REG_MM4, + X86_REG_MM5, + X86_REG_MM6, + X86_REG_MM7, + + // XMM registers + X86_REG_XMM0=X86_XMM_OFFSET, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7, + + // 8-bit registers + X86_REG_AL=X86_8BIT_OFFSET, + X86_REG_CL, + X86_REG_DL, + X86_REG_BL, + X86_REG_AH, + X86_REG_CH, + X86_REG_DH, + X86_REG_BH, + + // 16-bit registers + X86_REG_AX=X86_16BIT_OFFSET, + X86_REG_CX, + X86_REG_DX, + X86_REG_BX, + X86_REG_SP, + X86_REG_BP, + X86_REG_SI, + X86_REG_DI, + + // 32-bit registers + X86_REG_EAX=X86_32BIT_OFFSET, + X86_REG_ECX, + X86_REG_EDX, + X86_REG_EBX, + X86_REG_ESP, + X86_REG_EBP, + X86_REG_ESI, + X86_REG_EDI, + + // AMD64 8-bit registers + AMD64_REG_AL=AMD64_8BIT_OFFSET, + AMD64_REG_CL, + AMD64_REG_DL, + AMD64_REG_BL, + AMD64_REG_SPL, + AMD64_REG_BPL, + AMD64_REG_SIL, + AMD64_REG_DIL, + AMD64_REG_R8B, + AMD64_REG_R9B, + AMD64_REG_R10B, + AMD64_REG_R11B, + AMD64_REG_R12B, + AMD64_REG_R13B, + AMD64_REG_R14B, + AMD64_REG_R15B, + + // AMD64 16-bit registers + AMD64_REG_AX=AMD64_16BIT_OFFSET, + AMD64_REG_CX, + AMD64_REG_DX, + AMD64_REG_BX, + AMD64_REG_SP, + AMD64_REG_BP, + AMD64_REG_SI, + AMD64_REG_DI, + AMD64_REG_R8W, + AMD64_REG_R9W, + AMD64_REG_R10W, + AMD64_REG_R11W, + AMD64_REG_R12W, + AMD64_REG_R13W, + AMD64_REG_R14W, + AMD64_REG_R15W, + + // AMD64 32-bit registers + AMD64_REG_EAX=AMD64_32BIT_OFFSET, + AMD64_REG_ECX, + AMD64_REG_EDX, + AMD64_REG_EBX, + AMD64_REG_ESP, + AMD64_REG_EBP, + AMD64_REG_ESI, + AMD64_REG_EDI, + AMD64_REG_R8D, + AMD64_REG_R9D, + AMD64_REG_R10D, + AMD64_REG_R11D, + AMD64_REG_R12D, + AMD64_REG_R13D, + AMD64_REG_R14D, + AMD64_REG_R15D, + + // AMD64 64-bit registers + AMD64_REG_RAX=AMD64_64BIT_OFFSET, + AMD64_REG_RCX, + AMD64_REG_RDX, + AMD64_REG_RBX, + AMD64_REG_RSP, + AMD64_REG_RBP, + AMD64_REG_RSI, + AMD64_REG_RDI, + AMD64_REG_R8, + AMD64_REG_R9, + AMD64_REG_R10, + AMD64_REG_R11, + AMD64_REG_R12, + AMD64_REG_R13, + AMD64_REG_R14, + AMD64_REG_R15 +} X86_REGISTER; + +typedef enum _X86_TEST_REGISTER +{ + REG_TR0=0, + REG_TR1, + REG_TR2, + REG_TR3, + REG_TR4, + REG_TR5, + REG_TR6, + REG_TR7, + REG_TR8, + REG_TR9, + REG_TR10, + REG_TR11, + REG_TR12, + REG_TR13, + REG_TR14, + REG_TR15 +} X86_TEST_REGISTER; + +typedef enum _X86_CONTROL_REGISTER +{ + REG_CR0, + REG_CR1, + REG_CR2, + REG_CR3, + REG_CR4, + REG_CR5, + REG_CR6, + REG_CR7, + REG_CR8, + REG_CR9, + REG_CR10, + REG_CR11, + REG_CR12, + REG_CR13, + REG_CR14, + REG_CR15 +} X86_CONTROL_REGISTER; + +typedef enum _X86_DEBUG_REGISTER +{ + REG_DR0, + REG_DR1, + REG_DR2, + REG_DR3, + REG_DR4, + REG_DR5, + REG_DR6, + REG_DR7, + REG_DR8, + REG_DR9, + REG_DR10, + REG_DR11, + REG_DR12, + REG_DR13, + REG_DR14, + REG_DR15 +} X86_DEBUG_REGISTER; + +typedef enum _X86_MMX_REGISTER +{ + REG_MM0=0, + REG_MM1=1, + REG_MM2=2, + REG_MM3=3, + REG_MM4=4, + REG_MM5=5, + REG_MM6=6, + REG_MM7=7 +} X86_MMX_REGISTER; + +typedef enum _X86_SSE_REGISTER +{ + REG_XMM0=0, + REG_XMM1=1, + REG_XMM2=2, + REG_XMM3=3, + REG_XMM4=4, + REG_XMM5=5, + REG_XMM6=6, + REG_XMM7=7 +} X86_SSE_REGISTER; + +typedef enum _X86_FPU_REGISTER +{ + REG_ST0=0, + REG_ST1=1, + REG_ST2=2, + REG_ST3=3, + REG_ST4=4, + REG_ST5=5, + REG_ST6=6, + REG_ST7=7 +} X86_FPU_REGISTER; + +typedef enum _X86_8BIT_REGISTER +{ + REG_AL = 0, + REG_CL = 1, + REG_DL = 2, + REG_BL = 3, + REG_AH = 4, + REG_CH = 5, + REG_DH = 6, + REG_BH = 7 +} X86_8BIT_REGISTER; + +typedef enum _X86_16BIT_REGISTER +{ + REG_AX = 0, + REG_CX = 1, + REG_DX = 2, + REG_BX = 3, + REG_SP = 4, + REG_BP = 5, + REG_SI = 6, + REG_DI = 7 +} X86_16BIT_REGISTER; + +typedef enum _X86_32BIT_REGISTER +{ + REG_EAX = 0, + REG_ECX = 1, + REG_EDX = 2, + REG_EBX = 3, + REG_ESP = 4, + REG_EBP = 5, + REG_ESI = 6, + REG_EDI = 7 +} X86_32BIT_REGISTER; + +typedef enum _X86_SEGMENT +{ + SEG_ES = 0, + SEG_CS = 1, + SEG_SS = 2, + SEG_DS = 3, + SEG_FS = 4, + SEG_GS = 5, + SEG_MAX = 6 +} X86_SEGMENT; + +extern char *X86_Registers[]; + +#pragma pack(push,1) +typedef struct _MODRM +{ + U8 mod : 2; + U8 reg : 3; + U8 rm : 3; +} MODRM; +typedef struct _SIB +{ + U8 scale : 2; + U8 index : 3; + U8 base : 3; +} SIB; +typedef struct _REX +{ + U8 unused : 4; // bits 4,5,6,7 + U8 w : 1; // bit 3 + U8 r : 1; // bit 2 + U8 x : 1; // bit 1 + U8 b : 1; // bit 0 +} REX; +typedef struct _REX_MODRM +{ + U8 reg : 4; + U8 rm : 4; +} REX_MODRM; +typedef struct _REX_SIB +{ + U8 index : 4; + U8 base : 4; +} REX_SIB; +#pragma pack(pop) + +// +// Properties: +// If an operand is OP_COND_EXEC, it means that it is executed only if the pre-conditions are met. +// +// If if an instruction has one or more OP_COND_DST operands, then the actions are determined by +// whether the Opcode.Preconditions are met or not. If all the COND_* flags in Opcode.Preconditions +// are true, then the results are determined by ResultsIfTrue. If the preconditions are not met, then +// the results are determined by ResultsIfFalse. +// +// If Preconditions == NOCOND, then results in ResultsIfTrue are unconditional and ResultsIfFalse +// is ignored +// +typedef struct _X86_OPCODE +{ + struct _X86_OPCODE *Table; + CPU_TYPE CPU; // minimum CPU (starting with i386) + U32 MnemonicFlags; + char Mnemonic[X86_MAX_INSTRUCTION_LEN+1]; + U32 OperandFlags[X86_MAX_OPERANDS]; + U32 Preconditions; + U32 FlagsChanged; // changes in flags + U32 ResultsIfTrue; // results if Preconditions are met + U32 ResultsIfFalse; // results if Preconditions are not met +} X86_OPCODE; + +typedef struct _X86_INSTRUCTION +{ + struct _INSTRUCTION *Instruction; // the generic instruction format representing this instruction + + X86_OPCODE Opcode; + + U8 sib_b; + U8 modrm_b; + MODRM modrm; + SIB sib; + U8 rex_b; + REX rex; + REX_MODRM rex_modrm; + REX_SIB rex_sib; + + X86_SEGMENT DstSegment; + union + { + X86_SEGMENT Segment; + DWORD Selector; + }; + + // NOTE: these are for internal use, use Instruction->Operands[] + // + // If DstRegAddressing or SrcRegAddressing = TRUE then BaseRegister is the base register + // It is the operand represented by SIBOperand + // + // The operand indices of the destination operands is in DstOpIndex[0 to DstOpCount-1] + // The operand indices of the source operands is in SrcOpIndex[0 to SrcOpCount-1] + // + // These are used both for instructions like xadd/xchg (where both operands are source/destination) + // and to represent implicit registers (e.g., cmpxchg) + + U8 SrcOpIndex[3]; + U8 DstOpIndex[3]; + + // Addressing mode: + // If DstRegAddressing = TRUE, then these apply to DstReg + // If SrcRegAddressing = TRUE, then this applies to SrcReg[AddressIndex] + // If both are false, then SrcReg and DstReg are not addresses + X86_REGISTER BaseRegister; + X86_REGISTER IndexRegister; + + U8 Scale; + U8 HasDefault64Operand : 1; + U8 HasOperandSizePrefix : 1; + U8 HasAddressSizePrefix : 1; + U8 HasSegmentOverridePrefix : 1; + U8 HasLockPrefix : 1; + U8 HasRepeatWhileEqualPrefix : 1; + U8 HasRepeatWhileNotEqualPrefix : 1; + U8 HasBranchTakenPrefix : 1; + U8 HasBranchNotTakenPrefix : 1; + U8 HasDstAddressing : 1; + U8 HasSrcAddressing : 1; + U8 HasModRM : 1; + U8 HasBaseRegister : 1; + U8 HasIndexRegister : 1; + U8 HasFullDisplacement : 1; + U8 HasDstSegment : 1; // used for ins/cmps/scas/movs/etc which have 2 segments + U8 DstAddressIndex : 2; // DstOpIndex[DstAddressIndex] + U8 SrcAddressIndex : 2; // SrcOpIndex[SrcAddressIndex] + U8 DstOpCount : 2; + U8 SrcOpCount : 2; + U8 OperandSize : 4; + U8 AddressSize : 4; + U8 Relative : 1; + U8 HasSelector : 1; // segment is actually a selector + U8 Group : 5; + + S64 Displacement; + +} X86_INSTRUCTION; + +//////////////////////////////////////////////////////////////////////////////////// +// Exported functions +//////////////////////////////////////////////////////////////////////////////////// + +extern ARCHITECTURE_FORMAT_FUNCTIONS X86; + +// Instruction setup +BOOL X86_InitInstruction(struct _INSTRUCTION *Instruction); +void X86_CloseInstruction(struct _INSTRUCTION *Instruction); + +// Instruction translator +BOOL X86_TranslateInstruction(struct _INSTRUCTION *Instruction, BOOL Verbose); + +// Instruction decoder +BOOL X86_GetInstruction(struct _INSTRUCTION *Instruction, U8 *Address, DWORD Flags); + +// Function finding +U8 *X86_FindFunctionByPrologue(struct _INSTRUCTION *Instruction, U8 *StartAddress, U8 *EndAddress, DWORD Flags); + +#ifdef __cplusplus +} +#endif +#endif // X86_DISASM_H + diff --git a/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86_tables.h b/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86_tables.h new file mode 100644 index 0000000000..170bcc9126 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/disasm_x86_tables.h @@ -0,0 +1,3656 @@ +// Copyright (C) 2004, Matt Conover (mconover@gmail.com) +// +// The opcode tables in this file are based off the Intel Instruction Set Reference +// and an assortment of disassemblers, primarily libdisasm (by mammon) + +#ifndef DISASM_X86_TABLES +#define DISASM_X86_TABLES + +#pragma warning(disable: 4245) + +#define X86_GET_REG(val) ((val) & 7) +#define X86_GET_REG64(val) ((GET_REX_B(X86Instruction->rex_b) << 3) | ((val) & 7)) + +#define GET_MODRM_MOD(a) (((a) >> 6) & 3) // bits 6, 7 +#define GET_MODRM_REG(a) (((a) >> 3) & 7) // bits 3, 4, 5 +#define GET_MODRM_EXT(a) (((a) >> 3) & 7) // bits 3, 4, 5 +#define GET_MODRM_RM(a) ((a) & 7) // bits 0, 1, 2 + +#define GET_SIB_SCALE(a) (((a) >> 6) & 3) // bits 6, 7 +#define GET_SIB_INDEX(a) (((a) >> 3) & 7) // bits 3, 4, 5 +#define GET_SIB_BASE(a) ((a) & 7) // bits 0, 1, 2 + +#define REX_PREFIX_START 0x40 +#define REX_PREFIX_END 0x4F +#define GET_REX_W(r) (((r) & 8) >> 3) // bit 3 +#define GET_REX_R(r) (((r) & 4) >> 2) // bit 2 +#define GET_REX_X(r) (((r) & 2) >> 1) // bit 1 +#define GET_REX_B(r) ((r) & 1) // bit 0 +#define REX_MASK(n) ((n >> 16) & 0x0F) // bits 0-3 + +// Groupings to make the opcode table more readible +#define NOARGS { 0, 0, 0 } +#define NOCOND 0 +#define NOGROUP NULL +#define NOACTION 0 +#define NOCHANGE 0 +#define IGNORED 0 +#define NOINSTR NOGROUP, CPU_UNKNOWN, 0, "", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED +#define GROUP CPU_UNKNOWN, 0, "", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED +#define PREFIX NOGROUP, CPU_UNKNOWN, ITYPE_EXT_PREFIX, "", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED +#define EXT_FPU CPU_UNKNOWN, ITYPE_EXT_FPU, "", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED +#define EXT_64 CPU_UNKNOWN, ITYPE_EXT_64, "", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED +#define EXT_SUFFIX(a, b, c) CPU_UNKNOWN, ITYPE_EXT_SUFFIX, "", { a, b, c }, NOCOND, NOCHANGE, NOACTION, IGNORED +#define EXT_MODRM CPU_UNKNOWN, ITYPE_EXT_MODRM, "", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED + +#define SET_MODRM(modrm, src) \ +{ \ + (modrm).mod = GET_MODRM_MOD(src); \ + (modrm).reg = GET_MODRM_REG(src); \ + (modrm).rm = GET_MODRM_RM(src); \ +} + +#define SET_REX_MODRM(rex_modrm, rex, modrm) \ +{ \ + (rex_modrm).rm = ((rex).b << 3) | (modrm).rm; \ + (rex_modrm).reg = ((rex).r << 3) | (modrm).reg; \ +} + +#define SET_SIB(sib, src) \ +{ \ + (sib).scale = GET_SIB_SCALE(src); \ + (sib).index = GET_SIB_INDEX(src); \ + (sib).base = GET_SIB_BASE(src); \ +} + +#define SET_REX_SIB(rex_sib, rex, sib) \ +{ \ + (rex_sib).index = ((rex).x << 3) | (sib).index; \ + (rex_sib).base = ((rex).b << 3) | (sib).base; \ +} + +#define SET_REX(rex, src) \ +{ \ + (rex).w = GET_REX_W(src); \ + (rex).r = GET_REX_R(src); \ + (rex).x = GET_REX_X(src); \ + (rex).b = GET_REX_B(src); \ +} + +// Addressing modes +#define AMODE_A 0x00010000 +#define AMODE_C 0x00020000 +#define AMODE_D 0x00030000 +#define AMODE_E 0x00040000 +#define AMODE_G 0x00050000 +#define AMODE_I 0x00060000 +#define AMODE_J 0x00070000 +#define AMODE_M 0x00080000 +#define AMODE_O 0x00090000 +#define AMODE_P 0x000A0000 +#define AMODE_Q 0x000B0000 +#define AMODE_R 0x000C0000 +#define AMODE_S 0x000D0000 +#define AMODE_T 0x000E0000 +#define AMODE_V 0x000F0000 +#define AMODE_W 0x00100000 +#define AMODE_X 0x00110000 +#define AMODE_Y 0x00120000 +#define AMODE_PR 0x00130000 +#define AMODE_VR 0x00140000 +#define AMODE_xlat 0x00150000 + +// Operand types +#define OPTYPE_a 0x01000000 +#define OPTYPE_b 0x02000000 +#define OPTYPE_d 0x03000000 +#define OPTYPE_p 0x04000000 +#define OPTYPE_q 0x05000000 +#define OPTYPE_dt 0x06000000 +#define OPTYPE_v 0x07000000 +#define OPTYPE_w 0x08000000 +#define OPTYPE_ps 0x09000000 // packed 128-bit single real +#define OPTYPE_pd 0x0A000000 // packed 128-bit double real +#define OPTYPE_pb 0x0B000000 // packed BCD (10 bytes, 18-bit precision) +#define OPTYPE_ss 0x0C000000 // scalar single real +#define OPTYPE_sd 0x0D000000 // scalar double real +#define OPTYPE_se 0x0E000000 // scalar extended real +#define OPTYPE_fev 0x0F000000 // FPU environment (28 bytes if 32-bit modes, 14 bytes in 16-bit mode) +#define OPTYPE_fst1 0x10000000 // FPU state (108 bytes in 32-bit modes, 94 bytes in 16-bit real mode) +#define OPTYPE_fst2 0x11000000 // FPU/MMX/XMM/MXCSR state (512 bytes) +#define OPTYPE_z 0x12000000 +#define OPTYPE_o 0x13000000 +#define OPTYPE_dq 0x14000000 // OPTYPE_d or OPTYPE_o +#define OPTYPE_mw 0x15000000 // word if memory, register size otherwise +#define OPTYPE_sso 0x16000000 // OPTYPE_ss or OPTYPE_o +#define OPTYPE_sdo 0x17000000 // OPTYPE_ss or OPTYPE_o +#define OPTYPE_cpu 0x18000000 // pointer to CPU state structure +#define OPTYPE_lea 0x19000000 // size set by other operand +// NOTE: if you change this, you must also update OptypeHandlers[] in disasm_x86.c +// Be sure to preserve the ordering + +////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Registers +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +static char *Addressing16[8] = {"bx+si","bx+di","bp+si","bp+di","si","di","bp","bx"}; +static char *MMX_Registers[8] = {"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"}; +static char *SSE_Registers[8] = {"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"}; +static char *DR_Registers[8] = {"dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7"}; +static char *CR_Registers[8] = {"cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7"}; +static char *TR_Registers[8] = {"tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7"}; +static char *FPU_Registers[8] = {"st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"}; +static char *Segments[8] = {"es", "cs", "ss", "ds", "fs", "gs", "ERROR", "ERROR"}; +static char *Registers8[8] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; +static char *Registers16[8] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; +static char *Registers32[8] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; +static char *REX_Registers8[16] = {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }; +static char *REX_Registers16[16] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; +static char *REX_Registers32[16] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; +static char *REX_Registers64[16] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; +static char *DataSizes[8+1] = {"byte ptr", "word ptr", "dword ptr", "6_byte ptr", "qword ptr", "10_byte ptr", "INVALID PTR", "INVALID PTR", "oword ptr"}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// FPU constants +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +BYTE float_0[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +BYTE float_1[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F }; +BYTE float_l2t[10] = { 0xFE, 0x8A, 0x1B, 0xCD, 0x4B, 0x78, 0x9A, 0xD4, 0x00, 0x40 }; +BYTE float_l2e[10] = { 0xBC, 0xF0, 0x17, 0x5C, 0x29, 0x3B, 0xAA, 0xB8, 0xFF, 0x3F }; +BYTE float_pi[10] = { 0x35, 0xC2, 0x68, 0x21, 0xA2, 0xDA, 0x0F, 0xC9, 0x00, 0x40 }; +BYTE float_lg2[10] = { 0x99, 0xF7, 0xCF, 0xFB, 0x84, 0x9A, 0x20, 0x9A, 0xFD, 0x3F }; +BYTE float_ln2[10] = { 0xAC, 0x79, 0xCF, 0xD1, 0xF7, 0x17, 0x72, 0xB1, 0xFE, 0x3F }; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Tables +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +extern X86_OPCODE X86_Opcodes_2[0x100]; +extern X86_OPCODE X86_Group_1_80[8], X86_Group_1_81[8], X86_Group_1_82[8], X86_Group_1_83[8], X86_Group_2_C0[8], X86_Group_2_C1[8], X86_Group_2_D0[8], X86_Group_2_D1[8], X86_Group_2_D2[8], X86_Group_2_D3[8], X86_Group_3_F6[8], X86_Group_3_F7[8], X86_Group_4[8], X86_Group_5[8], X86_Group_6[8], X86_Group_7[8], X86_Group_8[8], X86_Group_9[8], X86_Group_10[8], X86_Group_11[8], X86_Group_12_C6[8], X86_Group_12_C7[8], X86_Group_13[8], X86_Group_14[8], X86_Group_15[8], X86_Group_16[8], X86_Group_17[8], X86_Group_P[8]; +extern X86_OPCODE X86_SSE[0x300], X86_SSE2_Group_13[24], X86_SSE2_Group_14[24], X86_SSE2_Group_15[24]; +extern X86_OPCODE X86_ESC_0[0x48], X86_ESC_1[0x48], X86_ESC_2[0x48], X86_ESC_3[0x48], X86_ESC_3[0x48], X86_ESC_4[0x48], X86_ESC_5[0x48], X86_ESC_6[0x48], X86_ESC_7[0x48]; +extern X86_OPCODE X86_3DNOW_0F[0x100]; +extern X86_OPCODE X86_0F01_ModRM[0x100]; +extern X86_OPCODE X86_Opcode_63[2], X86_Opcode_0F05[2]; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Opcode tables +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +X86_OPCODE X86_Opcodes_1[0x100] = // 1 byte opcodes +{ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OPTYPE_ES | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OPTYPE_ES | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x08 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x09 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x0A */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x0B */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x0C */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x0D */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OPTYPE_CS | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x0E */ + { X86_Opcodes_2, GROUP }, /* 0x0F */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x10 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x11 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x12 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x13 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x14 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x15 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OPTYPE_SS | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x16 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OPTYPE_SS | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x17 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x18 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x19 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x1A */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x1B */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x1C */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x1D */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OPTYPE_DS | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x1E */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OPTYPE_DS | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x1F */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x20 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x21 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x22 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x23 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x24 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x25 */ + { PREFIX }, /* 0x26 */ + { NOGROUP, CPU_I386, ITYPE_BCDCONV, "daa", { OPTYPE_REG_AL | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_AF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x27 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x28 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x29 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x2A */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x2B */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x2C */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x2D */ + { PREFIX }, /* 0x2E */ + { NOGROUP, CPU_I386, ITYPE_BCDCONV, "das", { OPTYPE_REG_AL | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_AF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x2F */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x30 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x31 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x32 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x33 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x34 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x35 */ + { PREFIX }, /* 0x36 */ + { NOGROUP, CPU_I386, ITYPE_BCDCONV, "aaa", { OPTYPE_REG_AL | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_AF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x37 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_E | OPTYPE_b | OP_SRC, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x38 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x39 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_G | OPTYPE_b | OP_SRC, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x3A */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_G | OPTYPE_v | OP_SRC, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x3B */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { OPTYPE_REG_AL | OP_SIGNED | OP_SRC, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x3C */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { OPTYPE_REG_xAX_BIG | OP_SIGNED | OP_SRC, AMODE_I | OPTYPE_z | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x3D */ + { PREFIX }, /* 0x3E */ + { NOGROUP, CPU_I386, ITYPE_BCDCONV, "aas", { OPTYPE_REG_AL | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_AF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x3F */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x40 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x41 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x42 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x43 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x44 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x45 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x46 */ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x47 */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x48 */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x49 */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x4A */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x4B */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x4C */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x4D */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x4E */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x4F */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x50 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x51 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x52 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x53 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x54 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x55 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x56 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OP_REG | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x57 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x58 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x59 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5A */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5B */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5C */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5D */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5E */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OP_REG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5F */ + { NOGROUP, CPU_I386, ITYPE_PUSHA, "pushad", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x60 */ + { NOGROUP, CPU_I386, ITYPE_POPA, "popad", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x61 */ + { NOGROUP, CPU_I386, ITYPE_BOUNDS, "bound", { AMODE_G | OPTYPE_v | OP_SRC, AMODE_M | OPTYPE_a | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x62 */ + { X86_Opcode_63, EXT_64 }, /* 0x63 */ + { PREFIX }, /* 0x64 */ + { PREFIX }, /* 0x65 */ + { PREFIX }, /* 0x66 */ + { PREFIX }, /* 0x67 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { AMODE_I | OPTYPE_z | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x68 */ + { NOGROUP, CPU_I386, ITYPE_MUL, "imul", { AMODE_G | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, AMODE_I | OPTYPE_z | OP_SIGNED | OP_SRC }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x69 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x6A */ + { NOGROUP, CPU_I386, ITYPE_MUL, "imul", { AMODE_G | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x6B */ + { NOGROUP, CPU_I386, ITYPE_IN, "insb", { AMODE_Y | OPTYPE_b | OP_DST, OPTYPE_REG_DX | OP_SYS | OP_SRC, 0 }, COND_D, NOCHANGE, xDI_DEC | xCX_REP_DEC, xDI_INC | xCX_REP_DEC }, /* 0x6C */ + { NOGROUP, CPU_I386, ITYPE_IN, "insd", { AMODE_Y | OPTYPE_z | OP_DST, OPTYPE_REG_DX | OP_SYS | OP_SRC, 0 }, COND_D, NOCHANGE, xDI_DECx | xCX_REP_DEC, xDI_INCx | xCX_REP_DEC }, /* 0x6D */ + { NOGROUP, CPU_I386, ITYPE_OUT, "outsb", { OPTYPE_REG_DX | OP_SYS | OP_DST, AMODE_X | OPTYPE_b | OP_SRC, 0 }, COND_D, NOCHANGE, xSI_DEC | xCX_REP_DEC, xSI_INC | xCX_REP_DEC }, /* 0x6E */ + { NOGROUP, CPU_I386, ITYPE_OUT, "outsd", { OPTYPE_REG_DX | OP_SYS | OP_DST, AMODE_X | OPTYPE_z | OP_SRC, 0 }, COND_D, NOCHANGE, xSI_DECx | xCX_REP_DEC, xSI_INCx | xCX_REP_DEC}, /* 0x6F */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jo", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_O, NOCHANGE, OP1_DST, NOACTION }, /* 0x70 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jno", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NO, NOCHANGE, OP1_DST, NOACTION }, /* 0x71 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jb", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_C, NOCHANGE, OP1_DST, NOACTION }, /* 0x72 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jnb", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NC, NOCHANGE, OP1_DST, NOACTION }, /* 0x73 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jz", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_Z, NOCHANGE, OP1_DST, NOACTION }, /* 0x74 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jnz", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NZ, NOCHANGE, OP1_DST, NOACTION }, /* 0x75 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jbe", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_BE, NOCHANGE, OP1_DST, NOACTION }, /* 0x76 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "ja", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_A, NOCHANGE, OP1_DST, NOACTION }, /* 0x77 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "js", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_S, NOCHANGE, OP1_DST, NOACTION }, /* 0x78 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jns", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NS, NOCHANGE, OP1_DST, NOACTION }, /* 0x79 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jpe", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_PE, NOCHANGE, OP1_DST, NOACTION }, /* 0x7A */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jpo", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_PO, NOCHANGE, OP1_DST, NOACTION }, /* 0x7B */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jl", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_L, NOCHANGE, OP1_DST, NOACTION }, /* 0x7C */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jge", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_GE, NOCHANGE, OP1_DST, NOACTION }, /* 0x7D */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jle", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_LE, NOCHANGE, OP1_DST, NOACTION }, /* 0x7E */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jg", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_G, NOCHANGE, OP1_DST, NOACTION }, /* 0x7F */ + { X86_Group_1_80, GROUP }, /* 0x80 Eb Ib */ + { X86_Group_1_81, GROUP }, /* 0x81 Ev Iz */ + { X86_Group_1_82, GROUP }, /* 0x82 Eb Ib */ + { X86_Group_1_83, GROUP }, /* 0x83 Ev Ib */ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { AMODE_E | OPTYPE_b | OP_SRC, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x84 */ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x85 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { AMODE_E | OPTYPE_b | OP_SRC | OP_DST, AMODE_G | OPTYPE_b | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x86 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, AMODE_G | OPTYPE_v | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x87 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_E | OPTYPE_b | OP_DST, AMODE_G | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x88 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x89 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_G | OPTYPE_b | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x8A */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x8B */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_E | OPTYPE_mw | OP_DST, AMODE_S | OPTYPE_w | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x8C */ + { NOGROUP, CPU_I386, ITYPE_LEA, "lea", { AMODE_G | OPTYPE_v | OP_DST, AMODE_M | OPTYPE_lea | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x8D */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_S | OPTYPE_w | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x8E */ + { X86_Group_10, GROUP }, /* 0x8F */ + { NOGROUP, CPU_I386, ITYPE_NOP, "nop", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x90 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x91 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x92 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x93 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x94 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x95 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x96 */ + { NOGROUP, CPU_I386, ITYPE_XCHG, "xchg", { OPTYPE_REG_xAX_BIG | OP_SRC | OP_DST, OP_REG | OP_SRC | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x97 */ + { NOGROUP, CPU_I386, ITYPE_SZCONV, "cwde", { OPTYPE_REG_xAX_BIG | OP_SIGNED | OP_DST, OPTYPE_REG_xAX_SMALL | OP_SIGNED | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x98 */ + { NOGROUP, CPU_I386, ITYPE_SZCONV, "cdq", { OPTYPE_xDX_HI_xAX_LO | OP_SIGNED | OP_DST, OPTYPE_REG_xAX_BIG | OP_SIGNED | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x99 */ + { NOGROUP, CPU_I386, ITYPE_CALL, "call", { AMODE_A | OPTYPE_p | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x9A */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "wait", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x9B */ + { NOGROUP, CPU_I386, ITYPE_PUSHF, "pushf", { OPTYPE_xFLAGS | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x9C */ + { NOGROUP, CPU_I386, ITYPE_POPF, "popf", { OPTYPE_xFLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_ALL_MOD, NOACTION, IGNORED }, /* 0x9D */ + { NOGROUP, CPU_I386, ITYPE_MOV, "sahf", { OPTYPE_FLAGS | OP_DST, OPTYPE_REG_AH | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_AF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x9E */ + { NOGROUP, CPU_I386, ITYPE_MOV, "lahf", { OPTYPE_REG_AH | OP_DST, OPTYPE_FLAGS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x9F */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG_AL | OP_DST, AMODE_O | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA0 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_O | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA1 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_O | OPTYPE_b | OP_DST, OPTYPE_REG_AL | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA2 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_O | OPTYPE_v | OP_DST, OPTYPE_REG_xAX_BIG | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA3 */ + { NOGROUP, CPU_I386, ITYPE_STRMOV, "movsb", { AMODE_Y | OPTYPE_b | OP_DST, AMODE_X | OPTYPE_b | OP_SRC, 0 }, COND_D, NOCHANGE, xDI_DEC | xSI_DEC | xCX_REP_DEC, xDI_INC | xSI_INC | xCX_REP_DEC}, /* 0xA4 */ + { NOGROUP, CPU_I386, ITYPE_STRMOV, "movsd", { AMODE_Y | OPTYPE_z | OP_DST, AMODE_X | OPTYPE_z | OP_SRC, 0 }, COND_D, NOCHANGE, xDI_DECx | xSI_DECx| xCX_REP_DEC, xDI_INCx | xSI_INCx | xCX_REP_DEC }, /* 0xA5 */ + { NOGROUP, CPU_I386, ITYPE_STRCMP, "cmpsb", { AMODE_X | OPTYPE_b | OP_SRC, AMODE_Y | OPTYPE_b | OP_SRC, 0 }, COND_D, FLAG_COMMON_MOD, xDI_DEC | xSI_DEC | xCX_REP_DEC, xDI_INC | xSI_INC | xCX_REP_DEC }, /* 0xA6 */ + { NOGROUP, CPU_I386, ITYPE_STRCMP, "cmpsd", { AMODE_X | OPTYPE_z | OP_SRC, AMODE_Y | OPTYPE_z | OP_SRC, 0 }, COND_D, FLAG_COMMON_MOD, xDI_DECx | xSI_DECx | xCX_REP_DEC, xDI_INCx | xSI_INCx | xCX_REP_DEC}, /* 0xA7 */ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { OPTYPE_REG_AL | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0xA8 */ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { OPTYPE_REG_xAX_BIG | OP_SRC, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0xA9 */ + { NOGROUP, CPU_I386, ITYPE_STRSTOR, "stosb", { AMODE_Y | OPTYPE_b | OP_DST, OPTYPE_REG_AL | OP_SRC, 0 }, COND_D, NOCHANGE, xDI_DEC | xSI_DEC | xCX_REP_DEC, xDI_INC | xSI_INC | xCX_REP_DEC }, /* 0xAA */ + { NOGROUP, CPU_I386, ITYPE_STRSTOR, "stosd", { AMODE_Y | OPTYPE_z | OP_DST, OPTYPE_REG_xAX_BIG | OP_SRC, 0 }, COND_D, NOCHANGE, xDI_DECx | xSI_DECx | xCX_REP_DEC, xDI_INCx | xSI_INCx | xCX_REP_DEC }, /* 0xAB */ + { NOGROUP, CPU_I386, ITYPE_STRLOAD, "lodsb", { OPTYPE_REG_AL | OP_DST, AMODE_X | OPTYPE_b | OP_SRC, 0 }, COND_D, NOCHANGE, xSI_DEC | xCX_REP_DEC, xSI_INC | xCX_REP_DEC }, /* 0xAC */ + { NOGROUP, CPU_I386, ITYPE_STRLOAD, "lodsd", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_X | OPTYPE_z | OP_SRC, 0 }, COND_D, NOCHANGE, xSI_DECx | xCX_REP_DEC, xSI_INCx | xCX_REP_DEC }, /* 0xAD */ + { NOGROUP, CPU_I386, ITYPE_STRCMP, "scasb", { OPTYPE_REG_AL | OP_SRC, AMODE_Y | OPTYPE_b | OP_SRC, 0 }, COND_D, FLAG_COMMON_MOD, xDI_DEC | xCX_REP_DEC, xDI_INC | xCX_REP_DEC }, /* 0xAE */ + { NOGROUP, CPU_I386, ITYPE_STRCMP, "scasd", { OPTYPE_REG_xAX_BIG | OP_SRC, AMODE_Y | OPTYPE_z | OP_SRC, 0 }, COND_D, FLAG_COMMON_MOD, xDI_DECx, xDI_INCx }, /* 0xAF */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB0 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB1 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB2 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB3 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB4 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB5 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB6 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OPTYPE_REG8 | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB7 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB8 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB9 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBA */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBB */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBC */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBD */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBE */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { OP_REG | OP_DST, AMODE_I | OPTYPE_v | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBF */ + { X86_Group_2_C0, GROUP }, /* 0xC0 Eb Ib */ + { X86_Group_2_C1, GROUP }, /* 0xC1 Ev Ib */ + { NOGROUP, CPU_I386, ITYPE_RET, "ret", { AMODE_I | OPTYPE_w | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC2 */ + { NOGROUP, CPU_I386, ITYPE_RET, "ret", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC3 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "les", { AMODE_G | OPTYPE_z | OP_DST, AMODE_M | OPTYPE_p | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC4 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "lds", { AMODE_G | OPTYPE_z | OP_DST, AMODE_M | OPTYPE_p | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC5 */ + { X86_Group_12_C6, GROUP }, /* 0xC6 Eb Ib */ + { X86_Group_12_C7, GROUP }, /* 0xC7 Ev Iz */ + { NOGROUP, CPU_I386, ITYPE_ENTER, "enter", { OPTYPE_REG_xBP | OP_SRC | OP_DST, AMODE_I | OPTYPE_w | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC8 */ + { NOGROUP, CPU_I386, ITYPE_LEAVE, "leave", { OPTYPE_REG_xBP | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC9 */ + { NOGROUP, CPU_I386, ITYPE_RET, "retf", { AMODE_I | OPTYPE_w | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCA */ + { NOGROUP, CPU_I386, ITYPE_RET, "retf", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCB */ + { NOGROUP, CPU_I386, ITYPE_DEBUG, "int3", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCC */ + { NOGROUP, CPU_I386, ITYPE_TRAP, "int", { AMODE_I | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCD */ + { NOGROUP, CPU_I386, ITYPE_OFLOW, "into", NOARGS, NOCOND, NOCHANGE, NOACTION, NOACTION }, /* 0xCE */ + { NOGROUP, CPU_I386, ITYPE_TRAPRET, "iret", NOARGS, NOCOND, FLAG_ALL_MOD, NOACTION, IGNORED }, /* 0xCF */ + { X86_Group_2_D0, GROUP }, /* 0xD0 Eb, 1 */ + { X86_Group_2_D1, GROUP }, /* 0xD1 Ev, 1 */ + { X86_Group_2_D2, GROUP }, /* 0xD2 Eb, CL */ + { X86_Group_2_D3, GROUP }, /* 0xD3 Ev, CL */ + { NOGROUP, CPU_I386, ITYPE_BCDCONV, "aam", { OPTYPE_REG_AX | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD, NOACTION, IGNORED }, /* 0xD4 */ + { NOGROUP, CPU_I386, ITYPE_BCDCONV, "aad", { OPTYPE_REG_AX | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD, NOACTION, IGNORED }, /* 0xD5 */ + { NOGROUP, CPU_I386, ITYPE_ARITH, "salc", { OPTYPE_REG_AL | OP_DST, OPTYPE_FF | OP_SRC, OPTYPE_0 | OP_SRC }, COND_C, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0xD6 */ + { NOGROUP, CPU_I386, ITYPE_XLAT, "xlat", { OPTYPE_REG_AL | OP_DST, AMODE_xlat | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD7 */ + { X86_ESC_0, EXT_FPU }, /* 0xD8 */ + { X86_ESC_1, EXT_FPU }, /* 0xD9 */ + { X86_ESC_2, EXT_FPU }, /* 0xDA */ + { X86_ESC_3, EXT_FPU }, /* 0xDB */ + { X86_ESC_4, EXT_FPU }, /* 0xDC */ + { X86_ESC_5, EXT_FPU }, /* 0xDD */ + { X86_ESC_6, EXT_FPU }, /* 0xDE */ + { X86_ESC_7, EXT_FPU }, /* 0xDF */ + { NOGROUP, CPU_I386, ITYPE_LOOPCC, "loopnz", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_REG_xCX_BIG_NZ | COND_NZ, NOCHANGE, OP1_DST | xCX_DEC, NOACTION }, /* 0xE0 */ + { NOGROUP, CPU_I386, ITYPE_LOOPCC, "loopz", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_REG_xCX_BIG_NZ | COND_Z, NOCHANGE, OP1_DST | xCX_DEC, NOACTION }, /* 0xE1 */ + { NOGROUP, CPU_I386, ITYPE_LOOPCC, "loop", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_REG_xCX_BIG_NZ, NOCHANGE, OP1_DST | xCX_DEC, NOACTION }, /* 0xE2 */ + { NOGROUP, CPU_I386, ITYPE_LOOPCC, "jecxz", { AMODE_J | OPTYPE_b | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_REG_xCX_BIG_Z, NOCHANGE, OP1_DST, NOACTION }, /* 0xE3 */ + { NOGROUP, CPU_I386, ITYPE_IN, "in", { OPTYPE_REG_AL | OP_DST, AMODE_I | OPTYPE_b | OP_SYS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, NOACTION }, /* 0xE4 */ + { NOGROUP, CPU_I386, ITYPE_IN, "in", { OPTYPE_REG_xAX_BIG | OP_DST, AMODE_I | OPTYPE_b | OP_SYS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, NOACTION }, /* 0xE5 */ + { NOGROUP, CPU_I386, ITYPE_OUT, "out", { AMODE_I | OPTYPE_b | OP_SYS | OP_DST, OPTYPE_REG_AL | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, NOACTION }, /* 0xE6 */ + { NOGROUP, CPU_I386, ITYPE_OUT, "out", { AMODE_I | OPTYPE_b | OP_SYS | OP_DST, OPTYPE_REG_xAX_BIG | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, NOACTION }, /* 0xE7 */ + { NOGROUP, CPU_I386, ITYPE_CALL, "call", { AMODE_J | OPTYPE_z | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE8 */ + { NOGROUP, CPU_I386, ITYPE_BRANCH, "jmp", { AMODE_J | OPTYPE_z | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE9 */ + { NOGROUP, CPU_I386, ITYPE_BRANCH, "jmp", { AMODE_A | OPTYPE_p | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEA */ + { NOGROUP, CPU_I386, ITYPE_BRANCH, "jmp", { AMODE_J | OPTYPE_b | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEB */ + { NOGROUP, CPU_I386, ITYPE_IN, "in", { OPTYPE_REG_AL | OP_DST, OPTYPE_REG_DX | OP_SYS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEC */ + { NOGROUP, CPU_I386, ITYPE_IN, "in", { OPTYPE_REG_xAX_BIG | OP_DST, OPTYPE_REG_DX | OP_SYS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xED */ + { NOGROUP, CPU_I386, ITYPE_OUT, "out", { OPTYPE_REG_DX | OP_SYS | OP_DST, OPTYPE_REG_AL | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEE */ + { NOGROUP, CPU_I386, ITYPE_OUT, "out", { OPTYPE_REG_DX | OP_SYS | OP_DST, OPTYPE_REG_xAX_BIG | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEF */ + { PREFIX }, /* 0xF0 */ + { NOGROUP, CPU_I386, ITYPE_DEBUG, "int1", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, // aka icebp /* 0xF1 */ + { PREFIX }, /* 0xF2 */ + { PREFIX }, /* 0xF3 */ + { NOGROUP, CPU_I386, ITYPE_HALT, "hlt", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF4 */ + { NOGROUP, CPU_I386, ITYPE_TOGCF, "cmc", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_CF_TOG, IGNORED }, /* 0xF5 */ + { X86_Group_3_F6, GROUP }, /* 0xF6 Eb */ + { X86_Group_3_F7, GROUP }, /* 0xF7 Ev */ + { NOGROUP, CPU_I386, ITYPE_CLEARCF, "clc", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_CF_CLR, NOACTION, IGNORED }, /* 0xF8 */ + { NOGROUP, CPU_I386, ITYPE_SETCF, "stc", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_CF_SET, NOACTION, IGNORED }, /* 0xF9 */ + { NOGROUP, CPU_I386, ITYPE_CLEARIF, "cli", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_IF_CLR, NOACTION, IGNORED }, /* 0xFA */ + { NOGROUP, CPU_I386, ITYPE_SETIF, "sti", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_IF_SET, NOACTION, IGNORED }, /* 0xFB */ + { NOGROUP, CPU_I386, ITYPE_CLEARDF, "cld", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_DF_CLR, NOACTION, IGNORED }, /* 0xFC */ + { NOGROUP, CPU_I386, ITYPE_SETDF, "std", { OPTYPE_FLAGS | OP_DST, 0, 0 }, NOCOND, FLAG_DF_SET, NOACTION, IGNORED }, /* 0xFD */ + { X86_Group_4, GROUP }, /* 0xFE */ + { X86_Group_5, GROUP }, /* 0xFF */ +}; + +X86_OPCODE X86_Opcodes_2[0x100] = // 2 byte opcodes +{ + { X86_Group_6, GROUP }, /* 0x00 */ + { X86_0F01_ModRM, EXT_MODRM }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "lar", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "lsl", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { X86_Opcode_0F05, EXT_64 }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "clts", { OPTYPE_CR0 | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_SYSCALLRET, "sysret", { OPTYPE_STAR_MSR | OP_MSR | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ + // 0F 07 could also be this undocumented instruction on older CPUs: + // { NOGROUP, CPU_I386, ITYPE_SYSTEM, "loadall", { AMODE_Y | OPTYPE_cpu | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ + { NOGROUP, CPU_I486, ITYPE_SYSTEM, "invd", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x08 */ + { NOGROUP, CPU_I486, ITYPE_SYSTEM, "wbinvd", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x09 */ + { NOINSTR }, /* 0x0A */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_INVALID, "undef" /* aka UD2 */, NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x0B */ + { NOINSTR }, /* 0x0C */ + { X86_Group_P, GROUP }, /* 0x0D */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "femms", { OPTYPE_FPU_TAG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x0E */ + { X86_3DNOW_0F, EXT_SUFFIX(AMODE_P | OPTYPE_q, AMODE_Q | OPTYPE_q, 0) }, /* 0x0F */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movups", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x10 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movups", { AMODE_W | OPTYPE_ps | OP_DST, AMODE_V | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x11 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movlps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x12 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movlps", { AMODE_M | OPTYPE_q | OP_DST, AMODE_V | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x13 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "unpcklps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x14 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "unpckhps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x15 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movhps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x16 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movhps", { AMODE_M | OPTYPE_q | OP_DST, AMODE_V | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x17 */ + { X86_Group_17, GROUP }, /* 0x18 */ + { NOINSTR }, /* 0x19 */ + { NOINSTR }, /* 0x1A */ + { NOINSTR }, /* 0x1B */ + { NOINSTR }, /* 0x1C */ + { NOINSTR }, /* 0x1D */ + { NOINSTR }, /* 0x1E */ + { NOINSTR }, /* 0x1F */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_R | OPTYPE_dq | OP_DST, AMODE_C | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x20 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_R | OPTYPE_dq | OP_DST, AMODE_D | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x21 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_C | OPTYPE_dq | OP_DST, AMODE_R | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x22 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_D | OPTYPE_dq | OP_DST, AMODE_R | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x23 */ + { NOINSTR }, /* 0x24 */ + //{ NOGROUP, CPU_I486, ITYPE_MOV, "mov", { AMODE_R | OPTYPE_d | OP_DST, AMODE_T | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x24 */ + { NOINSTR }, /* 0x25 */ + { NOINSTR }, /* 0x26 */ + //{ NOGROUP, CPU_I486, ITYPE_MOV, "mov", { AMODE_T | OPTYPE_d | OP_DST, AMODE_R | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x26 */ + { NOINSTR }, /* 0x27 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movaps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x28 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movaps", { AMODE_W | OPTYPE_ps | OP_DST, AMODE_V | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x29 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "cvtpi2ps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x2A */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movntps", { AMODE_M | OPTYPE_o | OP_DST, AMODE_V | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x2B */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "cvttps2pi", { AMODE_P | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x2C */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "cvtps2pi", { AMODE_P | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x2D */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_CMP, "ucomiss", { AMODE_V | OPTYPE_ss | OP_SRC, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_CF_MOD | FLAG_PF_MOD | FLAG_OF_CLR | FLAG_SF_CLR | FLAG_AF_CLR, NOACTION, IGNORED }, /* 0x2E */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_CMP, "comiss", { AMODE_V | OPTYPE_ps | OP_SRC, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_CF_MOD | FLAG_PF_MOD | FLAG_OF_CLR | FLAG_SF_CLR | FLAG_AF_CLR, NOACTION, IGNORED }, /* 0x2F */ + { NOGROUP, CPU_PENTIUM, ITYPE_SYSTEM, "wrmsr", { OPTYPE_REG_ECX | OP_MSR | OP_DST, OPTYPE_EDX_HI_EAX_LO | OP_SRC, 0 } , NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x30 */ + { NOGROUP, CPU_PENTIUM, ITYPE_SYSTEM, "rdtsc", { OPTYPE_EDX_HI_EAX_LO | OP_DST, OPTYPE_TSC | OP_MSR | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x31 */ + { NOGROUP, CPU_PENTIUM, ITYPE_SYSTEM, "rdmsr", { OPTYPE_EDX_HI_EAX_LO | OP_DST, OPTYPE_REG_ECX | OP_MSR | OP_SRC, 0 } , NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x32 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_OTHER, "rdpmc", { OPTYPE_EDX_HI_EAX_LO | OP_DST, OPTYPE_REG_ECX | OP_SYS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x33 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSCALL, "sysenter", { OPTYPE_CS_MSR | OP_MSR | OP_SRC, OPTYPE_EIP_MSR | OP_MSR | OP_SRC, OPTYPE_ESP_MSR | OP_MSR | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x34 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSCALLRET, "sysexit", { OPTYPE_CS_MSR | OP_MSR | OP_SRC, OPTYPE_EIP_MSR | OP_MSR | OP_SRC, OPTYPE_ESP_MSR | OP_MSR | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x35 */ + { NOINSTR }, /* 0x36 */ + { NOINSTR }, /* 0x37 */ + { NOINSTR }, /* 0x38 */ + { NOINSTR }, /* 0x39 */ + { NOINSTR }, /* 0x3A */ + { NOINSTR }, /* 0x3B */ + { NOINSTR }, /* 0x3C */ + { NOINSTR }, /* 0x3D */ + { NOINSTR }, /* 0x3E */ + { NOINSTR }, /* 0x3F */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovo", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_O, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x40 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovno", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_NO, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x41 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovc", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_C, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x42 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovnc", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_NC, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x43 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovz", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_Z, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x44 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovnz", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_NZ, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x45 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovbe", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_BE, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x46 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmova", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_A, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x47 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovs", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_S, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x48 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovns", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_NS, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x49 */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovpe", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_PE, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x4A */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovpo", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_PO, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x4B */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovl", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_L, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x4C */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovge", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_GE, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x4D */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovle", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_LE, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x4E */ + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_MOVCC, "cmovg", { AMODE_G | OPTYPE_v | OP_COND_DST, AMODE_E | OPTYPE_v | OP_COND_SRC, 0 }, COND_G, NOCHANGE, OP1_DST | OP2_SRC, NOACTION }, /* 0x4F */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "movmskps", { AMODE_G | OPTYPE_d | OP_DST, AMODE_VR | OPTYPE_ps| OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x50 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "sqrtps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x51 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "rsqrtps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x52 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "rcpps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x53 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_AND, "andps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x54 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_AND, "andnps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x55 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_OR, "orps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x56 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_XOR, "xorps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x57 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_ADD, "addps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x58 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MUL, "mulps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x59 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtps2pd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5A */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtdq2ps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5B */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_SUB, "subps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5C */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "minps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5D */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_DIV, "divps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5E */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "maxps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x5F */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "punpcklbw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x60 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "punpcklwd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x61 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "punpckldq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x62 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "packsswb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x63 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_CMP, "pcmpgtb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x64 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_CMP, "pcmpgtw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x65 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_CMP, "pcmpgtd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x66 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "packuswb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x67 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "punpckhbw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x68 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "punpckhwd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x69 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "punpckhdq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_d | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x6A */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "packssdw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x6B */ + { NOINSTR }, /* 0x6C */ + { NOINSTR }, /* 0x6D */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_MOV, "movd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_E | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x6E */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_MOV, "movq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x6F */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "pshufw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x70 */ + { X86_Group_13, GROUP }, /* 0x71 */ + { X86_Group_14, GROUP }, /* 0x72 */ + { X86_Group_15, GROUP }, /* 0x73 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_CMP, "pcmpeqb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x74 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_CMP, "pcmpeqw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x75 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_CMP, "pcmpeqd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x76 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "emms", { OPTYPE_FPU_TAG | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x77 */ + { NOINSTR }, /* 0x78 */ + { NOINSTR }, /* 0x79 */ + { NOINSTR }, /* 0x7A */ + { NOINSTR }, /* 0x7B */ + { NOINSTR }, /* 0x7C */ + { NOINSTR }, /* 0x7D */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_MOV, "movd", { AMODE_E | OPTYPE_dq | OP_DST, AMODE_P | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x7E */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_MOV, "movq", { AMODE_Q | OPTYPE_q | OP_DST, AMODE_P | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x7F */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jo", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_O, NOCHANGE, OP1_DST, NOACTION }, /* 0x80 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jno", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NO, NOCHANGE, OP1_DST, NOACTION }, /* 0x81 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jb", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_C, NOCHANGE, OP1_DST, NOACTION }, /* 0x82 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jnb", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NC, NOCHANGE, OP1_DST, NOACTION }, /* 0x83 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jz", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_Z, NOCHANGE, OP1_DST, NOACTION }, /* 0x84 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jnz", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NZ, NOCHANGE, OP1_DST, NOACTION }, /* 0x85 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jbe", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_BE, NOCHANGE, OP1_DST, NOACTION }, /* 0x86 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "ja", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_A, NOCHANGE, OP1_DST, NOACTION }, /* 0x87 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "js", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_S, NOCHANGE, OP1_DST, NOACTION }, /* 0x88 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jns", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_NS, NOCHANGE, OP1_DST, NOACTION }, /* 0x89 */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jpe", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_PE, NOCHANGE, OP1_DST, NOACTION }, /* 0x8A */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jpo", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_PO, NOCHANGE, OP1_DST, NOACTION }, /* 0x8B */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jl", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_L, NOCHANGE, OP1_DST, NOACTION }, /* 0x8C */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jge", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_GE, NOCHANGE, OP1_DST, NOACTION }, /* 0x8D */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jle", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_LE, NOCHANGE, OP1_DST, NOACTION }, /* 0x8E */ + { NOGROUP, CPU_I386, ITYPE_BRANCHCC, "jg", { AMODE_J | OPTYPE_z | OP_SRC | OP_COND_EXEC, 0, 0 }, COND_G, NOCHANGE, OP1_DST, NOACTION }, /* 0x8F */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "seto", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_O, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x90 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setno", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_NO, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x91 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setb", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_C, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x92 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setnb", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_NC, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x93 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "sete", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_Z, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x94 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setne", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_NZ, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x95 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setbe", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_BE, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x96 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "seta", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_A, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x97 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "sets", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_S, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x98 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setns", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_NS, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x99 */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setpe", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_PE, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x9A */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setpo", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_PO, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x9B */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setl", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_L, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x9C */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setge", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_GE, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x9D */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setle", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_LE, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x9E */ + { NOGROUP, CPU_I386, ITYPE_MOVCC, "setg", { AMODE_E | OPTYPE_b | OP_COND_DST, OPTYPE_1 | OP_COND_SRC, OPTYPE_0 | OP_COND_SRC }, COND_G, NOCHANGE, OP1_DST | OP2_SRC, OP1_DST | OP3_SRC }, /* 0x9F */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OPTYPE_FS | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA0 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OPTYPE_FS | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA1 */ + { NOGROUP, CPU_PENTIUM, ITYPE_CPUID, "cpuid", { OPTYPE_EDX_ECX_EBX_EAX | OP_DST, OPTYPE_REG_xAX_BIG | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA2 */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "bt", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xA3 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shld", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xA4 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shld", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, OPTYPE_REG_CL | OP_SRC }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xA5 */ + { NOINSTR }, /* 0xA6 */ + { NOINSTR }, /* 0xA7 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { OPTYPE_GS | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA8 */ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { OPTYPE_GS | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xA9 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "rsm", NOARGS, NOCOND, FLAG_ALL_MOD, NOACTION, IGNORED }, /* 0xAA */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "bts", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xAB */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shrd", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xAC */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shrd", { AMODE_E | OPTYPE_v | OP_DST, AMODE_G | OPTYPE_v | OP_SRC, OPTYPE_REG_CL | OP_SRC }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xAD */ + { X86_Group_16, GROUP }, /* 0xAE */ + { NOGROUP, CPU_I386, ITYPE_MUL, "imul", { AMODE_G | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xAF */ + { NOGROUP, CPU_I486, ITYPE_XCHGCC, "cmpxchg", { AMODE_E | OPTYPE_b | OP_SRC | OP_COND_DST, OPTYPE_REG_AL | OP_SRC | OP_COND_DST, AMODE_G | OPTYPE_b | OP_COND_SRC }, COND_OP1_EQ_OP2, FLAG_COMMON_MOD, OP1_DST | OP3_SRC, OP2_DST | OP1_SRC }, /* 0xB0 */ + { NOGROUP, CPU_I486, ITYPE_XCHGCC, "cmpxchg", { AMODE_E | OPTYPE_v | OP_SRC | OP_COND_DST, OPTYPE_REG_xAX_BIG | OP_SRC | OP_COND_DST, AMODE_G | OPTYPE_v | OP_COND_SRC }, COND_OP1_EQ_OP2, FLAG_COMMON_MOD, OP1_DST | OP3_SRC, OP2_DST | OP1_SRC }, /* 0xB1 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "lss", { AMODE_G | OPTYPE_z | OP_DST, AMODE_M | OPTYPE_p | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB2 */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "btr", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xB3 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "lfs", { AMODE_G | OPTYPE_z | OP_DST, AMODE_M | OPTYPE_p | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB4 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "lgs", { AMODE_G | OPTYPE_z | OP_DST, AMODE_M | OPTYPE_p | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB5 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "movzx", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB6 */ + { NOGROUP, CPU_I386, ITYPE_MOV, "movzx", { AMODE_G | OPTYPE_v | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xB7 */ + { NOINSTR }, /* 0xB8 */ + { X86_Group_11, GROUP }, /* 0xB9 */ + { X86_Group_8, GROUP }, /* 0xBA */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "btc", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_G | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0xBB */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "bsf", { AMODE_G | OPTYPE_v | OP_SRC, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, /* 0xBC */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "bsr", { AMODE_G | OPTYPE_v | OP_SRC, AMODE_E | OPTYPE_v | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, /* 0xBD */ + { NOGROUP, CPU_I386, ITYPE_MOV, "movsx", { AMODE_G | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBE */ + { NOGROUP, CPU_I386, ITYPE_MOV, "movsx", { AMODE_G | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xBF */ + { NOGROUP, CPU_I486, ITYPE_XCHGADD, "xadd", { AMODE_E | OPTYPE_b | OP_SRC | OP_DST, AMODE_G | OPTYPE_b | OP_SRC | OP_DST, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0xC0 */ + { NOGROUP, CPU_I486, ITYPE_XCHGADD, "xadd", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, AMODE_G | OPTYPE_v | OP_SRC | OP_DST, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0xC1 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_CMP, "cmpps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0xC2 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movnti", { AMODE_M | OPTYPE_dq | OP_DST, AMODE_G | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC3 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pinsrw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC4 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pextrw", { AMODE_G | OPTYPE_d | OP_DST, AMODE_PR | OPTYPE_q | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC5 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "shufps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC6 */ + { X86_Group_9, GROUP }, /* 0xC7 */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC8 */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC9 */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCA */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCB */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCC */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCD */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCE */ + { NOGROUP, CPU_I486, ITYPE_XCHG, "bswap", { OP_REG | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xCF */ + { NOINSTR }, /* 0xD0 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrlw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD1 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrld", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD2 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrlq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD3 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_ADD, "paddq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD4 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_MUL, "pmullw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD5 */ + { NOINSTR }, /* 0xD6 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pmovmskb", { AMODE_G | OPTYPE_d | OP_DST, AMODE_PR | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD7 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubusb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD8 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubusw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xD9 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pminub", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xDA */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_AND, "pand", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xDB */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddusb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xDC */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddusw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xDD */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pmaxub", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xDE */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_AND, "pandn", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xDF */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pavgb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE0 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psraw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE1 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrad", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE2 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pavgw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE3 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MUL, "pmulhuw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE4 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_MUL, "pmulhw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE5 */ + { NOINSTR }, /* 0xE6 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MOV, "movntq", { AMODE_M | OPTYPE_q | OP_DST, AMODE_P | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE7 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubsb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE8 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubsw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xE9 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pminsw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEA */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_OR, "por", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEB */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddsb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEC */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddsw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xED */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "pmaxsw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEE */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_XOR, "pxor", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xEF */ + { NOINSTR }, /* 0xF0 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psllw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF1 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "pslld", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF2 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psllq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF3 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_MUL, "pmuludq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF4 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "pmaddwd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF5 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "psadbw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF6 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "maskmovq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_PR | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF7 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF8 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xF9 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_SUB, "psubd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xFA */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_SUB, "psubq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xFB */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xFC */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xFD */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX_ADD, "paddd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xFE */ + { NOINSTR } /* 0xFF */, +}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Groups +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +X86_OPCODE X86_Group_1_80[8] = // 80 +{ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_E | OPTYPE_b | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_1_81[8] = // 81 +{ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_1_82[8] = // 82 +{ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_1_83[8] = // 83 +{ + { NOGROUP, CPU_I386, ITYPE_ADD, "add", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_OR, "or", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ADD, "adc", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sbb", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_AND, "and", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SUB, "sub", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_XOR, "xor", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_CMP, "cmp", { AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, AMODE_I | OPTYPE_b | OP_SIGNED | OP_SRC, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_2_C0[8] = // C0 +{ + { NOGROUP, CPU_I386, ITYPE_ROL, "rol", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "ror", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ROL, "rcl", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "rcr", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shl", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shr", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "sal", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "sar", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_2_C1[8] = // C1 +{ + { NOGROUP, CPU_I386, ITYPE_ROL, "rol", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "ror", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ROL, "rcl", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "rcr", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shl", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shr", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "sal", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "sar", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_2_D0[8] = // D0 +{ + { NOGROUP, CPU_I386, ITYPE_ROL, "rol", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "ror", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ROL, "rcl", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "rcr", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shl", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shr", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "sal", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "sar", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_2_D1[8] = // D1 +{ + { NOGROUP, CPU_I386, ITYPE_ROL, "rol", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "ror", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ROL, "rcl", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "rcr", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shl", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shr", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "sal", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "sar", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_1 | OP_SRC, 0 }, NOCOND, FLAG_OF_MOD | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_2_D2[8] = // D2 +{ + { NOGROUP, CPU_I386, ITYPE_ROL, "rol", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "ror", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ROL, "rcl", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "rcr", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shl", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shr", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "sal", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "sar", { AMODE_E | OPTYPE_b | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_2_D3[8] = // D3 +{ + { NOGROUP, CPU_I386, ITYPE_ROL, "rol", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "ror", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_ROL, "rcl", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_ROR, "rcr", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "shl", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "shr", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SHL, "sal", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_SHR, "sar", { AMODE_E | OPTYPE_v | OP_DST, OPTYPE_REG_CL | OP_SRC, 0 }, NOCOND, FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_3_F6[8] = // F6 +{ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { AMODE_E | OPTYPE_b | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { AMODE_E | OPTYPE_b | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_NOT, "not", { AMODE_E | OPTYPE_b | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_NEG, "neg", { AMODE_E | OPTYPE_b | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_MUL, "mul", { OPTYPE_REG_AX | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, OPTYPE_REG_AL | OP_SRC }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_MUL, "imul", { OPTYPE_REG_AX | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_b | OP_SIGNED | OP_SRC, OPTYPE_REG_AL | OP_SIGNED | OP_SRC }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_DIV, "div", { OPTYPE_REG_AX | OP_DST, AMODE_E | OPTYPE_b | OP_SRC, OPTYPE_REG_AX | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_DIV, "idiv", { OPTYPE_REG_AX | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_b | OP_SIGNED | OP_SRC, OPTYPE_REG_AX | OP_SIGNED | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED } /* 0x07 */, +}; + +X86_OPCODE X86_Group_3_F7[8] = // F7 +{ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_TEST, "test", { AMODE_E | OPTYPE_v | OP_SRC, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, FLAG_OF_CLR | FLAG_SF_MOD | FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_CLR, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_NOT, "not", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_NEG, "neg", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_MUL, "mul", { OPTYPE_xDX_HI_xAX_LO | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, OPTYPE_REG_xAX_BIG | OP_SRC }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_MUL, "imul", { OPTYPE_xDX_HI_xAX_LO | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, OPTYPE_REG_xAX_BIG | OP_SRC }, NOCOND, FLAG_OF_MOD | FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_DIV, "div", { OPTYPE_xDX_HI_xAX_LO | OP_DST, AMODE_E | OPTYPE_v | OP_SRC, OPTYPE_REG_xAX_BIG | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_DIV, "idiv", { OPTYPE_xDX_HI_xAX_LO | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_v | OP_SIGNED | OP_SRC, OPTYPE_REG_xAX_BIG | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_4[8] = // FE +{ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { AMODE_E | OPTYPE_b | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { AMODE_E | OPTYPE_b | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR } /* 0x07 */ +}; + +X86_OPCODE X86_Group_5[8] = // FF +{ + { NOGROUP, CPU_I386, ITYPE_INC, "inc", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_DEC, "dec", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, 0, 0 }, NOCOND, FLAG_OF_MOD|FLAG_SF_MOD|FLAG_ZF_MOD|FLAG_AF_MOD|FLAG_PF_MOD, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_CALL, "call", { AMODE_E | OPTYPE_v | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_CALL, "call", { AMODE_E | OPTYPE_p | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_BRANCH, "jmp", { AMODE_E | OPTYPE_v | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_BRANCH, "jmp", { AMODE_E | OPTYPE_p | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_PUSH, "push", { AMODE_E | OPTYPE_v | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_6[8] = // 0F 00 +{ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "sldt", { AMODE_E | OPTYPE_mw | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "str", { AMODE_E | OPTYPE_mw | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "lldt", { AMODE_E | OPTYPE_w | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "ltr", { AMODE_E | OPTYPE_w | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "verr", { AMODE_E | OPTYPE_w | OP_SRC, 0, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "verw", { AMODE_E | OPTYPE_w | OP_SRC, 0, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_IA64, ITYPE_BRANCH, "jmpe", { AMODE_E | OPTYPE_v | OP_SRC | OP_EXEC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOINSTR } /* 0x07 */ +}; + +X86_OPCODE X86_Group_7[8] = // 0F 01 +{ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "sgdt", { AMODE_M | OPTYPE_dt | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "sidt", { AMODE_M | OPTYPE_dt | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "lgdt", { AMODE_M | OPTYPE_dt | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "lidt", { AMODE_M | OPTYPE_dt | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "smsw", { AMODE_E | OPTYPE_mw | OP_DST, OPTYPE_CR0 | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "lmsw", { OPTYPE_CR0 | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I486, ITYPE_SYSTEM, "invlpg", { AMODE_M | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_8[8] = // 0F BA +{ + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "bt", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "bts", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "btr", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_BITTEST, "btc", { AMODE_E | OPTYPE_v | OP_SRC | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, FLAG_CF_MOD, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_9[8] = // 0F C7 +{ + { NOINSTR }, /* 0x00 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_XCHGCC, "cmpxchg8b", { AMODE_M | OPTYPE_q | OP_SRC | OP_COND_DST, OPTYPE_xDX_HI_xAX_LO | OP_SRC | OP_COND_DST, OPTYPE_xCX_HI_xBX_LO | OP_COND_SRC }, COND_OP1_EQ_OP2, FLAG_ZF_MOD, OP1_DST | OP3_SRC, OP2_DST | OP1_SRC }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_10[8] = // 8F (NOTE: AMD64 labels this Group 1A) +{ + { NOGROUP, CPU_I386, ITYPE_POP, "pop", { AMODE_E | OPTYPE_v | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_11[8] = // 0F B9 (NOTE: AMD64 labels this Group 10) +{ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_I386, ITYPE_INVALID, "undef", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED } /* 0x07 */ +}; + +X86_OPCODE X86_Group_12_C6[8] = // C6 (NOTE: AMD64 labels this Group 11) +{ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_E | OPTYPE_b | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0xC6 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_12_C7[8] = // C7 (NOTE: AMD64 labels this Group 11) +{ + { NOGROUP, CPU_I386, ITYPE_MOV, "mov", { AMODE_E | OPTYPE_v | OP_DST, AMODE_I | OPTYPE_z | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +// NOTE: the X86_SSE2_* is only followed if it is a 3-byte opcode (e.g., prefix is 66, F2, or F3) +X86_OPCODE X86_Group_13[8] = // 0F 71 (NOTE: AMD64 labels this Group 12) +{ + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrlw", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psraw", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psllw", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_14[8] = // 0F 72 (NOTE: AMD64 labels this Group 13) +{ + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrld", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrad", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "pslld", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_15[8] = // 0F 73 (NOTE: AMD64 labels this Group 14) +{ + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrlq", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psrldq", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "psllq", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_MMX, "pslldq", { AMODE_PR | OPTYPE_q | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED } /* 0x07 */ +}; + +X86_OPCODE X86_Group_16[8] = // 0F AE (NOTE: AMD64 labels this Group 15) +{ + { NOGROUP, CPU_PENTIUM2, ITYPE_FPU, "fxsave", { AMODE_M | OPTYPE_fst2 | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_FPU, "fxrstor", { AMODE_M | OPTYPE_fst2 | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "ldmxcsr", { AMODE_M | OPTYPE_d | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "stmxcsr", { AMODE_M | OPTYPE_d | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "lfence", NOARGS, NOCOND, NOCHANGE, SERIALIZE_READ, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "mfence", NOARGS, NOCOND, NOCHANGE, SERIALIZE_ALL, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "sfence", NOARGS, NOCOND, NOCHANGE, SERIALIZE_WRITE, IGNORED } /* 0x07 */ +}; + +X86_OPCODE X86_Group_17[8] = // 0F 18 (NOTE: AMD64 labels this Group 16) +{ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "prefetchnta", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x00 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "prefetcht0", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "prefetcht1", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "prefetcht2", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "hintnop", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "hintnop", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "hintnop", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_PENTIUM2, ITYPE_SYSTEM, "hintnop", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ +}; + +X86_OPCODE X86_Group_P[8] = // 0F 0D +{ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "prefetch", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x01 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "prefetchw", { AMODE_E | OPTYPE_b | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// FPU (ESC) opcodes +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +X86_OPCODE X86_ESC_0[0x48] = // D8 +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x00 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x01 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { AMODE_M | OPTYPE_ss | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // 0x02 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { AMODE_M | OPTYPE_ss | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // 0x03 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x04 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x05 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x06 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_ss | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x07 + + // + // ModRM >= C0: ST(0) <- ST(0) + ST(i) + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // C8-CF + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + // D0-D7 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x7 + // D8-DF + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xF + // E0-E7 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // E8-EF + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xF + // F0-F7 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // F8-FF + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED } // xF +}; + + +X86_OPCODE X86_ESC_1[0x48] = // D9 +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { AMODE_M | OPTYPE_ss | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // 0x00 + { NOINSTR }, // 0x01 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { AMODE_M | OPTYPE_ss | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x02 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { AMODE_M | OPTYPE_ss | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x03 + { NOGROUP, CPU_I287, ITYPE_FLOADENV, "fldenv", { AMODE_M | OPTYPE_fev | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // 0x04 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldcw", { OPTYPE_FPU_CONTROL | OP_DST, AMODE_M | OPTYPE_w | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // 0x05 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstenv", { AMODE_M | OPTYPE_fev | OP_DST, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // 0x06 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fnstcw", { AMODE_M | OPTYPE_w | OP_DST, OPTYPE_FPU_CONTROL | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // 0x07 + + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { OPTYPE_STx | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x7 + // C8-CF + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FEXCH, "fxch", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_STx | OP_SRC | OP_DST, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xF + // D0-D7 + { NOGROUP, CPU_I287, ITYPE_FPU, "fnop", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // D8-DF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + // E0-E7 + { NOGROUP, CPU_I287, ITYPE_FPU, "fchs", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FPU, "fabs", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOGROUP, CPU_I287, ITYPE_FPU, "ftst", { OPTYPE_ST0 | OP_SRC, OPTYPE_FLDZ | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FPU, "fxam", { OPTYPE_ST0 | OP_SRC, 0, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // E8-EF + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld1", { OPTYPE_FLD1 | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldl2t", { OPTYPE_FLDL2T | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldl2e", { OPTYPE_FLDL2E | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldpi", { OPTYPE_FLDPI | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldlg2", { OPTYPE_FLDLG2| OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldln2", { OPTYPE_FLDLN2 | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fldz", { OPTYPE_FLDZ | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // xE + { NOINSTR }, // xF + // F0-F7 + { NOGROUP, CPU_I287, ITYPE_FPU, "f2xm1", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FPU, "fyl2x", { OPTYPE_ST1 | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FPU, "fptan", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD|FPU_C2_MOD, FPU_STACK_PUSH, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FPU, "fpatan", { OPTYPE_ST1 | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC , 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FPU, "fxtract", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_ST1 | OP_DST, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x4 + { NOGROUP, CPU_I387, ITYPE_FPU, "fprem1", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_ST1 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FPU, "fdecstp", NOARGS, NOCOND, FPU_C1_MOD, FPU_STACK_DEC, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FPU, "fincstp", NOARGS, NOCOND, FPU_C1_MOD, FPU_STACK_INC, IGNORED }, // x7 + // F8-FF + { NOGROUP, CPU_I287, ITYPE_FPU, "fprem", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_ST1 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FPU, "fyl2xp1", { OPTYPE_ST1 | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FPU, "fsqrt", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FPU, "fsincos", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD|FPU_C2_MOD, FPU_STACK_PUSH, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FPU, "frndint", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FPU, "fscale", { OPTYPE_ST0 | OP_SRC | OP_DST, OPTYPE_ST1 | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FPU, "fsin", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD|FPU_C2_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FPU, "fcos", { OPTYPE_ST0 | OP_SRC | OP_DST, 0, 0 }, NOCOND, FPU_C1_MOD|FPU_C2_MOD, NOACTION, IGNORED } // xF +}; + + +X86_OPCODE X86_ESC_2[0x48] = // DA +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FADD, "fiadd", { OPTYPE_ST0 | OP_SIGNED | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fimul", { OPTYPE_ST0 | OP_SIGNED | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "ficom", { AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, OPTYPE_ST0 | OP_SRC | OP_DST, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "ficomp", { AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, OPTYPE_ST0 | OP_SRC | OP_DST, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fisub", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fisubr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fidiv", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fidivr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x0 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x1 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x2 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x3 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x4 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x5 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x6 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_B, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x7 + // C8-CF + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x8 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x9 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xA + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xB + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xC + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xD + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xE + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmove", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_E, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xF + // D0-D7 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x0 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x1 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x2 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x3 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x4 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x5 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x6 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_BE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x7 + // D8-DF + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x8 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x9 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xA + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xB + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xC + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xD + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xE + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FMOVCC, "fcmovu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_COND_SRC, 0 }, COND_U, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xF + // E0-E7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // E8-EF + { NOINSTR }, // x8 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucompp", { OPTYPE_ST1 | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP2, IGNORED }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + // F0-F7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // F8-FF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR } // xF +}; + + + +X86_OPCODE X86_ESC_3[0x48] = // DB +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fild", { AMODE_M | OPTYPE_d | OP_SIGNED | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // 0x00 + { NOGROUP, CPU_PENTIUM4, ITYPE_FSTORE, "fisttp", { AMODE_M | OPTYPE_d | OP_SIGNED | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x01 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fist", { AMODE_M | OPTYPE_d | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x02 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fistp", { AMODE_M | OPTYPE_d | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x03 + { NOINSTR }, // 0x04 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { AMODE_M | OPTYPE_se | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // 0x05 + { NOINSTR }, // 0x06 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { AMODE_M | OPTYPE_se | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x07 + + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x0 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x1 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x2 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x3 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x4 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x5 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x6 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnb", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NB, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x7 + // C8-CF + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x8 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x9 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xA + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xB + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xC + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xD + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xE + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovne", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xF + // D0-D7 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x0 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x1 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x2 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x3 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x4 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x5 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x6 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnbe", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NBE, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x7 + // D8-DF + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x8 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // x9 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xA + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xB + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xC + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xD + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xE + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FPU, "fcmovnu", { OPTYPE_ST0 | OP_COND_DST, OPTYPE_STx | OP_SRC, 0 }, COND_NU, FPU_C1_MOD, OP1_DST | OP2_SRC, NOACTION }, // xF + // E0-E7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOGROUP, CPU_I287, ITYPE_FPU, "fnclex", { OPTYPE_FPU_STATUS | OP_DST, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FPU, "finit", { OPTYPE_FPU_STATUS | OP_DST, 0, 0 }, NOCOND, FPU_ALL_CLR, NOACTION, IGNORED }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // E8-EF + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // xF + // F0-F7 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomi", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, NOACTION, IGNORED }, // x7 + // F8-FF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR } // xF +}; + +X86_OPCODE X86_ESC_4[0x48] = // DC +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x00 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x01 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcom", { AMODE_M | OPTYPE_sd | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // 0x02 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcomp", { AMODE_M | OPTYPE_sd | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // 0x03 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x04 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x05 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x06 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x07 + + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FADD, "fadd", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // C8-CF + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmul", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xF + // D0-D7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // D8-DF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + // E0-E7 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // E8-EF + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsub", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xF + // F0-F7 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivr", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // F8-FF + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdiv", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED } // xF +}; + + +X86_OPCODE X86_ESC_5[0x48] = // DD +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + // + + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fld", { AMODE_M | OPTYPE_sd | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_FSTORE, "fisttp", { AMODE_M | OPTYPE_d | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { AMODE_M | OPTYPE_sd | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { AMODE_M | OPTYPE_sd | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FRESTORE, "frstor", { AMODE_M | OPTYPE_fst1 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x4 + { NOINSTR }, // x5 + { NOGROUP, CPU_I287, ITYPE_FSAVE, "fsave", { AMODE_M | OPTYPE_fst1 | OP_DST, 0 }, NOCOND, FPU_ALL_CLR, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fnstsw", { AMODE_M | OPTYPE_w | OP_DST, OPTYPE_FPU_STATUS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FPU, "ffree", { OPTYPE_FPU_TAG | OP_DST, OPTYPE_STx | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + // C8-CF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + // D0-D7 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fst", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // x7 + // D8-DF + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fstp", { OPTYPE_STx | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xF + // E0-E7 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucom", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // x7 + // E8-EF + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_I387, ITYPE_FCOMP, "fucomp", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xF + // F0-F7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // F8-FF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR } // xF +}; + + +X86_OPCODE X86_ESC_6[0x48] = // DE +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FADD, "fiadd", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x00 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fimul", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x01 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "ficom", { AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, NOACTION, IGNORED }, // 0x02 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "ficomp", { AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // 0x03 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fisub", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x04 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fisubr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x05 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fidiv", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x06 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fidivr", { OPTYPE_ST0 | OP_SRC | OP_DST, AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x07 + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + + // C0-C7 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FADD, "faddp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x7 + // C8-CF + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FMUL, "fmulp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xF + // D0-D7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // D8-DF + { NOINSTR }, // x8 + { NOGROUP, CPU_I287, ITYPE_FCOMP, "fcompp", { OPTYPE_ST1 | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_ALL_MOD, FPU_STACK_POP2, IGNORED }, // x9 + { NOINSTR }, // 0xA + { NOINSTR }, // 0xB + { NOINSTR }, // 0xC + { NOINSTR }, // 0xD + { NOINSTR }, // 0xE + { NOINSTR }, // 0xF + // E0-E7 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x7 + // E8-EF + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FSUB, "fsubp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xF + // F0-F7 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x0 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x1 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x2 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x4 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x5 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x6 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivrp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x7 + // F8-FF + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_I287, ITYPE_FDIV, "fdivp", { OPTYPE_STx | OP_SRC | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED } // xF +}; + + +X86_OPCODE X86_ESC_7[0x48] = // DF +{ + // + // ModRM < C0 + // Index 0x00-0x07 = opcode extension + // + + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fild", { AMODE_M | OPTYPE_w | OP_SIGNED | OP_SRC, 0, 0}, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // 0x00 + { NOGROUP, CPU_PENTIUM4, ITYPE_FSTORE, "fisttp", { AMODE_M | OPTYPE_w | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x01 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fist", { AMODE_M | OPTYPE_w | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, NOACTION, IGNORED }, // 0x02 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fistp", { AMODE_M | OPTYPE_w | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x03 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fbld", { AMODE_M | OPTYPE_pb | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // 0x04 + { NOGROUP, CPU_I287, ITYPE_FLOAD, "fild", { AMODE_M | OPTYPE_q | OP_SIGNED | OP_SRC, 0, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_PUSH, IGNORED }, // 0x05 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fbstp", { AMODE_M | OPTYPE_pb | OP_DST, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x06 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fistp", { AMODE_M | OPTYPE_q | OP_SIGNED | OP_DST, OPTYPE_ST0 | OP_SRC, 0}, NOCOND, FPU_C1_MOD, FPU_STACK_POP, IGNORED }, // 0x07 + + // + // ModRM >= C0 + // Index 0x08-0x47 = ModRM 0xC0-0xFF + // + // C0-C7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // C8-CF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + // D0-D7 + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // D8-DF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + // E0-E7 + { NOGROUP, CPU_I287, ITYPE_FSTORE, "fnstsw", { OPTYPE_REG_AX | OP_DST, OPTYPE_FPU_STATUS | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + // E8-EF + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fucomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // xF + // F0-F7 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM_PRO, ITYPE_FCOMP, "fcomip", { OPTYPE_STx | OP_SRC, OPTYPE_ST0 | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_PF_MOD | FLAG_CF_MOD | FPU_ALL_MOD, FPU_STACK_POP, IGNORED }, // x7 + // F8-FF + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR } // xF +}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// SSE opcodes +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +X86_OPCODE X86_SSE[0x300] = +{ + // prefix 0x66 (operand size) + /* 0x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 1x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movupd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movupd", { AMODE_W | OPTYPE_pd | OP_DST, AMODE_V | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movlpd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_M | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movlpd", { AMODE_M | OPTYPE_q | OP_DST, AMODE_V | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "unpcklpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "unpckhpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movhpd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_M | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "mpvhpd", { AMODE_M | OPTYPE_q | OP_DST, AMODE_V | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 2x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movapd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movapd", { AMODE_W | OPTYPE_o | OP_DST, AMODE_V | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtpi2pd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movntpd", { AMODE_M | OPTYPE_o | OP_DST, AMODE_V | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvttpd2pi", { AMODE_P | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtpd2pi", { AMODE_P | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "ucomisd", { AMODE_V | OPTYPE_sd | OP_SRC, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_CF_MOD | FLAG_PF_MOD | FLAG_OF_CLR | FLAG_SF_CLR | FLAG_AF_CLR, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "comisd", { AMODE_V | OPTYPE_pd | OP_SRC, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD | FLAG_CF_MOD | FLAG_PF_MOD | FLAG_OF_CLR | FLAG_SF_CLR | FLAG_AF_CLR, NOACTION, IGNORED }, // xF + + /* 3x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 4x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 5x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "movmskpd", { AMODE_G | OPTYPE_d | OP_DST, AMODE_VR | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "sqrtpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_AND, "andpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_AND, "andnpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_OR, "orpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_XOR, "xorpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "addpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "mulpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtpd2ps", { AMODE_V | OPTYPE_ps | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtps2dq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "subpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "minpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_DIV, "divpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "maxpd", { AMODE_V | OPTYPE_pd | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 6x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpcklbw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpcklwd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpckldq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "packsswb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pcmpgtb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pcmpgtw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pcmpgtd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "packuswb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpckhbw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpckhwd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpckhdq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "packssdw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpcklqdq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "punpckhqdq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_E | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movdqa", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 7x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pshufd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { X86_SSE2_Group_13, GROUP }, // x1 + { X86_SSE2_Group_14, GROUP }, // x2 + { X86_SSE2_Group_15, GROUP }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "pcmpeqb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "pcmpeqw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "pcmpeqd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_ADD, "haddpd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_SUB, "hsubpd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movd", { AMODE_E | OPTYPE_dq | OP_DST, AMODE_V | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movdqa", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 8x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 9x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Ax */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Bx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Cx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "cmppd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, // x2 + { NOINSTR }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pinsrw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_E | OPTYPE_w | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pextrw", { AMODE_G | OPTYPE_d | OP_DST, AMODE_VR| OPTYPE_o | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "shufpd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Dx */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3, "addsubpd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrlw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrld", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrlq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "pmullw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movq", { AMODE_W | OPTYPE_q | OP_DST, AMODE_V | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pmovmskb", { AMODE_G | OPTYPE_d | OP_DST, AMODE_VR| OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubusb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubusw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pminub", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_AND, "pand", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddusb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddusw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pmaxub", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_AND, "pandn", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* Ex */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pavgb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psraw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrad", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pavgw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "pmulhuw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "pmulhw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvttpd2dq", { AMODE_V | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movntdq", { AMODE_M | OPTYPE_o | OP_DST, AMODE_V | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubsb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubsw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pminsw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_OR, "por", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddsb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddsw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pmaxuw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_XOR, "pxor", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* Fx */ + { NOINSTR }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psllw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pslld", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psllq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "pmuludq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x4 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "pmaddwd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psadbw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "maskmovdqu", { AMODE_V | OPTYPE_o | OP_DST, AMODE_VR| OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "psubq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddb", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddw", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "paddd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOINSTR }, // xF + + // prefix 0xf2 (repne) + /* 0x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 1x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movsd", { AMODE_V | OPTYPE_sdo | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movsd", { AMODE_W | OPTYPE_sd | OP_DST, AMODE_V | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_MOV, "movddup", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 2x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtsi2sd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_E | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOINSTR }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvttsd2si", { AMODE_G | OPTYPE_dq | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtsd2si", { AMODE_G | OPTYPE_dq | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 3x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 4x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 5x */ + { NOINSTR }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "sqrtsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "addsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "mulsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtsd2ss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOINSTR }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "subsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "minsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_DIV, "divsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "maxsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 6x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movdqa", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 7x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pshuflw", { AMODE_V | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_ADD, "haddps", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_SUB, "hsubps", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 8x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 9x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Ax */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Bx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Cx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_CMP, "cmpsd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_sd | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Dx */ + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE3, "addsubps", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movdq2q", { AMODE_P | OPTYPE_q | OP_DST, AMODE_VR | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Ex */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtpd2dq", { AMODE_V | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_pd | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Fx */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3, "lddqu", { AMODE_V | OPTYPE_o | OP_DST, AMODE_M | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + // prefix 0xf3 (rep) + /* 0x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 1x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movss", { AMODE_V | OPTYPE_sso | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movss", { AMODE_W | OPTYPE_ss | OP_DST, AMODE_V | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_MOV, "movsldup", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE3_MOV, "movshdup", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 2x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "cvtsi2ss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_E | OPTYPE_dq | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOINSTR }, // xB + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "cvttss2si", { AMODE_G | OPTYPE_dq | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE, "cvtss2si", { AMODE_G | OPTYPE_dq | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 3x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 4x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 5x */ + { NOINSTR }, // x0 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "sqrtss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x1 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "rsqrtss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x2 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "rcpss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_ADD, "addss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MUL, "mulss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x9 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtss2sd", { AMODE_V | OPTYPE_sd | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xA + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvttps2dq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_ps | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xB + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_SUB, "subss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xC + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "minss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_DIV, "divss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "maxss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 6x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movdqu", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 7x */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pshufhw", { AMODE_V | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movq", { AMODE_V | OPTYPE_q | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xE + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movdqu", { AMODE_W | OPTYPE_o | OP_DST, AMODE_V | OPTYPE_o | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // xF + + /* 8x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* 9x */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Ax */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Bx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Cx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOGROUP, CPU_PENTIUM3, ITYPE_SSE_CMP, "cmpss", { AMODE_V | OPTYPE_ss | OP_DST, AMODE_W | OPTYPE_ss | OP_SRC, AMODE_I | OPTYPE_b | OP_SRC }, NOCOND, FLAG_COMMON_MOD, NOACTION, IGNORED }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Dx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2_MOV, "movq2dq", { AMODE_V | OPTYPE_o | OP_DST, AMODE_PR | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Ex */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "cvtdq2pd", { AMODE_V | OPTYPE_o | OP_DST, AMODE_W | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR }, // xF + + /* Fx */ + { NOINSTR }, // x0 + { NOINSTR }, // x1 + { NOINSTR }, // x2 + { NOINSTR }, // x3 + { NOINSTR }, // x4 + { NOINSTR }, // x5 + { NOINSTR }, // x6 + { NOINSTR }, // x7 + { NOINSTR }, // x8 + { NOINSTR }, // x9 + { NOINSTR }, // xA + { NOINSTR }, // xB + { NOINSTR }, // xC + { NOINSTR }, // xD + { NOINSTR }, // xE + { NOINSTR } // xF +}; + +X86_OPCODE X86_SSE2_Group_13[24] = // 66/F2/F3 0F 71 +{ + // prefix 0x66 (operand size) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrlw", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psraw", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psllw", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ + + // prefix 0xf2 (repne) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ + + // prefix 0xf3 (rep) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_SSE2_Group_14[24] = // 66/F2/F3 0F 72 +{ + // prefix 0x66 (operand size) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrld", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrad", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pslld", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ + + // prefix 0xf2 (repne) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ + + // prefix 0xf3 (rep) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +X86_OPCODE X86_SSE2_Group_15[24] = +{ + // prefix 0x66 (operand size) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrlq", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x02 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psrldq", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "psllq", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x06 */ + { NOGROUP, CPU_PENTIUM4, ITYPE_SSE2, "pslldq", { AMODE_VR | OPTYPE_o | OP_DST, AMODE_I | OPTYPE_b | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0x07 */ + + // prefix 0xf2 (repne) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ + + // prefix 0xf3 (rep) + { NOINSTR }, /* 0x00 */ + { NOINSTR }, /* 0x01 */ + { NOINSTR }, /* 0x02 */ + { NOINSTR }, /* 0x03 */ + { NOINSTR }, /* 0x04 */ + { NOINSTR }, /* 0x05 */ + { NOINSTR }, /* 0x06 */ + { NOINSTR }, /* 0x07 */ +}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// 3DNow opcodes +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +X86_OPCODE X86_3DNOW_0F[0x100] = +{ + { NOINSTR }, /* 00 */ + { NOINSTR }, /* 01 */ + { NOINSTR }, /* 02 */ + { NOINSTR }, /* 03 */ + { NOINSTR }, /* 04 */ + { NOINSTR }, /* 05 */ + { NOINSTR }, /* 06 */ + { NOINSTR }, /* 07 */ + { NOINSTR }, /* 08 */ + { NOINSTR }, /* 09 */ + { NOINSTR }, /* 0A */ + { NOINSTR }, /* 0B */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pi2fw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0C */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pi2fd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 0D */ + { NOINSTR }, /* 0E */ + { NOINSTR }, /* 0F */ + { NOINSTR }, /* 10 */ + { NOINSTR }, /* 11 */ + { NOINSTR }, /* 12 */ + { NOINSTR }, /* 13 */ + { NOINSTR }, /* 14 */ + { NOINSTR }, /* 15 */ + { NOINSTR }, /* 16 */ + { NOINSTR }, /* 17 */ + { NOINSTR }, /* 18 */ + { NOINSTR }, /* 19 */ + { NOINSTR }, /* 1A */ + { NOINSTR }, /* 1B */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pf2iw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 1C */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pf2id", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 1D */ + { NOINSTR }, /* 1E */ + { NOINSTR }, /* 1F */ + { NOINSTR }, /* 20 */ + { NOINSTR }, /* 21 */ + { NOINSTR }, /* 22 */ + { NOINSTR }, /* 23 */ + { NOINSTR }, /* 24 */ + { NOINSTR }, /* 25 */ + { NOINSTR }, /* 26 */ + { NOINSTR }, /* 27 */ + { NOINSTR }, /* 28 */ + { NOINSTR }, /* 29 */ + { NOINSTR }, /* 2A */ + { NOINSTR }, /* 2B */ + { NOINSTR }, /* 2C */ + { NOINSTR }, /* 2D */ + { NOINSTR }, /* 2E */ + { NOINSTR }, /* 2F */ + { NOINSTR }, /* 30 */ + { NOINSTR }, /* 31 */ + { NOINSTR }, /* 32 */ + { NOINSTR }, /* 33 */ + { NOINSTR }, /* 34 */ + { NOINSTR }, /* 35 */ + { NOINSTR }, /* 36 */ + { NOINSTR }, /* 37 */ + { NOINSTR }, /* 38 */ + { NOINSTR }, /* 39 */ + { NOINSTR }, /* 3A */ + { NOINSTR }, /* 3B */ + { NOINSTR }, /* 3C */ + { NOINSTR }, /* 3D */ + { NOINSTR }, /* 3E */ + { NOINSTR }, /* 3F */ + { NOINSTR }, /* 40 */ + { NOINSTR }, /* 41 */ + { NOINSTR }, /* 42 */ + { NOINSTR }, /* 43 */ + { NOINSTR }, /* 44 */ + { NOINSTR }, /* 45 */ + { NOINSTR }, /* 46 */ + { NOINSTR }, /* 47 */ + { NOINSTR }, /* 48 */ + { NOINSTR }, /* 49 */ + { NOINSTR }, /* 4A */ + { NOINSTR }, /* 4B */ + { NOINSTR }, /* 4C */ + { NOINSTR }, /* 4D */ + { NOINSTR }, /* 4E */ + { NOINSTR }, /* 4F */ + { NOINSTR }, /* 50 */ + { NOINSTR }, /* 51 */ + { NOINSTR }, /* 52 */ + { NOINSTR }, /* 53 */ + { NOINSTR }, /* 54 */ + { NOINSTR }, /* 55 */ + { NOINSTR }, /* 56 */ + { NOINSTR }, /* 57 */ + { NOINSTR }, /* 58 */ + { NOINSTR }, /* 59 */ + { NOINSTR }, /* 5A */ + { NOINSTR }, /* 5B */ + { NOINSTR }, /* 5C */ + { NOINSTR }, /* 5D */ + { NOINSTR }, /* 5E */ + { NOINSTR }, /* 5F */ + { NOINSTR }, /* 60 */ + { NOINSTR }, /* 61 */ + { NOINSTR }, /* 62 */ + { NOINSTR }, /* 63 */ + { NOINSTR }, /* 64 */ + { NOINSTR }, /* 65 */ + { NOINSTR }, /* 66 */ + { NOINSTR }, /* 67 */ + { NOINSTR }, /* 68 */ + { NOINSTR }, /* 69 */ + { NOINSTR }, /* 6A */ + { NOINSTR }, /* 6B */ + { NOINSTR }, /* 6C */ + { NOINSTR }, /* 6D */ + { NOINSTR }, /* 6E */ + { NOINSTR }, /* 6F */ + { NOINSTR }, /* 70 */ + { NOINSTR }, /* 71 */ + { NOINSTR }, /* 72 */ + { NOINSTR }, /* 73 */ + { NOINSTR }, /* 74 */ + { NOINSTR }, /* 75 */ + { NOINSTR }, /* 76 */ + { NOINSTR }, /* 77 */ + { NOINSTR }, /* 78 */ + { NOINSTR }, /* 79 */ + { NOINSTR }, /* 7A */ + { NOINSTR }, /* 7B */ + { NOINSTR }, /* 7C */ + { NOINSTR }, /* 7D */ + { NOINSTR }, /* 7E */ + { NOINSTR }, /* 7F */ + { NOINSTR }, /* 80 */ + { NOINSTR }, /* 81 */ + { NOINSTR }, /* 82 */ + { NOINSTR }, /* 83 */ + { NOINSTR }, /* 84 */ + { NOINSTR }, /* 85 */ + { NOINSTR }, /* 86 */ + { NOINSTR }, /* 87 */ + { NOINSTR }, /* 88 */ + { NOINSTR }, /* 89 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfnacc", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 8A */ + { NOINSTR }, /* 8B */ + { NOINSTR }, /* 8C */ + { NOINSTR }, /* 8D */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfpnacc", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 8E */ + { NOINSTR }, /* 8F */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_CMP, "pfcmpge", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 90 */ + { NOINSTR }, /* 91 */ + { NOINSTR }, /* 92 */ + { NOINSTR }, /* 93 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfmin", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 94 */ + { NOINSTR }, /* 95 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfrcp", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 96 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfrsqrt", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 97 */ + { NOINSTR }, /* 98 */ + { NOINSTR }, /* 99 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_SUB, "pfsub", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 9A */ + { NOINSTR }, /* 9B */ + { NOINSTR }, /* 9C */ + { NOINSTR }, /* 9D */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_ADD, "pfadd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* 9E */ + { NOINSTR }, /* 9F */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_CMP, "pfcmpgt", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* A0 */ + { NOINSTR }, /* A1 */ + { NOINSTR }, /* A2 */ + { NOINSTR }, /* A3 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfmax", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* A4 */ + { NOINSTR }, /* A5 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfrcpit1", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* A6 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfrsqit1", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* A7 */ + { NOINSTR }, /* A8 */ + { NOINSTR }, /* A9 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_SUB, "pfsubr", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* AA */ + { NOINSTR }, /* AB */ + { NOINSTR }, /* AC */ + { NOINSTR }, /* AD */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfacc", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* AE */ + { NOINSTR }, /* AF */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_CMP, "pfcmpeq", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* B0 */ + { NOINSTR }, /* B1 */ + { NOINSTR }, /* B2 */ + { NOINSTR }, /* B3 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_MUL, "pfmul", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* B4 */ + { NOINSTR }, /* B5 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pfrcpit2", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* B6 */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_MUL, "pmulhrw", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* B7 */ + { NOINSTR }, /* B8 */ + { NOINSTR }, /* B9 */ + { NOINSTR }, /* BA */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW_XCHG, "pswapd", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* BB */ + { NOINSTR }, /* BC */ + { NOINSTR }, /* BD */ + { NOINSTR }, /* BE */ + { NOGROUP, CPU_AMD_K6_2, ITYPE_3DNOW, "pavgb", { AMODE_P | OPTYPE_q | OP_DST, AMODE_Q | OPTYPE_q | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, /* BF */ + { NOINSTR }, /* C0 */ + { NOINSTR }, /* C1 */ + { NOINSTR }, /* C2 */ + { NOINSTR }, /* C3 */ + { NOINSTR }, /* C4 */ + { NOINSTR }, /* C5 */ + { NOINSTR }, /* C6 */ + { NOINSTR }, /* C7 */ + { NOINSTR }, /* C8 */ + { NOINSTR }, /* C9 */ + { NOINSTR }, /* CA */ + { NOINSTR }, /* CB */ + { NOINSTR }, /* CC */ + { NOINSTR }, /* CD */ + { NOINSTR }, /* CE */ + { NOINSTR }, /* CF */ + { NOINSTR }, /* D0 */ + { NOINSTR }, /* D1 */ + { NOINSTR }, /* D2 */ + { NOINSTR }, /* D3 */ + { NOINSTR }, /* D4 */ + { NOINSTR }, /* D5 */ + { NOINSTR }, /* D6 */ + { NOINSTR }, /* D7 */ + { NOINSTR }, /* D8 */ + { NOINSTR }, /* D9 */ + { NOINSTR }, /* DA */ + { NOINSTR }, /* DB */ + { NOINSTR }, /* DC */ + { NOINSTR }, /* DD */ + { NOINSTR }, /* DE */ + { NOINSTR }, /* DF */ + { NOINSTR }, /* E0 */ + { NOINSTR }, /* E1 */ + { NOINSTR }, /* E2 */ + { NOINSTR }, /* E3 */ + { NOINSTR }, /* E4 */ + { NOINSTR }, /* E5 */ + { NOINSTR }, /* E6 */ + { NOINSTR }, /* E7 */ + { NOINSTR }, /* E8 */ + { NOINSTR }, /* E9 */ + { NOINSTR }, /* EA */ + { NOINSTR }, /* EB */ + { NOINSTR }, /* EC */ + { NOINSTR }, /* ED */ + { NOINSTR }, /* EE */ + { NOINSTR }, /* EF */ + { NOINSTR }, /* F0 */ + { NOINSTR }, /* F1 */ + { NOINSTR }, /* F2 */ + { NOINSTR }, /* F3 */ + { NOINSTR }, /* F4 */ + { NOINSTR }, /* F5 */ + { NOINSTR }, /* F6 */ + { NOINSTR }, /* F7 */ + { NOINSTR }, /* F8 */ + { NOINSTR }, /* F9 */ + { NOINSTR }, /* FA */ + { NOINSTR }, /* FB */ + { NOINSTR }, /* FC */ + { NOINSTR }, /* FD */ + { NOINSTR }, /* FE */ + { NOINSTR } /* FF */ +}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// 64-bit replacement opcodes +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +X86_OPCODE X86_Opcode_63[2] = +{ + { NOGROUP, CPU_I386, ITYPE_SYSTEM, "arpl", { AMODE_E | OPTYPE_w | OP_SRC, AMODE_G | OPTYPE_w | OP_SRC, 0 }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, // !ARCH_AMD64 + { NOGROUP, CPU_AMD64, ITYPE_MOV, "movsxd", { AMODE_G | OPTYPE_v | OP_SIGNED | OP_DST, AMODE_E | OPTYPE_d | OP_SIGNED | OP_SRC, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED } // ARCH_AMD64 +}; + +X86_OPCODE X86_Opcode_0F05[2] = +{ + { NOGROUP, CPU_AMD_K6_2, ITYPE_SYSCALL, "syscall", { OPTYPE_STAR_MSR | OP_MSR | OP_SRC, OPTYPE_CSTAR_MSR | OP_MSR | OP_SRC, OPTYPE_FMASK_MSR | OP_MSR | OP_SRC }, NOCOND, FLAG_ZF_MOD, NOACTION, IGNORED }, // !ARCH_AMD64 + { NOGROUP, CPU_AMD64, ITYPE_SYSCALL, "syscall", { OPTYPE_STAR_MSR | OP_MSR | OP_SRC, OPTYPE_LSTAR_MSR | OP_MSR | OP_SRC, OPTYPE_FMASK_MSR | OP_MSR | OP_SRC }, NOCOND, NOCHANGE, NOACTION, IGNORED } // ARCH_AMD64 +}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Other 3 byte opcodes +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +// Three byte opcodes where the third opcode byte is ModRM +X86_OPCODE X86_0F01_ModRM[0x100] = +{ + /* 0x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 1x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 2x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 3x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 4x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 5x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 6x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 7x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 8x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* 9x */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* Ax */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* Bx */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* Cx */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { NOGROUP, CPU_PRESCOTT, ITYPE_SYSTEM, "monitor", NOARGS, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { NOGROUP, CPU_PRESCOTT, ITYPE_SYSTEM, "mwait", NOARGS, NOCOND, NOCHANGE, SERIALIZE_ALL, IGNORED }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* Dx */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* Ex */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { X86_Group_7, GROUP }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP }, // xF + + /* Fx */ + { X86_Group_7, GROUP }, // x0 + { X86_Group_7, GROUP }, // x1 + { X86_Group_7, GROUP }, // x2 + { X86_Group_7, GROUP }, // x3 + { X86_Group_7, GROUP }, // x4 + { X86_Group_7, GROUP }, // x5 + { X86_Group_7, GROUP }, // x6 + { X86_Group_7, GROUP }, // x7 + { NOGROUP, CPU_AMD64, ITYPE_SYSTEM, "swapgs", { OPTYPE_KERNELBASE_MSR | OP_MSR | OP_SRC, 0, 0 }, NOCOND, NOCHANGE, NOACTION, IGNORED }, // x8 + { X86_Group_7, GROUP }, // x9 + { X86_Group_7, GROUP }, // xA + { X86_Group_7, GROUP }, // xB + { X86_Group_7, GROUP }, // xC + { X86_Group_7, GROUP }, // xD + { X86_Group_7, GROUP }, // xE + { X86_Group_7, GROUP } // xF +}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Sanity checking tables +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + +#define S2 1 // SSE2 +#define S3 2 // SSE3 +BYTE X86_ModRM_1[0x100] = +{ + // x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF + /* 0x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 1x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 2x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 3x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 6x */ 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 8x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Cx */ 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + /* Dx */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Fx */ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 +}; +BYTE X86_ModRM_2[0x100] = +{ + // x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF + /* 0x */ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, + /* 1x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + /* 2x */ 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 7x */ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* Ax */ 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, + /* Bx */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, + /* Cx */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + /* Dx */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* Ex */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* Fx */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 +}; + +BYTE X86_SSE_2[0x100] = +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1x */ 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 5x */ 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, + /* 7x */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Cx */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Dx */ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ex */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Fx */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +// Indicates if a LOCK prefix is allowed +// The following are allowed: +// add, adc, and, btc, btr, bts, cmpxchg, cmpxchg8, dec, inc, +// neg, not, or, sbb, sub, xor, xadd, xchg +#define GR 2 +BYTE X86_LockPrefix_1[0x100] = +{ + // x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF + /* 0x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 1x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 2x */ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + /* 3x */ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 8x */ GR, GR, GR, GR, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Cx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Fx */ 0, 0, 0, 0, 0, 0, GR, GR, 0, 0, 0, 0, 0, 0, GR, GR +}; + +BYTE X86_LockPrefix_2[0x100] = +{ + // x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + /* Bx */ 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, GR, 1, 0, 0, 0, 0, + /* Cx */ 1, 1, 0, 0, 0, 0, 0, GR, 0, 0, 0, 0, 0, 0, 0, 0, + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +BYTE X86_LockPrefix_Groups[17][8] = +{ +// x0 x1 x2 x3 x4 x5 x6 x7 + { 1, 1, 1, 1, 1, 1, 1, 0 }, // group 1 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 2 + { 0, 0, 1, 1, 0, 0, 0, 0 }, // group 3 + { 1, 1, 0, 0, 0, 0, 0, 0 }, // group 4 + { 1, 1, 0, 0, 0, 0, 0, 0 }, // group 5 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 6 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 7 + { 0, 0, 0, 0, 1, 1, 1, 1 }, // group 8 + { 0, 1, 0, 0, 0, 0, 0, 0 }, // group 9 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 10 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 11 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 12 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 13 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 14 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 15 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 16 + { 0, 0, 0, 0, 0, 0, 0, 0 }, // group 17 +}; + +#define X86_MAX_GROUP 19 +BYTE X86_Groups_1[0x100] = // one-byte opcodes +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6x */ + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + /* 8x */ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, /* 8x */ + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9x */ + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ax */ + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + /* Cx */ 2, 2, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, /* Cx */ + /* Dx */ 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Dx */ + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ex */ + /* Fx */ 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 4, 5 /* Fx */ +}; + +// 19 = Group P +// 20 = 3DNow +BYTE X86_Groups_2[0x100] = // two-byte opcodes +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 19, /* 0x */ + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6x */ + /* 7x */ 0, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8x */ + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9x */ + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, /* Ax */ + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 8, 0, 0, 0, 0, 0, /* Bx */ + /* Cx */ 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, /* Cx */ + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Dx */ + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ex */ + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* Fx */ +}; + +// Indicate which 1-byte opcodes are invalid with a 16-bit operand size +BYTE X86_Invalid_Op16_1[0x100] = +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6x */ + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8x */ + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9x */ + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ax */ + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + /* Cx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Cx */ + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Dx */ + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ex */ + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* Fx */ +}; + +// Indicate which 2-byte opcodes are invalid with a 16-bit operand size +BYTE X86_Invalid_Op16_2[0x100] = +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6x */ + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8x */ + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9x */ + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ax */ + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + /* Cx */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */ + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Dx */ + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ex */ + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* Fx */ +}; + +// Indicate which 1-byte opcodes are invalid with a 64-bit address size +BYTE X86_Invalid_Addr64_1[0x100] = +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x */ + /* 1x */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 1x */ + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, /* 2x */ + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, /* 3x */ + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + /* 6x */ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6x */ + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8x */ + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 9x */ + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ax */ + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + /* Cx */ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* Cx */ + /* Dx */ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Dx */ + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* Ex */ + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* Fx */ +}; + +// Indicate which 2-byte opcodes are invalid with a 64-bit address size +BYTE X86_Invalid_Addr64_2[0x100] = +{ + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + /* 3x */ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6x */ + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8x */ + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9x */ + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ax */ + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + /* Cx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Cx */ + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Dx */ + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Ex */ + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* Fx */ +}; + +#endif // DISASM_X86_TABLES \ No newline at end of file diff --git a/renderdoc/3rdparty/mhook/disasm-lib/misc.c b/renderdoc/3rdparty/mhook/disasm-lib/misc.c new file mode 100644 index 0000000000..c5b0ac61a5 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/misc.c @@ -0,0 +1,185 @@ +// Copyright (C) 2002, Matt Conover (mconover@gmail.com) +#include "misc.h" + +BOOL IsHexChar(BYTE ch) +{ + switch (ch) + { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + case 'A': case 'a': case 'B': case 'b': + case 'C': case 'c': case 'D': case 'd': + case 'E': case 'e': case 'F': case 'f': + return TRUE; + default: + return FALSE; + } +} + +// NOTE: caller must free the buffer returned +BYTE *HexToBinary(char *Input, DWORD InputLength, DWORD *OutputLength) +{ + DWORD i, j, ByteCount = 0; + char temp_byte[3]; + BYTE *p, *ByteString = NULL; + + if (!InputLength || !OutputLength) return NULL; + else *OutputLength = 0; + + while (*Input && isspace(*Input)) { Input++; InputLength--; } + if (!*Input) return NULL; + if (Input[0] == '\"') { Input++; InputLength--; } + p = (BYTE *)strchr(Input, '\"'); + if (p) InputLength--; + + if (InputLength > 2 && Input[2] == ' ') // assume spaces + { + for (i = 0; i < InputLength; i += 3) + { + while (i < InputLength && isspace(Input[i])) i++; // skip over extra space, \r, and \n + if (i >= InputLength) break; + + if (!IsHexChar(Input[i])) + { + //fprintf(stderr, "ERROR: invalid hex character at offset %lu (0x%04x)\n", i, i); + goto abort; + } + + if (i+1 >= InputLength || !Input[i+1]) + { + //fprintf(stderr, "ERROR: hex string terminates unexpectedly at offset %lu (0x%04x)\n", i+1, i+1); + goto abort; + } + + if (i+2 < InputLength && Input[i+2] && !isspace(Input[i+2])) + { + //fprintf(stderr, "ERROR: Hex string is malformed at offset %lu (0x%04x)\n", i, i); + //fprintf(stderr, "Found '%c' (0x%02x) instead of space\n", Input[i+2], Input[i+2]); + goto abort; + } + + ByteCount++; + } + + if (!ByteCount) + { + //fprintf(stderr, "Error: no input (byte count = 0)\n"); + goto abort; + } + + ByteString = malloc(ByteCount+1); + if (!ByteString) + { + //fprintf(stderr, "ERROR: failed to allocate %lu bytes\n", ByteCount); + goto abort; + } + + memset(ByteString, 0, ByteCount+1); + for (i = 0, j = 0; j < ByteCount; i += 3, j++) + { + while (isspace(Input[i])) i++; // skip over extra space, \r, and \n + temp_byte[0] = Input[i]; + temp_byte[1] = Input[i+1]; + temp_byte[2] = 0; + ByteString[j] = (BYTE)strtoul(temp_byte, NULL, 16); + } + } + else if (InputLength > 2 && Input[0] == '\\') + { + for (i = 0; i < InputLength; i += 2) + { + if (Input[i] != '\\' || (Input[i+1] != 'x' && Input[i+1] != '0')) + { + //fprintf(stderr, "ERROR: invalid hex character at offset %lu (0x%04x)\n", i, i); + goto abort; + } + i += 2; + + if (!IsHexChar(Input[i])) + { + //fprintf(stderr, "ERROR: invalid hex character at offset %lu (0x%04x)\n", i, i); + goto abort; + } + if (i+1 >= InputLength || !Input[i+1]) + { + //fprintf(stderr, "ERROR: hex string terminates unexpectedly at offset %lu (0x%04x)\n", i+1, i+1); + goto abort; + } + + ByteCount++; + } + + if (!ByteCount) + { + //fprintf(stderr, "Error: no input (byte count = 0)\n"); + goto abort; + } + + ByteString = malloc(ByteCount+1); + if (!ByteString) + { + //fprintf(stderr, "ERROR: failed to allocate %lu bytes\n", ByteCount); + goto abort; + } + + memset(ByteString, 0, ByteCount+1); + for (i = j = 0; j < ByteCount; i += 2, j++) + { + i += 2; + temp_byte[0] = Input[i]; + temp_byte[1] = Input[i+1]; + temp_byte[2] = 0; + ByteString[j] = (BYTE)strtoul(temp_byte, NULL, 16); + } + } + else // assume it is a hex string with no spaces with 2 bytes per character + { + for (i = 0; i < InputLength; i += 2) + { + if (!IsHexChar(Input[i])) + { + //fprintf(stderr, "ERROR: invalid hex character at offset %lu (0x%04x)\n", i, i); + goto abort; + } + if (i+1 >= InputLength || !Input[i+1]) + { + //fprintf(stderr, "ERROR: hex string terminates unexpectedly at offset %lu (0x%04x)\n", i+1, i+1); + goto abort; + } + + ByteCount++; + } + + if (!ByteCount) + { + //fprintf(stderr, "Error: no input (byte count = 0)\n"); + goto abort; + } + + ByteString = malloc(ByteCount+1); + if (!ByteString) + { + //fprintf(stderr, "ERROR: failed to allocate %lu bytes\n", ByteCount); + goto abort; + } + + memset(ByteString, 0, ByteCount+1); + for (i = 0, j = 0; j < ByteCount; i += 2, j++) + { + temp_byte[0] = Input[i]; + temp_byte[1] = Input[i+1]; + temp_byte[2] = 0; + ByteString[j] = (BYTE)strtoul(temp_byte, NULL, 16); + } + } + + *OutputLength = ByteCount; + return ByteString; + +abort: + if (OutputLength) *OutputLength = 0; + if (ByteString) free(ByteString); + return NULL; +} + diff --git a/renderdoc/3rdparty/mhook/disasm-lib/misc.h b/renderdoc/3rdparty/mhook/disasm-lib/misc.h new file mode 100644 index 0000000000..b3f585b758 --- /dev/null +++ b/renderdoc/3rdparty/mhook/disasm-lib/misc.h @@ -0,0 +1,52 @@ +// Copyright (C) 2002, Matt Conover (mconover@gmail.com) +#ifndef MISC_H +#define MISC_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +// NOTE: start is inclusive, end is exclusive (as in start <= x < end) +#define IS_IN_RANGE(x, s, e) \ +( \ + ((ULONG_PTR)(x) == (ULONG_PTR)(s) && (ULONG_PTR)(x) == (ULONG_PTR)(e)) || \ + ((ULONG_PTR)(x) >= (ULONG_PTR)(s) && (ULONG_PTR)(x) < (ULONG_PTR)(e)) \ +) + +#if _MSC_VER >= 1400 +#pragma warning(disable:4996) +#endif + +#if defined(_WIN64) + #define VALID_ADDRESS_MAX 0x7FFEFFFFFFFFFFFF // Win64 specific + typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; +#else + #define VALID_ADDRESS_MAX 0x7FFEFFFF // Win32 specific + typedef unsigned long ULONG_PTR, *PULONG_PTR; +#endif + +#ifndef DECLSPEC_ALIGN + #if (_MSC_VER >= 1300) && !defined(MIDL_PASS) + #define DECLSPEC_ALIGN(x) __declspec(align(x)) + #else + #define DECLSPEC_ALIGN(x) + #endif +#endif + +#define VALID_ADDRESS_MIN 0x10000 // Win32 specific +#define IS_VALID_ADDRESS(a) IS_IN_RANGE(a, VALID_ADDRESS_MIN, VALID_ADDRESS_MAX+1) + +BOOL IsHexChar(BYTE ch); +BYTE *HexToBinary(char *Input, DWORD InputLength, DWORD *OutputLength); + +#ifdef __cplusplus +} +#endif +#endif // MISC_H diff --git a/renderdoc/3rdparty/mhook/mhook-lib/mhook.cpp b/renderdoc/3rdparty/mhook/mhook-lib/mhook.cpp new file mode 100644 index 0000000000..eeff4dda42 --- /dev/null +++ b/renderdoc/3rdparty/mhook/mhook-lib/mhook.cpp @@ -0,0 +1,822 @@ +//Copyright (c) 2007-2008, Marton Anka +// +//Permission is hereby granted, free of charge, to any person obtaining a +//copy of this software and associated documentation files (the "Software"), +//to deal in the Software without restriction, including without limitation +//the rights to use, copy, modify, merge, publish, distribute, sublicense, +//and/or sell copies of the Software, and to permit persons to whom the +//Software is furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included +//in all copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +//OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +//THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +//IN THE SOFTWARE. + +#include +#include +#include +#include "mhook.h" +#include "../disasm-lib/disasm.h" + +#pragma warning(disable:4706 4310) + +//========================================================================= +#ifndef cntof +#define cntof(a) (sizeof(a)/sizeof(a[0])) +#endif + +//========================================================================= +#ifndef GOOD_HANDLE +#define GOOD_HANDLE(a) ((a!=INVALID_HANDLE_VALUE)&&(a!=NULL)) +#endif + +//========================================================================= +#ifndef gle +#define gle GetLastError +#endif + +//========================================================================= +#ifndef ODPRINTF + +#ifdef _DEBUG +#define ODPRINTF(a) odprintf a +#else +#define ODPRINTF(a) +#endif + +inline void __cdecl odprintf(PCSTR format, ...) { + va_list args; + va_start(args, format); + int len = _vscprintf(format, args); + if (len > 0) { + len += (1 + 2); + PSTR buf = (PSTR) malloc(len); + if (buf) { + len = vsprintf_s(buf, len, format, args); + if (len > 0) { + while (len && isspace(buf[len-1])) len--; + buf[len++] = '\r'; + buf[len++] = '\n'; + buf[len] = 0; + OutputDebugStringA(buf); + } + free(buf); + } + va_end(args); + } +} + +inline void __cdecl odprintf(PCWSTR format, ...) { + va_list args; + va_start(args, format); + int len = _vscwprintf(format, args); + if (len > 0) { + len += (1 + 2); + PWSTR buf = (PWSTR) malloc(sizeof(WCHAR)*len); + if (buf) { + len = vswprintf_s(buf, len, format, args); + if (len > 0) { + while (len && iswspace(buf[len-1])) len--; + buf[len++] = L'\r'; + buf[len++] = L'\n'; + buf[len] = 0; + OutputDebugStringW(buf); + } + free(buf); + } + va_end(args); + } +} + +#endif //#ifndef ODPRINTF + +//========================================================================= +#define MHOOKS_MAX_CODE_BYTES 32 +#define MHOOKS_MAX_RIPS 4 + +//========================================================================= +// The trampoline structure - stores every bit of info about a hook +struct MHOOKS_TRAMPOLINE { + PBYTE pSystemFunction; // the original system function + DWORD cbOverwrittenCode; // number of bytes overwritten by the jump + PBYTE pHookFunction; // the hook function that we provide + BYTE codeJumpToHookFunction[MHOOKS_MAX_CODE_BYTES]; // placeholder for code that jumps to the hook function + BYTE codeTrampoline[MHOOKS_MAX_CODE_BYTES]; // placeholder for code that holds the first few + // bytes from the system function and a jump to the remainder + // in the original location + BYTE codeUntouched[MHOOKS_MAX_CODE_BYTES]; // placeholder for unmodified original code + // (we patch IP-relative addressing) +}; + + +//========================================================================= +// The patch data structures - store info about rip-relative instructions +// during hook placement +struct MHOOKS_RIPINFO +{ + DWORD dwOffset; + S64 nDisplacement; +}; + +struct MHOOKS_PATCHDATA +{ + S64 nLimitUp; + S64 nLimitDown; + DWORD nRipCnt; + MHOOKS_RIPINFO rips[MHOOKS_MAX_RIPS]; +}; + +//========================================================================= +// Global vars +static BOOL g_bVarsInitialized = FALSE; +static CRITICAL_SECTION g_cs; +static MHOOKS_TRAMPOLINE* g_pHooks[MHOOKS_MAX_SUPPORTED_HOOKS]; +static DWORD g_nHooksInUse = 0; +static BOOL g_bThreadsSuspended = FALSE; +static HANDLE* g_hThreadHandles = NULL; +static DWORD g_nThreadHandles = 0; +#define MHOOK_JMPSIZE 5 + +//========================================================================= +// Toolhelp defintions so the functions can be dynamically bound to +typedef HANDLE (WINAPI * _CreateToolhelp32Snapshot)( + DWORD dwFlags, + DWORD th32ProcessID + ); + +typedef BOOL (WINAPI * _Thread32First)( + HANDLE hSnapshot, + LPTHREADENTRY32 lpte + ); + +typedef BOOL (WINAPI * _Thread32Next)( + HANDLE hSnapshot, + LPTHREADENTRY32 lpte + ); + +//========================================================================= +// Bring in the toolhelp functions from kernel32 +_CreateToolhelp32Snapshot fnCreateToolhelp32Snapshot = (_CreateToolhelp32Snapshot) GetProcAddress(GetModuleHandle(L"kernel32"), "CreateToolhelp32Snapshot"); +_Thread32First fnThread32First = (_Thread32First) GetProcAddress(GetModuleHandle(L"kernel32"), "Thread32First"); +_Thread32Next fnThread32Next = (_Thread32Next) GetProcAddress(GetModuleHandle(L"kernel32"), "Thread32Next"); + +//========================================================================= +static VOID EnterCritSec() { + if (!g_bVarsInitialized) { + InitializeCriticalSection(&g_cs); + ZeroMemory(g_pHooks, sizeof(g_pHooks)); + g_bVarsInitialized = TRUE; + } + EnterCriticalSection(&g_cs); +} + +//========================================================================= +static VOID LeaveCritSec() { + LeaveCriticalSection(&g_cs); +} + +//========================================================================= +// Internal function: +// +// Skip over jumps that lead to the real function. Gets around import +// jump tables, etc. +//========================================================================= +static PBYTE SkipJumps(PBYTE pbCode) { +#ifdef _M_IX86_X64 + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { +#ifdef _M_IX86 + // on x86 we have an absolute pointer... + PBYTE pbTarget = *(PBYTE *)&pbCode[2]; + // ... that shows us an absolute pointer. + return SkipJumps(*(PBYTE *)pbTarget); +#elif defined _M_X64 + // on x64 we have a 32-bit offset... + INT32 lOffset = *(INT32 *)&pbCode[2]; + // ... that shows us an absolute pointer + return SkipJumps(*(PBYTE*)(pbCode + 6 + lOffset)); +#endif + } else if (pbCode[0] == 0xe9) { + // here the behavior is identical, we have... + // ...a 32-bit offset to the destination. + return SkipJumps(pbCode + 5 + *(INT32 *)&pbCode[1]); + } else if (pbCode[0] == 0xeb) { + // and finally an 8-bit offset to the destination + return SkipJumps(pbCode + 2 + *(CHAR *)&pbCode[1]); + } +#else +#error unsupported platform +#endif + return pbCode; +} + +//========================================================================= +// Internal function: +// +// Writes code at pbCode that jumps to pbJumpTo. Will attempt to do this +// in as few bytes as possible. Important on x64 where the long jump +// (0xff 0x25 ....) can take up 14 bytes. +//========================================================================= +static PBYTE EmitJump(PBYTE pbCode, PBYTE pbJumpTo) { +#ifdef _M_IX86_X64 + PBYTE pbJumpFrom = pbCode + 5; + SIZE_T cbDiff = pbJumpFrom > pbJumpTo ? pbJumpFrom - pbJumpTo : pbJumpTo - pbJumpFrom; + ODPRINTF((L"mhooks: EmitJump: Jumping from %p to %p, diff is %p", pbJumpFrom, pbJumpTo, cbDiff)); + if (cbDiff <= 0x7fff0000) { + pbCode[0] = 0xe9; + pbCode += 1; + *((PDWORD)pbCode) = (DWORD)(DWORD_PTR)(pbJumpTo - pbJumpFrom); + pbCode += sizeof(DWORD); + } else { + pbCode[0] = 0xff; + pbCode[1] = 0x25; + pbCode += 2; +#ifdef _M_IX86 + // on x86 we write an absolute address (just behind the instruction) + *((PDWORD)pbCode) = (DWORD)(DWORD_PTR)(pbCode + sizeof(DWORD)); +#elif defined _M_X64 + // on x64 we write the relative address of the same location + *((PDWORD)pbCode) = (DWORD)0; +#endif + pbCode += sizeof(DWORD); + *((PDWORD_PTR)pbCode) = (DWORD_PTR)(pbJumpTo); + pbCode += sizeof(DWORD_PTR); + } +#else +#error unsupported platform +#endif + return pbCode; +} + +//========================================================================= +// Internal function: +// +// Will try to allocate the trampoline structure within 2 gigabytes of +// the target function. +//========================================================================= +static MHOOKS_TRAMPOLINE* TrampolineAlloc(PBYTE pSystemFunction, S64 nLimitUp, S64 nLimitDown) { + + MHOOKS_TRAMPOLINE* pTrampoline = NULL; + + // do we have room to store this guy? + if (g_nHooksInUse < MHOOKS_MAX_SUPPORTED_HOOKS) { + + // determine lower and upper bounds for the allocation locations. + // in the basic scenario this is +/- 2GB but IP-relative instructions + // found in the original code may require a smaller window. + PBYTE pLower = pSystemFunction + nLimitUp; + pLower = pLower < (PBYTE)(DWORD_PTR)0x0000000080000000 ? + (PBYTE)(0x1) : (PBYTE)(pLower - (PBYTE)0x7fff0000); + PBYTE pUpper = pSystemFunction + nLimitDown; + pUpper = pUpper < (PBYTE)(DWORD_PTR)0xffffffff80000000 ? + (PBYTE)(pUpper + (DWORD_PTR)0x7ff80000) : (PBYTE)(DWORD_PTR)0xfffffffffff80000; + ODPRINTF((L"mhooks: TrampolineAlloc: Allocating for %p between %p and %p", pSystemFunction, pLower, pUpper)); + + SYSTEM_INFO sSysInfo = {0}; + ::GetSystemInfo(&sSysInfo); + + // go through the available memory blocks and try to allocate a chunk for us + for (PBYTE pbAlloc = pLower; pbAlloc < pUpper;) { + // determine current state + MEMORY_BASIC_INFORMATION mbi; + ODPRINTF((L"mhooks: TrampolineAlloc: Looking at address %p", pbAlloc)); + if (!VirtualQuery(pbAlloc, &mbi, sizeof(mbi))) + break; + // free & large enough? + if (mbi.State == MEM_FREE && mbi.RegionSize >= sizeof(MHOOKS_TRAMPOLINE) && mbi.RegionSize >= sSysInfo.dwAllocationGranularity) { + // yes, align the pointer to the 64K boundary first + pbAlloc = (PBYTE)(ULONG_PTR((ULONG_PTR(pbAlloc) + (sSysInfo.dwAllocationGranularity-1)) / sSysInfo.dwAllocationGranularity) * sSysInfo.dwAllocationGranularity); + // and then try to allocate it + pTrampoline = (MHOOKS_TRAMPOLINE*)VirtualAlloc(pbAlloc, sizeof(MHOOKS_TRAMPOLINE), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READ); + if (pTrampoline) { + ODPRINTF((L"mhooks: TrampolineAlloc: Allocated block at %p as the trampoline", pTrampoline)); + break; + } + } + // continue the search + pbAlloc = (PBYTE)mbi.BaseAddress + mbi.RegionSize; + } + + // found and allocated a trampoline? + if (pTrampoline) { + // put it into our list so we know we'll have to free it + for (DWORD i=0; icodeTrampoline == pHookedFunction) + return g_pHooks[i]; + } + } + return NULL; +} + +//========================================================================= +// Internal function: +// +// Free a trampoline structure. +//========================================================================= +static VOID TrampolineFree(MHOOKS_TRAMPOLINE* pTrampoline, BOOL bNeverUsed) { + for (DWORD i=0; i= pbCode && pIp < (pbCode + cbBytes)) { + if (nTries < 3) { + // oops - we should try to get the instruction pointer out of here. + ODPRINTF((L"mhooks: SuspendOneThread: suspended thread %d - IP is at %p - IS COLLIDING WITH CODE", dwThreadId, pIp)); + ResumeThread(hThread); + Sleep(100); + SuspendThread(hThread); + nTries++; + } else { + // we gave it all we could. (this will probably never + // happen - unless the thread has already been suspended + // to begin with) + ODPRINTF((L"mhooks: SuspendOneThread: suspended thread %d - IP is at %p - IS COLLIDING WITH CODE - CAN'T FIX", dwThreadId, pIp)); + ResumeThread(hThread); + CloseHandle(hThread); + hThread = NULL; + break; + } + } else { + // success, the IP is not conflicting + ODPRINTF((L"mhooks: SuspendOneThread: Successfully suspended thread %d - IP is at %p", dwThreadId, pIp)); + break; + } + } + } else { + // couldn't suspend + CloseHandle(hThread); + hThread = NULL; + } + } + return hThread; +} + +//========================================================================= +// Internal function: +// +// Resumes all previously suspended threads in the current process. +//========================================================================= +static VOID ResumeOtherThreads() { + // make sure things go as fast as possible + INT nOriginalPriority = GetThreadPriority(GetCurrentThread()); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + // go through our list + for (DWORD i=0; inRipCnt; i++) { + DWORD dwNewDisplacement = (DWORD)(pdata->rips[i].nDisplacement - diff); + ODPRINTF((L"mhooks: fixing up RIP instruction operand for code at 0x%p: " + L"old displacement: 0x%8.8x, new displacement: 0x%8.8x", + pbNew + pdata->rips[i].dwOffset, + (DWORD)pdata->rips[i].nDisplacement, + dwNewDisplacement)); + *(PDWORD)(pbNew + pdata->rips[i].dwOffset) = dwNewDisplacement; + } +#endif +} + +//========================================================================= +// Examine the machine code at the target function's entry point, and +// skip bytes in a way that we'll always end on an instruction boundary. +// We also detect branches and subroutine calls (as well as returns) +// at which point disassembly must stop. +// Finally, detect and collect information on IP-relative instructions +// that we can patch. +static DWORD DisassembleAndSkip(PVOID pFunction, DWORD dwMinLen, MHOOKS_PATCHDATA* pdata) { + DWORD dwRet = 0; + pdata->nLimitDown = 0; + pdata->nLimitUp = 0; + pdata->nRipCnt = 0; +#ifdef _M_IX86 + ARCHITECTURE_TYPE arch = ARCH_X86; +#elif defined _M_X64 + ARCHITECTURE_TYPE arch = ARCH_X64; +#else + #error unsupported platform +#endif + DISASSEMBLER dis; + if (InitDisassembler(&dis, arch)) { + INSTRUCTION* pins = NULL; + U8* pLoc = (U8*)pFunction; + DWORD dwFlags = DISASM_DECODE | DISASM_DISASSEMBLE | DISASM_ALIGNOUTPUT; + + ODPRINTF((L"mhooks: DisassembleAndSkip: Disassembling %p", pLoc)); + while ( (dwRet < dwMinLen) && (pins = GetInstruction(&dis, (ULONG_PTR)pLoc, pLoc, dwFlags)) ) { + ODPRINTF(("mhooks: DisassembleAndSkip: %p: %s", pLoc, pins->String)); + if (pins->Type == ITYPE_RET ) break; + if (pins->Type == ITYPE_BRANCH ) break; + if (pins->Type == ITYPE_BRANCHCC) break; + if (pins->Type == ITYPE_CALL ) break; + if (pins->Type == ITYPE_CALLCC ) break; + + #if defined _M_X64 + BOOL bProcessRip = FALSE; + // mov or lea to register from rip+imm32 + if ((pins->Type == ITYPE_MOV || pins->Type == ITYPE_LEA) && (pins->X86.Relative) && + (pins->X86.OperandSize == 8) && (pins->OperandCount == 2) && + (pins->Operands[1].Flags & OP_IPREL) && (pins->Operands[1].Register == AMD64_REG_RIP)) + { + // rip-addressing "mov reg, [rip+imm32]" + ODPRINTF((L"mhooks: DisassembleAndSkip: found OP_IPREL on operand %d with displacement 0x%x (in memory: 0x%x)", 1, pins->X86.Displacement, *(PDWORD)(pLoc+3))); + bProcessRip = TRUE; + } + // mov or lea to rip+imm32 from register + else if ((pins->Type == ITYPE_MOV || pins->Type == ITYPE_LEA) && (pins->X86.Relative) && + (pins->X86.OperandSize == 8) && (pins->OperandCount == 2) && + (pins->Operands[0].Flags & OP_IPREL) && (pins->Operands[0].Register == AMD64_REG_RIP)) + { + // rip-addressing "mov [rip+imm32], reg" + ODPRINTF((L"mhooks: DisassembleAndSkip: found OP_IPREL on operand %d with displacement 0x%x (in memory: 0x%x)", 0, pins->X86.Displacement, *(PDWORD)(pLoc+3))); + bProcessRip = TRUE; + } + else if ( (pins->OperandCount >= 1) && (pins->Operands[0].Flags & OP_IPREL) ) + { + // unsupported rip-addressing + ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 0)); + // dump instruction bytes to the debug output + for (DWORD i=0; iLength; i++) { + ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); + } + break; + } + else if ( (pins->OperandCount >= 2) && (pins->Operands[1].Flags & OP_IPREL) ) + { + // unsupported rip-addressing + ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 1)); + // dump instruction bytes to the debug output + for (DWORD i=0; iLength; i++) { + ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); + } + break; + } + else if ( (pins->OperandCount >= 3) && (pins->Operands[2].Flags & OP_IPREL) ) + { + // unsupported rip-addressing + ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 2)); + // dump instruction bytes to the debug output + for (DWORD i=0; iLength; i++) { + ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); + } + break; + } + // follow through with RIP-processing if needed + if (bProcessRip) { + // calculate displacement relative to function start + S64 nAdjustedDisplacement = pins->X86.Displacement + (pLoc - (U8*)pFunction); + // store displacement values furthest from zero (both positive and negative) + if (nAdjustedDisplacement < pdata->nLimitDown) + pdata->nLimitDown = nAdjustedDisplacement; + if (nAdjustedDisplacement > pdata->nLimitUp) + pdata->nLimitUp = nAdjustedDisplacement; + // store patch info + if (pdata->nRipCnt < MHOOKS_MAX_RIPS) { + pdata->rips[pdata->nRipCnt].dwOffset = dwRet + 3; + pdata->rips[pdata->nRipCnt].nDisplacement = pins->X86.Displacement; + pdata->nRipCnt++; + } else { + // no room for patch info, stop disassembly + break; + } + } + #endif + + dwRet += pins->Length; + pLoc += pins->Length; + } + + CloseDisassembler(&dis); + } + + return dwRet; +} + +//========================================================================= +void Mhook_SuspendOtherThreads() { + SuspendOtherThreads(NULL, 0); + g_bThreadsSuspended = TRUE; +} +void Mhook_ResumeOtherThreads() { + ResumeOtherThreads(); + g_bThreadsSuspended = FALSE; +} +//========================================================================= + +//========================================================================= +bool Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction) { + MHOOKS_TRAMPOLINE* pTrampoline = NULL; + PVOID pSystemFunction = *ppSystemFunction; + // ensure thread-safety + EnterCritSec(); + ODPRINTF((L"mhooks: Mhook_SetHook: Started on the job: %p / %p", pSystemFunction, pHookFunction)); + // find the real functions (jump over jump tables, if any) + pSystemFunction = SkipJumps((PBYTE)pSystemFunction); + pHookFunction = SkipJumps((PBYTE)pHookFunction); + ODPRINTF((L"mhooks: Mhook_SetHook: Started on the job: %p / %p", pSystemFunction, pHookFunction)); + // figure out the length of the overwrite zone + MHOOKS_PATCHDATA patchdata = {0}; + DWORD dwInstructionLength = DisassembleAndSkip(pSystemFunction, MHOOK_JMPSIZE, &patchdata); + if (dwInstructionLength >= MHOOK_JMPSIZE) { + ODPRINTF((L"mhooks: Mhook_SetHook: disassembly signals %d bytes", dwInstructionLength)); + // suspend every other thread in this process, and make sure their IP + // is not in the code we're about to overwrite. + SuspendOtherThreads((PBYTE)pSystemFunction, dwInstructionLength); + // allocate a trampoline structure (TODO: it is pretty wasteful to get + // VirtualAlloc to grab chunks of memory smaller than 100 bytes) + pTrampoline = TrampolineAlloc((PBYTE)pSystemFunction, patchdata.nLimitUp, patchdata.nLimitDown); + if (pTrampoline) { + ODPRINTF((L"mhooks: Mhook_SetHook: allocated structure at %p", pTrampoline)); + // open ourselves so we can VirtualProtectEx + HANDLE hProc = GetCurrentProcess(); + DWORD dwOldProtectSystemFunction = 0; + DWORD dwOldProtectTrampolineFunction = 0; + // set the system function to PAGE_EXECUTE_READWRITE + if (VirtualProtectEx(hProc, pSystemFunction, dwInstructionLength, PAGE_EXECUTE_READWRITE, &dwOldProtectSystemFunction)) { + ODPRINTF((L"mhooks: Mhook_SetHook: readwrite set on system function")); + // mark our trampoline buffer to PAGE_EXECUTE_READWRITE + if (VirtualProtectEx(hProc, pTrampoline, sizeof(MHOOKS_TRAMPOLINE), PAGE_EXECUTE_READWRITE, &dwOldProtectTrampolineFunction)) { + ODPRINTF((L"mhooks: Mhook_SetHook: readwrite set on trampoline structure")); + + // create our trampoline function + PBYTE pbCode = pTrampoline->codeTrampoline; + // save original code.. + for (DWORD i = 0; icodeUntouched[i] = pbCode[i] = ((PBYTE)pSystemFunction)[i]; + } + pbCode += dwInstructionLength; + // plus a jump to the continuation in the original location + pbCode = EmitJump(pbCode, ((PBYTE)pSystemFunction) + dwInstructionLength); + ODPRINTF((L"mhooks: Mhook_SetHook: updated the trampoline")); + + // fix up any IP-relative addressing in the code + FixupIPRelativeAddressing(pTrampoline->codeTrampoline, (PBYTE)pSystemFunction, &patchdata); + + DWORD_PTR dwDistance = (PBYTE)pHookFunction < (PBYTE)pSystemFunction ? + (PBYTE)pSystemFunction - (PBYTE)pHookFunction : (PBYTE)pHookFunction - (PBYTE)pSystemFunction; + if (dwDistance > 0x7fff0000) { + // create a stub that jumps to the replacement function. + // we need this because jumping from the API to the hook directly + // will be a long jump, which is 14 bytes on x64, and we want to + // avoid that - the API may or may not have room for such stuff. + // (remember, we only have 5 bytes guaranteed in the API.) + // on the other hand we do have room, and the trampoline will always be + // within +/- 2GB of the API, so we do the long jump in there. + // the API will jump to the "reverse trampoline" which + // will jump to the user's hook code. + pbCode = pTrampoline->codeJumpToHookFunction; + pbCode = EmitJump(pbCode, (PBYTE)pHookFunction); + ODPRINTF((L"mhooks: Mhook_SetHook: created reverse trampoline")); + FlushInstructionCache(hProc, pTrampoline->codeJumpToHookFunction, + pbCode - pTrampoline->codeJumpToHookFunction); + + // update the API itself + pbCode = (PBYTE)pSystemFunction; + pbCode = EmitJump(pbCode, pTrampoline->codeJumpToHookFunction); + } else { + // the jump will be at most 5 bytes so we can do it directly + // update the API itself + pbCode = (PBYTE)pSystemFunction; + pbCode = EmitJump(pbCode, (PBYTE)pHookFunction); + } + + // update data members + pTrampoline->cbOverwrittenCode = dwInstructionLength; + pTrampoline->pSystemFunction = (PBYTE)pSystemFunction; + pTrampoline->pHookFunction = (PBYTE)pHookFunction; + + // flush instruction cache and restore original protection + FlushInstructionCache(hProc, pTrampoline->codeTrampoline, dwInstructionLength); + VirtualProtectEx(hProc, pTrampoline, sizeof(MHOOKS_TRAMPOLINE), dwOldProtectTrampolineFunction, &dwOldProtectTrampolineFunction); + } else { + ODPRINTF((L"mhooks: Mhook_SetHook: failed VirtualProtectEx 2: %d", gle())); + } + // flush instruction cache and restore original protection + FlushInstructionCache(hProc, pSystemFunction, dwInstructionLength); + VirtualProtectEx(hProc, pSystemFunction, dwInstructionLength, dwOldProtectSystemFunction, &dwOldProtectSystemFunction); + } else { + ODPRINTF((L"mhooks: Mhook_SetHook: failed VirtualProtectEx 1: %d", gle())); + } + if (pTrampoline->pSystemFunction) { + // this is what the application will use as the entry point + // to the "original" unhooked function. + *ppSystemFunction = pTrampoline->codeTrampoline; + ODPRINTF((L"mhooks: Mhook_SetHook: Hooked the function!")); + } else { + // if we failed discard the trampoline (forcing VirtualFree) + TrampolineFree(pTrampoline, TRUE); + pTrampoline = NULL; + } + } + // resume everybody else + ResumeOtherThreads(); + } else { + ODPRINTF((L"mhooks: disassembly signals %d bytes (unacceptable)", dwInstructionLength)); + } + LeaveCritSec(); + return (pTrampoline != NULL); +} + +//========================================================================= +bool Mhook_Unhook(PVOID *ppHookedFunction) { + ODPRINTF((L"mhooks: Mhook_Unhook: %p", *ppHookedFunction)); + bool bRet = false; + EnterCritSec(); + // get the trampoline structure that corresponds to our function + MHOOKS_TRAMPOLINE* pTrampoline = TrampolineGet((PBYTE)*ppHookedFunction); + if (pTrampoline) { + // make sure nobody's executing code where we're about to overwrite a few bytes + SuspendOtherThreads(pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode); + ODPRINTF((L"mhooks: Mhook_Unhook: found struct at %p", pTrampoline)); + // open ourselves so we can VirtualProtectEx + HANDLE hProc = GetCurrentProcess(); + DWORD dwOldProtectSystemFunction = 0; + // make memory writable + if (VirtualProtectEx(hProc, pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode, PAGE_EXECUTE_READWRITE, &dwOldProtectSystemFunction)) { + ODPRINTF((L"mhooks: Mhook_Unhook: readwrite set on system function")); + PBYTE pbCode = (PBYTE)pTrampoline->pSystemFunction; + for (DWORD i = 0; icbOverwrittenCode; i++) { + pbCode[i] = pTrampoline->codeUntouched[i]; + } + // flush instruction cache and make memory unwritable + FlushInstructionCache(hProc, pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode); + VirtualProtectEx(hProc, pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode, dwOldProtectSystemFunction, &dwOldProtectSystemFunction); + // return the original function pointer + *ppHookedFunction = pTrampoline->pSystemFunction; + bRet = true; + ODPRINTF((L"mhooks: Mhook_Unhook: sysfunc: %p", *ppHookedFunction)); + // free the trampoline while not really discarding it from memory + TrampolineFree(pTrampoline, FALSE); + ODPRINTF((L"mhooks: Mhook_Unhook: unhook successful")); + } else { + ODPRINTF((L"mhooks: Mhook_Unhook: failed VirtualProtectEx 1: %d", gle())); + } + // make the other guys runnable + ResumeOtherThreads(); + } + LeaveCritSec(); + return bRet; +} + +//========================================================================= diff --git a/renderdoc/3rdparty/mhook/mhook-lib/mhook.h b/renderdoc/3rdparty/mhook/mhook-lib/mhook.h new file mode 100644 index 0000000000..4c2b0d691a --- /dev/null +++ b/renderdoc/3rdparty/mhook/mhook-lib/mhook.h @@ -0,0 +1,42 @@ +//Copyright (c) 2007-2008, Marton Anka +// +//Permission is hereby granted, free of charge, to any person obtaining a +//copy of this software and associated documentation files (the "Software"), +//to deal in the Software without restriction, including without limitation +//the rights to use, copy, modify, merge, publish, distribute, sublicense, +//and/or sell copies of the Software, and to permit persons to whom the +//Software is furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included +//in all copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +//OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +//THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +//IN THE SOFTWARE. + +#ifdef _M_IX86 +#define _M_IX86_X64 +#elif defined _M_X64 +#define _M_IX86_X64 +#endif + +bool Mhook_SetHook(void **ppSystemFunction, void *pHookFunction); +bool Mhook_Unhook(void **ppHookedFunction); + +// optimisation - when setting many hooks CreateToolHelp32Snapshot to enumerate threads +// can become a bottleneck, allow apps to suspend threads across multiple hooks +// +// note - it's the responsibility of user code to ensure that the threads don't have +// their instruction pointer near any of the hooks - as this would normally be handled +// on a per-hook basis. +// +// these functions are also not thread safe. +void Mhook_SuspendOtherThreads(); +void Mhook_ResumeOtherThreads(); + +#define MHOOKS_MAX_SUPPORTED_HOOKS 512 + diff --git a/renderdoc/Makefile b/renderdoc/Makefile new file mode 100644 index 0000000000..b988f4b4ee --- /dev/null +++ b/renderdoc/Makefile @@ -0,0 +1,72 @@ +CC=gcc +CPP=g++ +MACROS=-DLINUX \ + -DRENDERDOC_PLATFORM=linux \ + -DRENDERDOC_EXPORTS \ + -DGIT_COMMIT_HASH='"'$$(git rev-parse HEAD)'"' \ + -DRENDERDOC_VERSION_STRING='"0.20"' +CFLAGS=-c -Wall -Werror -Wno-error=format -fPIC $(MACROS) -I. +CPPFLAGS=-std=c++11 -g -Wno-unused -Wno-unknown-pragmas -Wno-reorder -fvisibility=hidden -fvisibility-inlines-hidden +LDFLAGS=-lpthread -lrt -shared -ldl -lX11 +OBJECTS=replay/replay_output.o \ +replay/replay_renderer.o \ +replay/entry_points.o \ +replay/basic_types.o \ +hooks/hooks.o \ +hooks/gl_linux_hooks.o \ +hooks/linux_libentry.o \ +serialise/serialiser.o \ +common/common.o \ +core/remote_access.o \ +core/replay_proxy.o \ +core/remote_replay.o \ +core/resource_manager.o \ +core/core.o \ +data/glsl/blit.frago \ +data/glsl/blit.verto \ +data/glsl/texdisplay.frago \ +data/glsl/checkerboard.frago \ +data/glsl/generic.frago \ +data/glsl/generic.verto \ +data/glsl/mesh.verto \ +maths/camera.o \ +maths/matrix.o \ +os/os_specific.o \ +3rdparty/jpeg-compressor/jpgd.o \ +3rdparty/jpeg-compressor/jpge.o \ +3rdparty/lz4/lz4.o \ +driver/gl/gl_common.o \ +driver/gl/gl_context_driver.o \ +driver/gl/gl_device_driver.o \ +driver/gl/gl_driver.o \ +driver/gl/gl_manager.o \ +driver/gl/gl_debug.o \ +driver/gl/gl_replay.o \ +driver/gl/gl_replay_linux.o \ +driver/gl/gl_resources.o \ +os/linux/linux_callstack.o \ +os/linux/linux_network.o \ +os/linux/linux_process.o \ +os/linux/linux_stringio.o \ +os/linux/linux_threading.o + +all: librenderdoc.so + +%.o: %.cpp + $(CPP) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.verto: %.vert + cd $$(dirname $@) && objcopy --input binary --output elf64-x86-64 --binary-architecture i386 $$(basename $<) $$(basename $@) + +%.frago: %.frag + cd $$(dirname $@) && objcopy --input binary --output elf64-x86-64 --binary-architecture i386 $$(basename $<) $$(basename $@) + +librenderdoc.so: $(OBJECTS) $(SOURCES) + g++ -o librenderdoc.so $(LDFLAGS) $(OBJECTS) + +clean: + find -type f -iname \*.o -exec rm '{}' \; + rm -f librenderdoc.so diff --git a/renderdoc/common/common.cpp b/renderdoc/common/common.cpp new file mode 100644 index 0000000000..59e5f99efc --- /dev/null +++ b/renderdoc/common/common.cpp @@ -0,0 +1,180 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common.h" +#include +#include + +#include "os/os_specific.h" +#include "common/threading.h" + +#include "string_utils.h" + +#include +using std::string; + +template<> const wchar_t* pathSeparator() { return L"\\/"; } +template<> const char* pathSeparator() { return "\\/"; } + +template<> const wchar_t* curdir() { return L"."; } +template<> const char* curdir() { return "."; } + +std::wstring widen(std::string str) +{ + return std::wstring(str.begin(), str.end()); +} + +std::string narrow(std::wstring str) +{ + return std::string(str.begin(), str.end()); +} + +void rdcassert(const char *condition, const char *file, unsigned int line, const char *func) +{ + rdclog_int(RDCLog_Error, file, line, "Assertion failed: '%hs'", condition, file, line); +} + +static wstring &logfile() +{ + static wstring fn; + return fn; +} + +const wchar_t *rdclog_getfilename() +{ + return logfile().c_str(); +} + +void rdclog_filename(const wchar_t *filename) +{ + logfile() = L""; + if(filename && filename[0]) + logfile() = filename; +} + +void rdclog_delete() +{ + if(!logfile().empty()) + FileIO::UnlinkFileW(logfile().c_str()); +} + +void rdclog_flush() +{ +} + +void rdclog_int(LogType type, const char *file, unsigned int line, const char *fmt, ...) +{ + if(type <= RDCLog_First || type >= RDCLog_NumTypes) + { + RDCFATAL("Unexpected log type"); + return; + } + + va_list args; + va_start(args, fmt); + + const char *name = "RENDERDOC: "; + + char timestamp[64] = {0}; +#if defined(INCLUDE_TIMESTAMP_IN_LOG) + StringFormat::sntimef(timestamp, 63, "[%H:%M:%S] "); +#endif + + char location[64] = {0}; +#if defined(INCLUDE_LOCATION_IN_LOG) + string loc; + loc = basename(string(file)); + StringFormat::snprintf(location, 63, "% 20s(%4d) - ", loc.c_str(), line); +#endif + + const char *typestr[RDCLog_NumTypes] = { + "Debug ", + "Log ", + "Warning", + "Error ", + "Fatal ", + }; + + const size_t outBufSize = 4*1024; + char outputBuffer[outBufSize+1]; + outputBuffer[outBufSize] = 0; + + char *output = outputBuffer; + size_t available = outBufSize; + + int numWritten = StringFormat::snprintf(output, available, "%hs %hs%hs%hs - ", name, timestamp, location, typestr[type]); + + if(numWritten < 0) + { + va_end(args); + return; + } + + output += numWritten; + available -= numWritten; + + numWritten = StringFormat::vsnprintf(output, available, fmt, args); + + va_end(args); + + if(numWritten < 0) + return; + + output += numWritten; + available -= numWritten; + + if(available < 2) + return; + + *output = '\n'; + *(output+1) = 0; + + { + static Threading::CriticalSection lock; + + SCOPED_LOCK(lock); + +#if defined(OUTPUT_LOG_TO_DEBUG_OUT) + OSUtility::DebugOutputA(outputBuffer); +#endif +#if defined(OUTPUT_LOG_TO_STDOUT) + fprintf(stdout, "%hs", outputBuffer); fflush(stdout); +#endif +#if defined(OUTPUT_LOG_TO_STDERR) + fprintf(stderr, "%hs", outputBuffer); fflush(stderr); +#endif +#if defined(OUTPUT_LOG_TO_DISK) + if(!logfile().empty()) + { + FILE *f = FileIO::fopen(logfile().c_str(), L"a"); + if(f) + { + FileIO::fwrite(outputBuffer, 1, strlen(outputBuffer), f); + FileIO::fclose(f); + } + } +#endif + } +} diff --git a/renderdoc/common/common.h b/renderdoc/common/common.h new file mode 100644 index 0000000000..26c23cd5e7 --- /dev/null +++ b/renderdoc/common/common.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "globalconfig.h" + +///////////////////////////////////////////////// +// Utility macros + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) do { if (p) { delete (p); (p)=NULL; } } while(0) +#endif + +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(p) do { if (p) { delete[] (p); (p)=NULL; } } while(0) +#endif + +#ifndef SAFE_ADDREF +#define SAFE_ADDREF(p) do { if (p) { (p)->AddRef(); } } while(0) +#endif + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) do { if (p) { (p)->Release(); (p)=NULL; } } while(0) +#define SAFE_RELEASE_NOCLEAR(p) do { if (p) { (p)->Release(); } } while(0) +#endif + +#ifndef ARRAY_COUNT +#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof(arr[0])) +#endif + +#define RANDF(mn, mx) ((float(rand())/float(RAND_MAX))*((mx)-(mn))+(mn)) + +#define STRINGIZE2(a) #a +#define STRINGIZE(a) STRINGIZE2(a) + +#define CONCAT2(a, b) a##b +#define CONCAT(a, b) CONCAT2(a, b) + +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) + +#include "os/os_specific.h" + +#define RDCEraseMem(a, b) memset(a, 0, b) +#define RDCEraseEl(a) memset(&a, 0, sizeof(a)) + +template +T RDCCLAMP(const T &val, const T &mn, const T &mx) { return val < mn ? mn : (val > mx ? mx : val); } + +template +T RDCMIN(const T &a, const T &b) { return a < b ? a : b; } + +template +T RDCMAX(const T &a, const T &b) { return a > b ? a : b; } + +template +inline T AlignUp4(T x) { return (x+0x3) & (~0x3); } + +template +inline T AlignUp16(T x) { return (x+0xf) & (~0xf); } + +#define MAKE_FOURCC(a, b, c, d) (((uint32_t)(d) << 24) | ((uint32_t)(c) << 16) | ((uint32_t)(b) << 8) | (uint32_t)(a)) + +///////////////////////////////////////////////// +// Debugging features + +#define RDCDUMP() do { OSUtility::ForceCrash(); } while(0) + +#if !defined(RELEASE) || defined(FORCE_DEBUGBREAK) +#define RDCBREAK() do { if(OSUtility::DebuggerPresent()) OSUtility::DebugBreak(); else RDCDUMP(); } while(0) +#else +#define RDCBREAK() do { } while(0) +#endif + +#define RDCUNIMPLEMENTED(...) do { rdclog(RDCLog_Warning, "Unimplemented: " __VA_ARGS__); RDCBREAK(); } while(0) + +// +// Logging +// + +enum LogType +{ + RDCLog_First = -1, + RDCLog_Debug, + RDCLog_Comment, + RDCLog_Warning, + RDCLog_Error, + RDCLog_Fatal, + RDCLog_NumTypes, +}; + +#if defined(STRIP_LOG) +#define RDCLOGFILE(fn) do { } while(0) +#define RDCLOGDELETE() do { } while(0) + +#define RDCDEBUG(...) do { } while(0) +#define RDCLOG(...) do { } while(0) +#define RDCWARN(...) do { } while(0) +#define RDCERR(...) do { } while(0) +#define RDCFATAL(...) do { RDCDUMP(); exit(0); } while(0) +#else +void rdclog_flush(); +void rdclog_int(LogType type, const char *file, unsigned int line, const char *fmt, ...); + +#define rdclog(type, ...) rdclog_int(type, __FILE__, __LINE__, __VA_ARGS__) + +const wchar_t *rdclog_getfilename(); +void rdclog_filename(const wchar_t *filename); +void rdclog_delete(); + +#define RDCLOGFILE(fn) rdclog_filename(fn) +#define RDCGETLOGFILE() rdclog_getfilename() +#define RDCLOGDELETE() rdclog_delete() + +#if ( !defined(RELEASE) || defined(FORCE_DEBUG_LOGS) ) && !defined(STRIP_DEBUG_LOGS) +#define RDCDEBUG(...) rdclog(RDCLog_Debug, __VA_ARGS__) +#else +#define RDCDEBUG(...) do { } while(0) +#endif + +#define RDCLOG(...) rdclog(RDCLog_Comment, __VA_ARGS__) +#define RDCWARN(...) rdclog(RDCLog_Warning, __VA_ARGS__) + +#if defined(DEBUGBREAK_ON_ERROR_LOG) +#define RDCERR(...) do { rdclog(RDCLog_Error, __VA_ARGS__); rdclog_flush(); RDCBREAK(); } while(0) +#else +#define RDCERR(...) rdclog(RDCLog_Error, __VA_ARGS__) +#endif + +#define RDCFATAL(...) do { rdclog(RDCLog_Fatal, __VA_ARGS__); rdclog_flush(); RDCDUMP(); exit(0); } while(0) +#endif + +// +// Assert +// + +#if !defined(RELEASE) || defined(FORCE_ASSERTS) +void rdcassert(const char *condition, const char *file, unsigned int line, const char *func); + +#define RDCASSERT(cond) do { if(!(cond)) { rdcassert(#cond, __FILE__, __LINE__, __PRETTY_FUNCTION_SIGNATURE__); rdclog_flush(); RDCBREAK(); } } while(0) +#else +#define RDCASSERT(cond) do { } while(0) +#endif + +// +// Compile asserts +// + +#if defined(STRIP_COMPILE_ASSERTS) +#define RDCCOMPILE_ASSERT(condition, message) do { } while(0) +#else +#define RDCCOMPILE_ASSERT(condition, message) static_assert(condition, message) +#endif + +typedef unsigned char byte; diff --git a/renderdoc/common/globalconfig.h b/renderdoc/common/globalconfig.h new file mode 100644 index 0000000000..0b633283e0 --- /dev/null +++ b/renderdoc/common/globalconfig.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +///////////////////////////////////////////////// +// Global constants +enum +{ + RenderDoc_FirstCaptureNetworkPort = 38920, + RenderDoc_LastCaptureNetworkPort = RenderDoc_FirstCaptureNetworkPort + 7, + RenderDoc_ReplayNetworkPort = 39920, +}; + +///////////////////////////////////////////////// +// Debugging features configuration + +// remove all logging code +//#define STRIP_LOG + +// remove all compile time asserts. Normally done even in release +// but this would speed up compilation +//#define STRIP_COMPILE_ASSERTS + +// force asserts regardless of debug/release mode +#define FORCE_ASSERTS + +// force debugbreaks regardless of debug/release mode +//#define FORCE_DEBUGBREAK + +// synchronously (ie. flushed to disk) write out the text-mode only serialised +// data of ALL serialising. Helps in debugging crashes to know exactly which +// calls have been made +//#define DEBUG_TEXT_SERIALISER + +///////////////////////////////////////////////// +// Logging configuration + +// error logs trigger a breakpoint +#define DEBUGBREAK_ON_ERROR_LOG + +// whether to include timestamp on log lines +#define INCLUDE_TIMESTAMP_IN_LOG + +// whether to include file and line on log lines +#define INCLUDE_LOCATION_IN_LOG + +// logs go to stdout/stderr +#define OUTPUT_LOG_TO_STDOUT +//#define OUTPUT_LOG_TO_STDERR + +// logs go to debug output (visual studio output window) +#define OUTPUT_LOG_TO_DEBUG_OUT + +// logs go to disk +#define OUTPUT_LOG_TO_DISK + +// normally only in a debug build do we +// include debug logs. This prints them all the time +//#define FORCE_DEBUG_LOGS +// this strips them completely +//#define STRIP_DEBUG_LOGS + +///////////////////////////////////////////////// +// optional features + +#if defined(NVIDIA_PERFKIT_DIR) +#define ENABLE_NVIDIA_PERFKIT +#endif + +#if defined(AMD_PERFAPI_DIR) +#define ENABLE_AMD_PERFAPI +#endif diff --git a/renderdoc/common/string_utils.h b/renderdoc/common/string_utils.h new file mode 100644 index 0000000000..39458fd11e --- /dev/null +++ b/renderdoc/common/string_utils.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include +#include +#include +#include +using std::basic_string; +using std::vector; + +// in common.cpp +template const charType* pathSeparator(); +template const charType* curdir(); + +template strType basename(const strType &path) +{ + strType base = path; + + if(base.length() == 0) + return base; + + if(base[base.length()-1] == '/' || base[base.length()-1] == '\\') + base.erase(base.size()-1); + + size_t offset = base.find_last_of(pathSeparator()); + + if(offset == strType::npos) + return base; + + return base.substr(offset+1); +} + +template strType dirname(const strType &path) +{ + strType base = path; + + if(base.length() == 0) + return base; + + if(base[base.length()-1] == '/' || base[base.length()-1] == '\\') + base.erase(base.size()-1); + + size_t offset = base.find_last_of(pathSeparator()); + + if(offset == strType::npos) + return curdir(); + + return base.substr(0, offset); +} + +template +void strreplace(basic_string& str, const basic_string& toFind, const basic_string& replacement, typename basic_string::size_type index = 0) +{ + typename basic_string::size_type length = toFind.length(); + + while(index < str.length()) + { + index = str.find(toFind, index); + + if(index < str.length()) + { + str.replace(index, length, replacement); + } + } +} + +template +basic_string strlower(const basic_string& str) +{ + basic_string newstr(str); + transform(newstr.begin(), newstr.end(), newstr.begin(), tolower); + return newstr; +} + +template +basic_string strupper(const basic_string& str) +{ + basic_string newstr(str); + transform(newstr.begin(), newstr.end(), newstr.begin(), (int(*)(int))toupper); + return newstr; +} + +template +void split(const basic_string& in, vector >& out, const CharType sep) +{ + basic_string work = in; + typename basic_string::size_type offset = work.find(sep); + + while(offset != basic_string::npos) + { + out.push_back(work.substr(0, offset)); + work = work.substr(offset+1); + + offset = work.find(sep); + } + + if(work.size() && work[0] != 0) + out.push_back(work); +} + +template +void merge(const vector >& in, basic_string& out, const CharType sep) +{ + out = basic_string(); + for(size_t i=0; i < in.size(); i++) + { + out += in[i]; + out += sep; + } +} + +std::wstring widen(std::string str); +std::string narrow(std::wstring str); diff --git a/renderdoc/common/threading.h b/renderdoc/common/threading.h new file mode 100644 index 0000000000..91827dc3c9 --- /dev/null +++ b/renderdoc/common/threading.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "os/os_specific.h" + +namespace Threading +{ + +class ScopedLock +{ + public: + ScopedLock(CriticalSection &cs) + : m_CS(&cs) + { m_CS->Lock(); } + ~ScopedLock() + { m_CS->Unlock(); } + + private: + CriticalSection *m_CS; +}; + +class TryScopedLock +{ + public: + TryScopedLock(CriticalSection &cs) + : m_CS(&cs) + { m_Owned = m_CS->Trylock(); } + ~TryScopedLock() + { if(m_Owned) m_CS->Unlock(); } + + bool HasLock() + { + return m_Owned; + } + + private: + CriticalSection *m_CS; + bool m_Owned; +}; + +}; + +#define SCOPED_LOCK(cs) Threading::ScopedLock CONCAT(scopedlock, __LINE__)(cs); diff --git a/renderdoc/common/timing.h b/renderdoc/common/timing.h new file mode 100644 index 0000000000..679a684432 --- /dev/null +++ b/renderdoc/common/timing.h @@ -0,0 +1,93 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +using std::string; + +#include +#include + +#include "common.h" +#include "os/os_specific.h" + +class PerformanceTimer +{ + public: + PerformanceTimer() + { + m_CounterFrequency = Timing::GetTickFrequency(); + + Restart(); + } + + double GetMilliseconds() + { + return double(Timing::GetTick()-m_Start)/m_CounterFrequency; + } + + void Restart() + { + m_Start = Timing::GetTick(); + } + + private: + double m_CounterFrequency; + uint64_t m_Start; +}; + +class ScopedTimer +{ + public: + ScopedTimer(const char *file, unsigned int line, const char *fmt, ...) + { + m_File = file; + m_Line = line; + + va_list args; + va_start(args, fmt); + + char buf[1024]; + buf[1023] = 0; + StringFormat::vsnprintf(buf, 1023, fmt, args); + + m_Message = buf; + + va_end(args); + } + + ~ScopedTimer() + { + rdclog_int(RDCLog_Comment, m_File, m_Line, "Timer %hs - %.3lf ms", m_Message.c_str(), m_Timer.GetMilliseconds()); + } + private: + const char *m_File; + unsigned int m_Line; + string m_Message; + PerformanceTimer m_Timer; +}; + +#define SCOPED_TIMER(...) ScopedTimer CONCAT(timer, __LINE__) (__FILE__, __LINE__, __VA_ARGS__); \ No newline at end of file diff --git a/renderdoc/common/wrapped_pool.h b/renderdoc/common/wrapped_pool.h new file mode 100644 index 0000000000..f1adaffc5d --- /dev/null +++ b/renderdoc/common/wrapped_pool.h @@ -0,0 +1,263 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +#include "common.h" +#include "threading.h" + +#if !defined(_RELEASE) +#define INCLUDE_TYPE_NAMES +#endif + +#ifdef INCLUDE_TYPE_NAMES +template class GetTypeName { public: static const char *Name(); }; +#endif + +template class FriendMaker { public: typedef C Type; }; + +// allocate each class in its own pool so we can identify the type by the pointer +template +class WrappingPool +{ + public: + void *Allocate() + { + SCOPED_LOCK(m_Lock); + + // try and allocate from immediate pool + void *ret = m_ImmediatePool.Allocate(); + if(ret != NULL) return ret; + + // fall back to additional pools, if there are any + for(size_t i=0; i < m_AdditionalPools.size(); i++) + { + ret = m_AdditionalPools[i]->Allocate(); + if(ret != NULL) + return ret; + } + + // warn when we need to allocate an additional pool +#ifdef INCLUDE_TYPE_NAMES + RDCWARN("Ran out of free slots in %hs pool!", GetTypeName::Name()); +#else + RDCWARN("Ran out of free slots in pool 0x%p!", &m_ImmediatePool.items[0]); +#endif + + // allocate a new additional pool and use that to allocate from + m_AdditionalPools.push_back(new ItemPool()); + +#ifdef INCLUDE_TYPE_NAMES + RDCDEBUG("WrappingPool[%d]<%hs>: %p -> %p", (uint32_t)m_AdditionalPools.size() - 1, GetTypeName::Name(), + &m_AdditionalPools.back()->items[0], &m_AdditionalPools.back()->items[AllocCount-1]); +#endif + + return m_AdditionalPools.back()->Allocate(); + } + + bool IsAlloc(void *p) + { + // we can check the immediate pool without locking + if(m_ImmediatePool.IsAlloc(p)) + return true; + + // if we have additional pools, lock and check them. + // TODO: Check for additional pools in a lock-free manner, + // to prevent the cost of locking if there are no more pools. + { + SCOPED_LOCK(m_Lock); + + for(size_t i=0; i < m_AdditionalPools.size(); i++) + if(m_AdditionalPools[i]->IsAlloc(p)) + return true; + } + + return false; + } + + void Deallocate(void *p) + { + SCOPED_LOCK(m_Lock); + + // try immediate pool + if(m_ImmediatePool.IsAlloc(p)) + { + m_ImmediatePool.Deallocate(p); + return; + } + else if(!m_AdditionalPools.empty()) + { + // fall back and try additional pools + for(size_t i=0; i < m_AdditionalPools.size(); i++) + { + if(m_AdditionalPools[i]->IsAlloc(p)) + { + m_AdditionalPools[i]->Deallocate(p); + return; + } + } + } + + // this is an error - deleting an object that we don't recognise +#ifdef INCLUDE_TYPE_NAMES + RDCERR("Resource being deleted through wrong pool - 0x%p not a member of %hs", p, GetTypeName::Name()); +#else + RDCERR("Resource being deleted through wrong pool - 0x%p not a member of 0x%p", p, &m_ImmediatePool.items[0])); +#endif + } + + private: + WrappingPool() + { +#ifdef INCLUDE_TYPE_NAMES + RDCDEBUG("WrappingPool<%hs>: %p -> %p", GetTypeName::Name(), &m_ImmediatePool.items[0], &m_ImmediatePool.items[AllocCount-1]); +#endif + + RDCCOMPILE_ASSERT(PoolCount*AllocByteSize <= MaxPoolByteSize, "Pool is bigger than max pool size cap"); + RDCCOMPILE_ASSERT(PoolCount > 2, "Pool isn't greater than 2 in size. Bad parameters?"); // make sure parameters are sane + } + ~WrappingPool() + { + for(size_t i=0; i < m_AdditionalPools.size(); i++) + delete m_AdditionalPools[i]; + + m_AdditionalPools.clear(); + } + + static const size_t AllocCount = PoolCount; + static const size_t AllocByteSize; + + Threading::CriticalSection m_Lock; + + struct ItemPool + { + ItemPool() + { + lastAllocIdx = 0; + RDCEraseEl(allocated); + + items = (WrapType *)(new uint8_t[AllocCount*AllocByteSize]); + } + ~ItemPool() + { + delete[] (uint8_t *)items; + } + + void *Allocate() + { + int lastAlloc = lastAllocIdx; + + if(allocated[lastAlloc]) + { + int end = lastAlloc; + + do + { + lastAlloc = (lastAlloc+1) % PoolCount; + } while (allocated[lastAlloc] && lastAlloc != end); + + if(allocated[lastAlloc]) + { + return NULL; + } + } + + void *ret = (void *)&items[lastAlloc]; + allocated[lastAlloc] = true; + +#if !defined(RELEASE) + memset(ret, 0xb0, AllocByteSize); +#endif + + lastAllocIdx = lastAlloc; + + return ret; + } + + void Deallocate(void *p) + { + RDCASSERT(IsAlloc(p)); + +#if !defined(RELEASE) + if(!IsAlloc(p)) + { + RDCERR("Resource being deleted through wrong pool - 0x%p not a memory of 0x%p", p, &items[0]); + return; + } +#endif + + size_t idx = (WrapType *)p-&items[0]; + + allocated[idx] = false; + +#if !defined(RELEASE) + memset(p, 0xfe, AllocByteSize); +#endif + } + + bool IsAlloc(void *p) + { + return p >= &items[0] && p < &items[PoolCount]; + } + + WrapType *items; + + // could possibly make this uint32s and check via bitmasks, but + // we'll see if it shows up in profiling + bool allocated[PoolCount]; + + // store the last allocations index. Good place to start from and we + // go through the pool in a ring. Good performance when the pool is empty + // or contiguously allocated, poorer performance when the pool gets filled up. + // It also has the bonus of handling repeated new/free well by reallocating the + // same element. + int lastAllocIdx; + }; + + ItemPool m_ImmediatePool; + std::vector m_AdditionalPools; + + friend typename FriendMaker::Type; +}; + +#define ALLOCATE_WITH_WRAPPED_POOL(...) \ + typedef WrappingPool<__VA_ARGS__> PoolType; \ + static PoolType m_Pool; \ + void* operator new(size_t sz) { return m_Pool.Allocate(); } \ + void operator delete(void* p) { m_Pool.Deallocate(p); } \ + static bool IsAlloc(void *p) { return m_Pool.IsAlloc(p); } + +#ifdef INCLUDE_TYPE_NAMES +#define DECL_TYPENAME(a) template<> const char *GetTypeName< a >::Name() { return #a; } +#else +#define DECL_TYPENAME(a) +#endif + +#define WRAPPED_POOL_INST(a) \ + a::PoolType a::m_Pool; \ + const size_t a::PoolType::AllocByteSize = sizeof(a); \ + DECL_TYPENAME(a); diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp new file mode 100644 index 0000000000..8d765259bf --- /dev/null +++ b/renderdoc/core/core.cpp @@ -0,0 +1,528 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "core/core.h" +#include "common/string_utils.h" +#include "serialise/serialiser.h" +#include "replay/replay_driver.h" + +#include + +#ifdef WIN32 +#include "data/resource.h" +#endif + +#include "crash_handler.h" + +template<> +string ToStrHelper::Get(const RDCDriver &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(RDC_Unknown) + TOSTR_CASE_STRINGIZE(RDC_D3D11) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "RDCDriver<%d>", el); + + return tostrBuf; +} + +RenderDoc *RenderDoc::m_Inst = NULL; + +RenderDoc &RenderDoc::Inst() +{ + static RenderDoc realInst; + RenderDoc::m_Inst = &realInst; + return realInst; +} + +void RenderDoc::RecreateCrashHandler() +{ + if(m_ExHandler) + m_ExHandler->UnregisterMemoryRegion(this); + +#ifdef CRASH_HANDLER_ENABLED + m_ExHandler = new CrashHandler(m_ExHandler); +#endif + + if(m_ExHandler) + m_ExHandler->RegisterMemoryRegion(this, sizeof(RenderDoc)); +} + +RenderDoc::RenderDoc() +{ + m_LogFile = L""; + m_MarkerIndentLevel = 0; + m_CurrentDriver = RDC_Unknown; + + m_Replay = false; + + m_Focus = false; + m_Cap = false; + + m_ProgressPtr = NULL; + + m_ExHandler = NULL; + + m_RemoteServerThreadShutdown = false; + m_RemoteClientThreadShutdown = false; +} + +void RenderDoc::Initialise() +{ + Callstack::Init(); + + Network::Init(); + + m_RemoteIdent = 0; + + if(!IsReplayApp()) + { + uint32_t port = RenderDoc_FirstCaptureNetworkPort; + + Network::Socket *sock = Network::CreateServerSocket("0.0.0.0", port&0xffff, 4); + + while(sock == NULL) + { + port++; + if(port > RenderDoc_LastCaptureNetworkPort) + { + m_RemoteIdent = 0; + break; + } + + sock = Network::CreateServerSocket("0.0.0.0", port&0xffff, 4); + } + + if(sock) + { + m_RemoteIdent = port; + + m_RemoteServerThreadShutdown = false; + m_RemoteThread = Threading::CreateThread(RemoteAccessServerThread, (void *)sock); + } + } + + // set default capture log - useful for when hooks aren't setup + // through the UI (and a log file isn't set manually) + { + wstring capture_filename, logging_filename; + + const wchar_t *base = L"RenderDoc_app"; + if(IsReplayApp()) + base = L"RenderDoc_replay"; + + FileIO::GetDefaultFiles(base, capture_filename, logging_filename, m_Target); + + if(m_LogFile.empty()) + SetLogFile(capture_filename.c_str()); + + wstring existingLog = RDCGETLOGFILE(); + FileIO::CopyFileW(existingLog.c_str(), logging_filename.c_str(), true); + RDCLOGFILE(logging_filename.c_str()); + } + + if(IsReplayApp()) + RDCLOG("RenderDoc v%hs (%hs) loaded in replay application", RENDERDOC_VERSION_STRING, GIT_COMMIT_HASH); + else + RDCLOG("RenderDoc v%hs (%hs) capturing application", RENDERDOC_VERSION_STRING, GIT_COMMIT_HASH); + + Keyboard::Init(); + + m_ExHandler = NULL; + + { + wstring curFile; + FileIO::GetExecutableFilename(curFile); + + wstring f = strlower(curFile); + + // only create crash handler when we're not in renderdoccmd.exe (to prevent infinite loop as + // the crash handler itself launches renderdoccmd.exe) + if(f.find(L"renderdoccmd.exe") == wstring::npos) + { + RecreateCrashHandler(); + } + } +} + +RenderDoc::~RenderDoc() +{ + if(m_ExHandler) + { + m_ExHandler->UnregisterMemoryRegion(this); + + SAFE_DELETE(m_ExHandler); + } + + for(size_t i=0; i < m_CapturePaths.size(); i++) + { + if(m_CaptureRetrieved[i]) + { + RDCLOG("Removing remotely retrieved capture %ls", m_CapturePaths[i].c_str()); + FileIO::UnlinkFileW(m_CapturePaths[i].c_str()); + } + else + { + RDCLOG("'Leaking' unretrieved capture %ls", m_CapturePaths[i].c_str()); + } + } + + m_RemoteServerThreadShutdown = true; + Threading::JoinThread(m_RemoteThread); + Threading::CloseThread(m_RemoteThread); + m_RemoteThread = 0; + + Network::Shutdown(); + + RDCLOGDELETE(); +} + +void RenderDoc::Tick() +{ + static bool prev_f11 = false; + static bool prev_f12 = false; + + bool cur_f11 = Keyboard::GetKeyState(Keyboard::eKey_F11); + bool cur_f12 = Keyboard::GetKeyState(Keyboard::eKey_F12) || Keyboard::GetKeyState(Keyboard::eKey_PrtScrn); + + if(!prev_f11 && cur_f11) + FocusToggle(); + if(!prev_f12 && cur_f12) + TriggerCapture(); + + prev_f11 = cur_f11; + prev_f12 = cur_f12; +} + +bool RenderDoc::ShouldTriggerCapture(uint32_t frameNumber) +{ + bool ret = m_Cap; + + m_Cap = false; + + set frames; + frames.swap(m_QueuedFrameCaptures); + for(auto it=frames.begin(); it != frames.end(); ++it) + { + if(*it < frameNumber) + { + // discard, this frame is past. + } + else if((*it) - 1 == frameNumber) + { + // we want to capture the next frame + ret = true; + } + else + { + // not hit this yet, keep it around + m_QueuedFrameCaptures.insert(*it); + } + } + + return ret; +} + +Serialiser *RenderDoc::OpenWriteSerialiser(uint32_t frameNum, RDCInitParams *params, void *thpixels, size_t thlen, uint32_t thwidth, uint32_t thheight) +{ + RDCASSERT(m_CurrentDriver != RDC_Unknown); + +#if defined(RELEASE) + const bool debugSerialiser = false; +#else + const bool debugSerialiser = true; +#endif + + m_CurrentLogFile = StringFormat::WFmt(L"%ls_frame%u.rdc", m_LogFile.c_str(), frameNum); + + Serialiser *fileSerialiser = new Serialiser(m_CurrentLogFile.c_str(), Serialiser::WRITING, debugSerialiser); + + + Serialiser *chunkSerialiser = new Serialiser(NULL, Serialiser::WRITING, debugSerialiser); + + { + ScopedContext scope(chunkSerialiser, NULL, "Thumbnail", THUMBNAIL_DATA, false); + + bool HasThumbnail = (thpixels != NULL && thwidth > 0 && thheight > 0); + chunkSerialiser->Serialise("HasThumbnail", HasThumbnail); + + if(HasThumbnail) + { + byte *buf = (byte *)thpixels; + chunkSerialiser->Serialise("ThumbWidth", thwidth); + chunkSerialiser->Serialise("ThumbHeight", thheight); + chunkSerialiser->SerialiseBuffer("ThumbnailPixels", buf, thlen); + } + + fileSerialiser->Insert(scope.Get(true)); + } + + { + ScopedContext scope(chunkSerialiser, NULL, "Capture Create Parameters", CREATE_PARAMS, false); + + chunkSerialiser->Serialise("DriverType", m_CurrentDriver); + chunkSerialiser->SerialiseString("DriverName", m_CurrentDriverName); + + { + ScopedContext scope(chunkSerialiser, NULL, "Driver Specific", DRIVER_INIT_PARAMS, false); + + params->m_pSerialiser = chunkSerialiser; + params->m_State = WRITING; + params->Serialise(); + } + + fileSerialiser->Insert(scope.Get(true)); + } + + SAFE_DELETE(chunkSerialiser); + + return fileSerialiser; +} + +ReplayCreateStatus RenderDoc::FillInitParams(const wchar_t *logFile, RDCDriver &driverType, wstring &driverName, RDCInitParams *params) +{ + Serialiser ser(logFile, Serialiser::READING, true); + + if(ser.HasError()) + { + RDCERR("Couldn't open '%ls'", logFile); + + switch(ser.ErrorCode()) + { + case Serialiser::eSerError_FileIO: return eReplayCreate_FileIOFailed; + case Serialiser::eSerError_Corrupt: return eReplayCreate_FileCorrupted; + case Serialiser::eSerError_UnsupportedVersion: return eReplayCreate_FileIncompatibleVersion; + default: break; + } + + return eReplayCreate_InternalError; + } + + ser.Rewind(); + + { + int chunkType = ser.PushContext(NULL, 1, false); + + if(chunkType != THUMBNAIL_DATA) + { + RDCERR("Malformed logfile '%ls', first chunk isn't thumbnail data", logFile); + return eReplayCreate_FileCorrupted; + } + + ser.SkipCurrentChunk(); + + ser.PopContext(NULL, 1); + } + + { + int chunkType = ser.PushContext(NULL, 1, false); + + if(chunkType != CREATE_PARAMS) + { + RDCERR("Malformed logfile '%ls', second chunk isn't create params", logFile); + return eReplayCreate_FileCorrupted; + } + + ser.Serialise("DriverType", driverType); + ser.SerialiseString("DriverName", driverName); + + chunkType = ser.PushContext(NULL, 1, false); + + if(chunkType != DRIVER_INIT_PARAMS) + { + RDCERR("Malformed logfile '%ls', chunk doesn't contain driver init params", logFile); + return eReplayCreate_FileCorrupted; + } + + if(params) + { + params->m_State = READING; + params->m_pSerialiser = &ser; + return params->Serialise(); + } + } + + // we can just throw away the serialiser, don't need to care about closing/popping contexts + return eReplayCreate_Success; +} + +bool RenderDoc::HasReplayDriver(RDCDriver driver) +{ + return m_ReplayDriverProviders.find(driver) != m_ReplayDriverProviders.end(); +} + +bool RenderDoc::HasRemoteDriver(RDCDriver driver) +{ + if(m_RemoteDriverProviders.find(driver) != m_RemoteDriverProviders.end()) + return true; + + return HasReplayDriver(driver); +} + +void RenderDoc::RegisterReplayProvider(RDCDriver driver, const wchar_t *name, ReplayDriverProvider provider) +{ + if(HasReplayDriver(driver)) + RDCERR("Re-registering provider for %ls (was %ls)", name, m_DriverNames[driver].c_str()); + if(HasRemoteDriver(driver)) + RDCWARN("Registering local provider %ls for existing remote provider %ls", name, m_DriverNames[driver].c_str()); + + m_DriverNames[driver] = name; + m_ReplayDriverProviders[driver] = provider; +} + +void RenderDoc::RegisterRemoteProvider(RDCDriver driver, const wchar_t *name, RemoteDriverProvider provider) +{ + if(HasRemoteDriver(driver)) + RDCERR("Re-registering provider for %ls (was %ls)", name, m_DriverNames[driver].c_str()); + if(HasReplayDriver(driver)) + RDCWARN("Registering remote provider %ls for existing local provider %ls", name, m_DriverNames[driver].c_str()); + + m_DriverNames[driver] = name; + m_RemoteDriverProviders[driver] = provider; +} + +ReplayCreateStatus RenderDoc::CreateReplayDriver(RDCDriver driverType, const wchar_t *logfile, IReplayDriver **driver) +{ + if(driver == NULL) return eReplayCreate_InternalError; + + if(m_ReplayDriverProviders.find(driverType) != m_ReplayDriverProviders.end()) + return m_ReplayDriverProviders[driverType](logfile, driver); + + RDCERR("Unsupported replay driver requested: %d", driverType); + return eReplayCreate_APIUnsupported; +} + +ReplayCreateStatus RenderDoc::CreateRemoteDriver(RDCDriver driverType, const wchar_t *logfile, IRemoteDriver **driver) +{ + if(driver == NULL) return eReplayCreate_InternalError; + + if(m_RemoteDriverProviders.find(driverType) != m_RemoteDriverProviders.end()) + return m_RemoteDriverProviders[driverType](logfile, driver); + + // replay drivers are remote drivers, fall back and try them + if(m_ReplayDriverProviders.find(driverType) != m_ReplayDriverProviders.end()) + { + IReplayDriver *dr = NULL; + auto status = m_ReplayDriverProviders[driverType](logfile, &dr); + + if(status == eReplayCreate_Success) + *driver = (IRemoteDriver *)dr; + else + RDCASSERT(dr == NULL); + + return status; + } + + RDCERR("Unsupported replay driver requested: %d", driverType); + return eReplayCreate_APIUnsupported; +} + +void RenderDoc::SetCurrentDriver(RDCDriver driver) +{ + if(!HasReplayDriver(driver) && !HasRemoteDriver(driver)) + { + RDCFATAL("Trying to register unsupported driver!"); + } + m_CurrentDriver = driver; + m_CurrentDriverName = m_DriverNames[driver]; +} + +void RenderDoc::GetCurrentDriver(RDCDriver &driver, wstring &name) +{ + driver = m_CurrentDriver; + name = m_CurrentDriverName; +} + +map RenderDoc::GetReplayDrivers() +{ + map ret; + for(auto it=m_ReplayDriverProviders.begin(); it != m_ReplayDriverProviders.end(); ++it) + ret[it->first] = m_DriverNames[it->first]; + return ret; +} + +map RenderDoc::GetRemoteDrivers() +{ + map ret; + + for(auto it=m_RemoteDriverProviders.begin(); it != m_RemoteDriverProviders.end(); ++it) + ret[it->first] = m_DriverNames[it->first]; + + // replay drivers are remote drivers. + for(auto it=m_ReplayDriverProviders.begin(); it != m_ReplayDriverProviders.end(); ++it) + ret[it->first] = m_DriverNames[it->first]; + + return ret; +} + +void RenderDoc::SetCaptureOptions(const CaptureOptions *opts) +{ + m_Options = *opts; +} + +void RenderDoc::SetLogFile(const wchar_t *logFile) +{ + m_LogFile = logFile; + + if(m_LogFile.substr(m_LogFile.length()-4) == L".rdc") + m_LogFile = m_LogFile.substr(0, m_LogFile.length()-4); +} + +void RenderDoc::SetProgress(LoadProgressSection section, float delta) +{ + if(m_ProgressPtr == NULL) + return; + + float weights[NumSections]; + + // must sum to 1.0 + weights[DebugManagerInit] = 0.4f; + weights[FileInitialRead] = 0.6f; + + float progress = 0.0f; + for(int i=0; i < section; i++) + { + progress += weights[i]; + } + + progress += weights[section]*delta; + + *m_ProgressPtr = progress; +} + +void RenderDoc::SuccessfullyWrittenLog() +{ + RDCLOG("Written to disk: %ls", m_CurrentLogFile.c_str()); + + { + SCOPED_LOCK(m_CaptureLock); + m_CapturePaths.push_back(m_CurrentLogFile); + m_CaptureRetrieved.push_back(false); + } +} diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h new file mode 100644 index 0000000000..e6a6b7de60 --- /dev/null +++ b/renderdoc/core/core.h @@ -0,0 +1,261 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +#include +#include +#include +#include +using std::wstring; +using std::vector; +using std::map; +using std::set; + +class Serialiser; +class Chunk; + +#include "replay/capture_options.h" +#include "replay/replay_enums.h" +#include "os/os_specific.h" +#include "common/threading.h" + +struct ICrashHandler +{ + virtual ~ICrashHandler() {} + + virtual void WriteMinidump() = 0; + virtual void WriteMinidump(void *data) = 0; + + virtual void RegisterMemoryRegion(void *mem, size_t size) = 0; + virtual void UnregisterMemoryRegion(void *mem) = 0; +}; + +enum LogState +{ + READING = 0, + EXECUTING, + WRITING, + WRITING_IDLE, + WRITING_CAPFRAME, +}; + +enum SystemChunks +{ + // 0 is reserved as a 'null' chunk that is only for debug + CREATE_PARAMS = 1, + THUMBNAIL_DATA, + DRIVER_INIT_PARAMS, + INITIAL_CONTENTS, + + FIRST_CHUNK_ID, +}; + +enum RDCDriver +{ + RDC_Unknown = 0, + RDC_D3D11 = 1, + RDC_OpenGL = 2, + RDC_Reserved1 = 3, + RDC_Reserved2 = 4, + RDC_D3D10 = 5, + RDC_D3D9 = 6, + RDC_Custom = 100000, + RDC_Custom0 = RDC_Custom, + RDC_Custom1, + RDC_Custom2, + RDC_Custom3, + RDC_Custom4, + RDC_Custom5, + RDC_Custom6, + RDC_Custom7, + RDC_Custom8, + RDC_Custom9, +}; + +namespace DXBC { class DXBCFile; } +namespace Callstack { class StackResolver; } + +enum ReplayLogType +{ + eReplay_Full, + eReplay_WithoutDraw, + eReplay_OnlyDraw, +}; + +struct RDCInitParams +{ + RDCInitParams() { m_State = WRITING; m_pSerialiser = m_pDebugSerialiser = NULL; } + virtual ~RDCInitParams() {} + virtual ReplayCreateStatus Serialise() = 0; + + LogState m_State; + Serialiser *m_pSerialiser; + Serialiser *m_pDebugSerialiser; +}; + +enum LoadProgressSection +{ + DebugManagerInit, + FileInitialRead, + NumSections, +}; + +class IRemoteDriver; +class IReplayDriver; + +typedef ReplayCreateStatus (*RemoteDriverProvider)(const wchar_t *logfile, IRemoteDriver **driver); +typedef ReplayCreateStatus (*ReplayDriverProvider)(const wchar_t *logfile, IReplayDriver **driver); + +// this class mediates everything and owns any 'global' resources such as the crash handler. +// +// It acts as a central hub that registers any driver providers and can be asked to create one +// for a given logfile or type. +class RenderDoc +{ + public: + static RenderDoc &Inst(); + + void SetProgressPtr(float *progress) { m_ProgressPtr = progress; } + void SetProgress(LoadProgressSection section, float delta); + + // set from outside of the device creation interface + void SetLogFile(const wchar_t *logFile); + const wchar_t *GetLogFile() { return m_LogFile.c_str(); } + + const wchar_t *GetCurrentTarget() { return m_Target.c_str(); } + + void Initialise(); + + void SetReplayApp(bool replay) { m_Replay = replay; } + bool IsReplayApp() { return m_Replay; } + + void BecomeReplayHost(volatile bool &killReplay); + + void SetCaptureOptions(const CaptureOptions *opts); + const CaptureOptions &GetCaptureOptions() { return m_Options; } + + void RecreateCrashHandler(); + ICrashHandler *GetCrashHandler() { return m_ExHandler; } + + Serialiser *OpenWriteSerialiser(uint32_t frameNum, RDCInitParams *params, void *thpixels, size_t thlen, uint32_t thwidth, uint32_t thheight); + void SuccessfullyWrittenLog(); + + vector GetCaptures() + { + SCOPED_LOCK(m_CaptureLock); + return m_CapturePaths; + } + + void MarkCaptureRetrieved(uint32_t idx) + { + SCOPED_LOCK(m_CaptureLock); + if(idx < m_CapturePaths.size()) + { + m_CaptureRetrieved[idx] = true; + } + } + + ReplayCreateStatus FillInitParams(const wchar_t *logfile, RDCDriver &driverType, wstring &driverName, RDCInitParams *params); + + void RegisterReplayProvider(RDCDriver driver, const wchar_t *name, ReplayDriverProvider provider); + void RegisterRemoteProvider(RDCDriver driver, const wchar_t *name, RemoteDriverProvider provider); + + ReplayCreateStatus CreateReplayDriver(RDCDriver driverType, const wchar_t *logfile, IReplayDriver **driver); + ReplayCreateStatus CreateRemoteDriver(RDCDriver driverType, const wchar_t *logfile, IRemoteDriver **driver); + + map GetReplayDrivers(); + map GetRemoteDrivers(); + + bool HasReplayDriver(RDCDriver driver); + bool HasRemoteDriver(RDCDriver driver); + + void SetCurrentDriver(RDCDriver driver); + void GetCurrentDriver(RDCDriver &driver, wstring &name); + + uint32_t GetRemoteAccessIdent() { return m_RemoteIdent; } + + void Tick(); + + void FocusToggle() { m_Focus = true; m_Cap = false; } + void TriggerCapture() { m_Cap = true; } + + void QueueCapture(uint32_t frameNumber) { m_QueuedFrameCaptures.insert(frameNumber); } + + bool ShouldFocusToggle() { bool ret = m_Focus; m_Focus = false; return ret; } + bool ShouldTriggerCapture(uint32_t frameNumber); + private: + RenderDoc(); + ~RenderDoc(); + + static RenderDoc *m_Inst; + + bool m_Replay; + + bool m_Focus; + bool m_Cap; + + wstring m_Target; + wstring m_LogFile; + wstring m_CurrentLogFile; + CaptureOptions m_Options; + + set m_QueuedFrameCaptures; + + uint32_t m_RemoteIdent; + Threading::ThreadHandle m_RemoteThread; + + int32_t m_MarkerIndentLevel; + RDCDriver m_CurrentDriver; + wstring m_CurrentDriverName; + + float *m_ProgressPtr; + + Threading::CriticalSection m_CaptureLock; + vector m_CapturePaths; + vector m_CaptureRetrieved; + + map m_DriverNames; + map m_ReplayDriverProviders; + map m_RemoteDriverProviders; + + volatile bool m_RemoteServerThreadShutdown; + volatile bool m_RemoteClientThreadShutdown; + Threading::CriticalSection m_SingleClientLock; + wstring m_SingleClientName; + + static void RemoteAccessServerThread(void *s); + static void RemoteAccessClientThread(void *s); + + ICrashHandler *m_ExHandler; +}; + +struct DriverRegistration +{ + DriverRegistration(RDCDriver driver, const wchar_t *name, ReplayDriverProvider provider) { RenderDoc::Inst().RegisterReplayProvider(driver, name, provider); } + DriverRegistration(RDCDriver driver, const wchar_t *name, RemoteDriverProvider provider) { RenderDoc::Inst().RegisterRemoteProvider(driver, name, provider); } +}; diff --git a/renderdoc/core/crash_handler.h b/renderdoc/core/crash_handler.h new file mode 100644 index 0000000000..1a8af94fe7 --- /dev/null +++ b/renderdoc/core/crash_handler.h @@ -0,0 +1,162 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + + +#if USE_BREAKPAD && defined(RENDERDOC_OFFICIAL_BUILD) + +#define CRASH_HANDLER_ENABLED + +// breakpad +#include "client/windows/handler/exception_handler.h" +#include "client/windows/common/ipc_protocol.h" + +class CrashHandler : public ICrashHandler +{ + public: + CrashHandler(ICrashHandler *existing) + { + m_ExHandler = NULL; + + google_breakpad::AppMemoryList mem; + + if(existing) + mem = ((CrashHandler *)existing)->m_ExHandler->QueryRegisteredAppMemory(); + + SAFE_DELETE(existing); + + /////////////////// + + wchar_t tempPath[MAX_PATH] = {0}; + GetTempPathW(MAX_PATH-1, tempPath); + + wstring dumpFolder = tempPath; + dumpFolder += L"RenderDocDumps"; + + CreateDirectoryW(dumpFolder.c_str(), NULL); + + MINIDUMP_TYPE dumpType = MINIDUMP_TYPE(MiniDumpNormal|MiniDumpWithIndirectlyReferencedMemory); + + { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + RDCEraseEl(pi); + RDCEraseEl(si); + + HANDLE waitEvent = CreateEventA(NULL, TRUE, FALSE, "RENDERDOC_CRASHHANDLE"); + + wchar_t radpath[MAX_PATH] = {0}; + GetModuleFileNameW(GetModuleHandleA("renderdoc.dll"), radpath, MAX_PATH-1); + + size_t len = wcslen(radpath); + + wchar_t *slash = wcsrchr(radpath, L'\\'); + + if(slash) + { + *slash = 0; + } + else + { + slash = wcsrchr(radpath, L'/'); + + if(slash) + *slash = 0; + else + { + radpath[0] = '.'; + radpath[1] = 0; + } + } + + wstring cmdline = L"\""; + cmdline += radpath; + cmdline += L"/renderdoccmd.exe\" crashhandle"; + + wchar_t *paramsAlloc = new wchar_t[512]; + + wcscpy_s(paramsAlloc, 511, cmdline.c_str()); + + CreateProcessW(NULL, paramsAlloc, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + DWORD res = WaitForSingleObject(waitEvent, 2000); + + CloseHandle(waitEvent); + } + + static google_breakpad::CustomInfoEntry breakpadCustomInfo[] = { + google_breakpad::CustomInfoEntry(L"version", RENDERDOC_VERSION_STRING_W), + google_breakpad::CustomInfoEntry(L"logpath", RDCGETLOGFILE()), + }; + + breakpadCustomInfo[1].set_value(RDCGETLOGFILE()); + + google_breakpad::CustomClientInfo custom = { &breakpadCustomInfo[0], ARRAY_COUNT(breakpadCustomInfo) }; + + _CrtSetReportMode(_CRT_ASSERT, 0); + m_ExHandler = new google_breakpad::ExceptionHandler(dumpFolder.c_str(), + NULL, + NULL, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL, + dumpType, + L"\\\\.\\pipe\\RenderDocBreakpadServer", + &custom); + + m_ExHandler->set_handle_debug_exceptions(true); + + for(size_t i=0; i < mem.size(); i++) + m_ExHandler->RegisterAppMemory((void *)mem[i].ptr, mem[i].length); + } + + virtual ~CrashHandler() + { + SAFE_DELETE(m_ExHandler); + } + + void WriteMinidump() + { + m_ExHandler->WriteMinidump(); + } + + void WriteMinidump(void *data) + { + m_ExHandler->WriteMinidumpForException((EXCEPTION_POINTERS *)data); + } + + void RegisterMemoryRegion(void *mem, size_t size) + { + m_ExHandler->RegisterAppMemory(mem, size); + } + + void UnregisterMemoryRegion(void *mem) + { + m_ExHandler->UnregisterAppMemory(mem); + } + + private: + google_breakpad::ExceptionHandler *m_ExHandler; +}; + +#endif diff --git a/renderdoc/core/remote_access.cpp b/renderdoc/core/remote_access.cpp new file mode 100644 index 0000000000..0d1fd1b599 --- /dev/null +++ b/renderdoc/core/remote_access.cpp @@ -0,0 +1,624 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "replay/type_helpers.h" +#include "replay/renderdoc.h" +#include "core/core.h" +#include "os/os_specific.h" +#include "serialise/serialiser.h" +#include "socket_helpers.h" + +enum PacketType +{ + ePacket_Noop, + ePacket_Handshake, + ePacket_Busy, + ePacket_NewCapture, + ePacket_RegisterAPI, + ePacket_TriggerCapture, + ePacket_CopyCapture, + ePacket_QueueCapture, +}; + +void RenderDoc::RemoteAccessClientThread(void *s) +{ + Network::Socket *client = (Network::Socket *)s; + + Serialiser ser(L"", Serialiser::WRITING, false); + + wstring api = L""; + RDCDriver driver; + RenderDoc::Inst().GetCurrentDriver(driver, api); + + ser.Rewind(); + + wstring target = RenderDoc::Inst().GetCurrentTarget(); + ser.Serialise("", target); + ser.Serialise("", api); + + if(!SendPacket(client, ePacket_Handshake, ser)) + { + SAFE_DELETE(client); + + { + SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock); + RenderDoc::Inst().m_SingleClientName = L""; + } + + return; + } + + const int pingtime = 1000; // ping every 1000ms + const int ticktime = 10; // tick every 10ms + int curtime = 0; + + vector captures; + + while(client) + { + if(RenderDoc::Inst().m_RemoteClientThreadShutdown || (client && !client->Connected())) + { + SAFE_DELETE(client); + break; + } + + ser.Rewind(); + + Threading::Sleep(ticktime); + curtime += ticktime; + + PacketType packetType = ePacket_Noop; + + wstring curapi; + RenderDoc::Inst().GetCurrentDriver(driver, curapi); + + if(curapi != api) + { + api = curapi; + + ser.Serialise("", api); + + packetType = ePacket_RegisterAPI; + } + else + { + vector caps = RenderDoc::Inst().GetCaptures(); + + if(caps.size() != captures.size()) + { + uint32_t idx = (uint32_t)captures.size(); + + captures.push_back(caps[idx]); + + packetType = ePacket_NewCapture; + + uint64_t timestamp = FileIO::GetModifiedTimestamp(captures.back().c_str()); + ser.Serialise("", idx); + ser.Serialise("", timestamp); + + ser.Serialise("", captures.back()); + + uint32_t len = 128*1024; + byte *thumb = new byte[len]; + RENDERDOC_GetThumbnail(captures.back().c_str(), thumb, len); + + size_t l = len; + ser.Serialise("", len); + ser.SerialiseBuffer("", thumb, l); + delete[] thumb; + } + } + + if(curtime < pingtime && packetType == ePacket_Noop) + { + if(client->IsRecvDataWaiting()) + { + PacketType type; + Serialiser *recvser = NULL; + + if(!RecvPacket(client, type, &recvser)) + SAFE_DELETE(client); + + if(client == NULL) + { + SAFE_DELETE(recvser); + continue; + } + else if(type == ePacket_TriggerCapture) + { + RenderDoc::Inst().TriggerCapture(); + } + else if(type == ePacket_QueueCapture) + { + uint32_t frameNum = 0; + recvser->Serialise("", frameNum); + + RenderDoc::Inst().QueueCapture(frameNum); + } + else if(type == ePacket_CopyCapture) + { + vector caps = RenderDoc::Inst().GetCaptures(); + + uint32_t id = 0; + recvser->Serialise("", id); + + if(id < caps.size()) + { + ser.Serialise("", id); + + if(!SendPacket(client, ePacket_CopyCapture, ser)) + { + SAFE_DELETE(client); + continue; + } + + ser.Rewind(); + + if(!SendChunkedFile(client, ePacket_CopyCapture, caps[id].c_str(), ser, NULL)) + { + SAFE_DELETE(client); + continue; + } + + RenderDoc::Inst().MarkCaptureRetrieved(id); + } + } + + SAFE_DELETE(recvser); + } + + continue; + } + + curtime = 0; + + if(!SendPacket(client, packetType, ser)) + { + SAFE_DELETE(client); + continue; + } + } + + // give up our connection + { + SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock); + RenderDoc::Inst().m_SingleClientName = L""; + } +} + +void RenderDoc::RemoteAccessServerThread(void *s) +{ + Network::Socket *sock = (Network::Socket *)s; + + RenderDoc::Inst().m_SingleClientName = L""; + + Threading::ThreadHandle clientThread = 0; + + RenderDoc::Inst().m_RemoteClientThreadShutdown = false; + + while(!RenderDoc::Inst().m_RemoteServerThreadShutdown) + { + Network::Socket *client = sock->AcceptClient(false); + + if(client == NULL) + { + if(!sock->Connected()) + { + RDCERR("Error in accept - shutting down server"); + + SAFE_DELETE(sock); + return; + } + + Threading::Sleep(5); + + continue; + } + + wstring existingClient; + wstring newClient; + bool kick = false; + + // receive handshake from client and get its name + { + PacketType type; + Serialiser *ser; + if(!RecvPacket(client, type, &ser)) + { + SAFE_DELETE(ser); + SAFE_DELETE(client); + continue; + } + + if(type != ePacket_Handshake) + { + SAFE_DELETE(ser); + SAFE_DELETE(client); + continue; + } + + ser->SerialiseString("", newClient); + ser->Serialise("", kick); + + SAFE_DELETE(ser); + + if(newClient.empty()) + { + SAFE_DELETE(client); + continue; + } + } + + // see if we have a client + { + SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock); + existingClient = RenderDoc::Inst().m_SingleClientName; + } + + if(!existingClient.empty() && kick) + { + // forcibly close communication thread which will kill the connection + RenderDoc::Inst().m_RemoteClientThreadShutdown = true; + Threading::JoinThread(clientThread); + Threading::CloseThread(clientThread); + clientThread = 0; + RenderDoc::Inst().m_RemoteClientThreadShutdown = false; + existingClient = L""; + } + + if(existingClient.empty()) + { + SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock); + RenderDoc::Inst().m_SingleClientName = newClient; + } + + // if we've claimed client status, spawn a thread to communicate + if(existingClient.empty() || kick) + { + clientThread = Threading::CreateThread(RemoteAccessClientThread, client); + continue; + } + else + { + // if we've been asked to kick the existing connection off + // reject this connection and tell them who is busy + Serialiser ser(L"", Serialiser::WRITING, false); + + wstring api = L""; + RDCDriver driver; + RenderDoc::Inst().GetCurrentDriver(driver, api); + + wstring target = RenderDoc::Inst().GetCurrentTarget(); + ser.Serialise("", target); + ser.Serialise("", api); + + ser.SerialiseString("", RenderDoc::Inst().m_SingleClientName); + + // don't care about errors, we're going to close the connection either way + SendPacket(client, ePacket_Busy, ser); + + SAFE_DELETE(client); + } + } + + RenderDoc::Inst().m_RemoteClientThreadShutdown = true; + Threading::JoinThread(clientThread); + Threading::CloseThread(clientThread); + clientThread = 0; +} + +struct RemoteAccess +{ + public: + RemoteAccess(Network::Socket *sock, wstring clientName, bool forceConnection, bool localhost) + : m_Socket(sock), m_Local(localhost) + { + PacketType type; + vector payload; + + { + Serialiser ser(L"", Serialiser::WRITING, false); + + ser.SerialiseString("", clientName); + ser.Serialise("", forceConnection); + + if(!SendPacket(m_Socket, ePacket_Handshake, ser)) + { + SAFE_DELETE(m_Socket); + return; + } + } + + Serialiser *ser = NULL; + GetPacket(type, ser); + + RDCASSERT(type == ePacket_Handshake || type == ePacket_Busy); + + if(type == ePacket_Handshake) + { + ser->Serialise("", m_Target); + ser->Serialise("", m_API); + + RDCLOG("Got remote handshake: %ls (%ls)", m_Target.c_str(), m_API.c_str()); + } + else if(type == ePacket_Busy) + { + ser->Serialise("", m_Target); + ser->Serialise("", m_API); + ser->Serialise("", m_BusyClient); + + RDCLOG("Got remote busy signal: %ls (%ls) owned by %ls", m_Target.c_str(), m_API.c_str(), m_BusyClient.c_str()); + } + + SAFE_DELETE(ser); + } + + bool Connected() { return m_Socket != NULL && m_Socket->Connected(); } + + void Shutdown() + { + SAFE_DELETE(m_Socket); + delete this; + } + + const wchar_t *GetTarget() + { + return m_Target.c_str(); + } + + const wchar_t *GetAPI() + { + return m_API.c_str(); + } + + const wchar_t *GetBusyClient() + { + return m_BusyClient.c_str(); + } + + void TriggerCapture() + { + if(!SendPacket(m_Socket, ePacket_TriggerCapture)) + SAFE_DELETE(m_Socket); + } + + void QueueCapture(uint32_t frameNumber) + { + Serialiser ser(L"", Serialiser::WRITING, false); + + ser.Serialise("", frameNumber); + + if(!SendPacket(m_Socket, ePacket_QueueCapture, ser)) + { + SAFE_DELETE(m_Socket); + return; + } + } + + void CopyCapture(uint32_t remoteID, const wchar_t *localpath) + { + Serialiser ser(L"", Serialiser::WRITING, false); + + ser.Serialise("", remoteID); + + if(!SendPacket(m_Socket, ePacket_CopyCapture, ser)) + { + SAFE_DELETE(m_Socket); + return; + } + + m_CaptureCopies[remoteID] = localpath; + } + + void ReceiveMessage(RemoteMessage *msg) + { + if(m_Socket == NULL) + { + msg->Type = eRemoteMsg_Disconnected; + return; + } + + if(!m_Socket->IsRecvDataWaiting()) + { + if(!m_Socket->Connected()) + { + SAFE_DELETE(m_Socket); + msg->Type = eRemoteMsg_Disconnected; + } + else + { + Threading::Sleep(2); + msg->Type = eRemoteMsg_Noop; + } + + return; + } + + PacketType type; + Serialiser *ser = NULL; + + GetPacket(type, ser); + + if(m_Socket == NULL) + { + SAFE_DELETE(ser); + + msg->Type = eRemoteMsg_Disconnected; + return; + } + else + { + if(type == ePacket_Noop) + { + SAFE_DELETE(ser); + + RDCDEBUG("Got a no-op"); + msg->Type = eRemoteMsg_Noop; + return; + } + else if(type == ePacket_Busy) + { + wstring existingClient; + ser->Serialise("", existingClient); + + SAFE_DELETE(ser); + + SAFE_DELETE(m_Socket); + + RDCLOG("Got busy signal: '%ls", existingClient.c_str()); + msg->Type = eRemoteMsg_Busy; + msg->Busy.ClientName = existingClient; + return; + } + else if(type == ePacket_CopyCapture) + { + msg->Type = eRemoteMsg_CaptureCopied; + + ser->Serialise("", msg->NewCapture.ID); + + SAFE_DELETE(ser); + + msg->NewCapture.localpath = m_CaptureCopies[msg->NewCapture.ID]; + + if(!RecvChunkedFile(m_Socket, ePacket_CopyCapture, msg->NewCapture.localpath.elems, ser, NULL)) + { + SAFE_DELETE(ser); + SAFE_DELETE(m_Socket); + + msg->Type = eRemoteMsg_Disconnected; + return; + } + + m_CaptureCopies.erase(msg->NewCapture.ID); + + SAFE_DELETE(ser); + + return; + } + else if(type == ePacket_NewCapture) + { + msg->Type = eRemoteMsg_NewCapture; + + ser->Serialise("", msg->NewCapture.ID); + ser->Serialise("", msg->NewCapture.timestamp); + + wstring path; + ser->Serialise("", path); + msg->NewCapture.localpath = path; + + if(!m_Local) + msg->NewCapture.localpath = L""; + + uint32_t thumblen = 0; + ser->Serialise("", thumblen); + + create_array_uninit(msg->NewCapture.thumbnail, thumblen); + + size_t l = 0; + byte *buf = &msg->NewCapture.thumbnail[0]; + ser->SerialiseBuffer("", buf, l); + + RDCLOG("Got a new capture: %d (time %llu) %d byte thumbnail", msg->NewCapture.ID, msg->NewCapture.timestamp, thumblen); + + SAFE_DELETE(ser); + + return; + } + else if(type == ePacket_RegisterAPI) + { + msg->Type = eRemoteMsg_RegisterAPI; + + ser->Serialise("", m_API); + msg->RegisterAPI.APIName = m_API; + + RDCLOG("Used API: %ls", m_API.c_str()); + + SAFE_DELETE(ser); + + return; + } + } + + SAFE_DELETE(ser); + + msg->Type = eRemoteMsg_Noop; + } + + private: + Network::Socket *m_Socket; + bool m_Local; + wstring m_Target, m_API, m_BusyClient; + + map m_CaptureCopies; + + void GetPacket(PacketType &type, Serialiser *&ser) + { + if(!RecvPacket(m_Socket, type, &ser)) + SAFE_DELETE(m_Socket); + } +}; + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_Shutdown(RemoteAccess *access) +{ access->Shutdown(); } + +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RemoteAccess_GetTarget(RemoteAccess *access) +{ return access->GetTarget(); } +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RemoteAccess_GetAPI(RemoteAccess *access) +{ return access->GetAPI(); } +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RemoteAccess_GetBusyClient(RemoteAccess *access) +{ return access->GetBusyClient(); } + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_TriggerCapture(RemoteAccess *access) +{ access->TriggerCapture(); } +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_QueueCapture(RemoteAccess *access, uint32_t frameNumber) +{ access->QueueCapture(frameNumber); } +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_CopyCapture(RemoteAccess *access, uint32_t remoteID, const wchar_t *localpath) +{ access->CopyCapture(remoteID, localpath); } + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_ReceiveMessage(RemoteAccess *access, RemoteMessage *msg) +{ access->ReceiveMessage(msg); } + +extern "C" RENDERDOC_API +RemoteAccess * RENDERDOC_CC RENDERDOC_CreateRemoteAccessConnection(const wchar_t *host, uint32_t ident, const wchar_t *clientName, bool forceConnection) +{ + wstring s = L"localhost"; + if(host != NULL && host[0] != L'\0') + s = host; + + bool localhost = (s == L"localhost"); + + Network::Socket *sock = Network::CreateClientSocket(s.c_str(), ident&0xffff, 3000); + + if(sock == NULL) + return NULL; + + RemoteAccess *remote = new RemoteAccess(sock, clientName, forceConnection, localhost); + + if(remote->Connected()) + return remote; + + delete remote; + return NULL; +} diff --git a/renderdoc/core/remote_replay.cpp b/renderdoc/core/remote_replay.cpp new file mode 100644 index 0000000000..918ee83906 --- /dev/null +++ b/renderdoc/core/remote_replay.cpp @@ -0,0 +1,439 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "replay/renderdoc.h" +#include "replay/replay_renderer.h" +#include "core/core.h" +#include "os/os_specific.h" +#include "serialise/serialiser.h" +#include "socket_helpers.h" +#include "replay_proxy.h" + +#include +using std::pair; + +enum PacketType +{ + ePacket_Noop, + ePacket_RemoteDriverList, + ePacket_CopyCapture, + ePacket_LogOpenProgress, + ePacket_LogReady, +}; + +struct ProgressLoopData +{ + Network::Socket *sock; + float progress; + bool killsignal; +}; + +static void ProgressTicker(void *d) +{ + ProgressLoopData *data = (ProgressLoopData *)d; + + Serialiser ser(L"", Serialiser::WRITING, false); + + while(!data->killsignal) + { + ser.Rewind(); + ser.Serialise("", data->progress); + + if(!SendPacket(data->sock, ePacket_LogOpenProgress, ser)) + { + SAFE_DELETE(data->sock); + break; + } + Threading::Sleep(100); + } +} + +void RenderDoc::BecomeReplayHost(volatile bool &killReplay) +{ + Network::Socket *sock = Network::CreateServerSocket("0.0.0.0", RenderDoc_ReplayNetworkPort, 1); + + if(sock == NULL) + return; + + Serialiser ser(L"", Serialiser::WRITING, false); + + bool newlyReady = true; + + while(!killReplay) + { + if(newlyReady) + { + RDCLOG("Replay host ready for requests."); + newlyReady = false; + } + + Network::Socket *client = sock->AcceptClient(false); + + if(client == NULL) + { + if(!sock->Connected()) + { + RDCERR("Error in accept - shutting down server"); + + SAFE_DELETE(sock); + return; + } + + Threading::Sleep(5); + + continue; + } + + newlyReady = true; + + RDCLOG("Connection received."); + + map drivers = RenderDoc::Inst().GetRemoteDrivers(); + + size_t count = drivers.size(); + ser.Serialise("", count); + + for(auto it=drivers.begin(); it != drivers.end(); ++it) + { + RDCDriver driver = it->first; + ser.Serialise("", driver); + ser.Serialise("", (*it).second); + } + + if(!SendPacket(client, ePacket_RemoteDriverList, ser)) + { + RDCERR("Network error sending supported driver list"); + SAFE_DELETE(client); + continue; + } + + Threading::Sleep(4); + + // don't care about the result, just want to check that the socket hasn't been gracefully shut down + client->IsRecvDataWaiting(); + if(!client->Connected()) + { + RDCLOG("Connection closed after sending remote driver list"); + SAFE_DELETE(client); + continue; + } + + wstring cap_file; + wstring dummy, dummy2; + FileIO::GetDefaultFiles(L"remotecopy", cap_file, dummy, dummy2); + + Serialiser *ser = NULL; + + if(!RecvChunkedFile(client, ePacket_CopyCapture, cap_file.c_str(), ser, NULL)) + { + FileIO::UnlinkFileW(cap_file.c_str()); + + RDCERR("Network error receiving file"); + + SAFE_DELETE(ser); + SAFE_DELETE(client); + continue; + } + + RDCLOG("File received."); + + SAFE_DELETE(ser); + + RDCDriver driverType = RDC_Unknown; + wstring driverName = L""; + RenderDoc::Inst().FillInitParams(cap_file.c_str(), driverType, driverName, NULL); + + if(RenderDoc::Inst().HasRemoteDriver(driverType)) + { + ProgressLoopData data; + + data.sock = client; + data.killsignal = false; + data.progress = 0.0f; + + RenderDoc::Inst().SetProgressPtr(&data.progress); + + Threading::ThreadHandle ticker = Threading::CreateThread(ProgressTicker, &data); + + IRemoteDriver *driver = NULL; + auto status = RenderDoc::Inst().CreateRemoteDriver(driverType, cap_file.c_str(), &driver); + + if(status != eReplayCreate_Success || driver == NULL) + { + RDCERR("Failed to create remote driver for driver type %d name %ls", driverType, driverName.c_str()); + SAFE_DELETE(ser); + SAFE_DELETE(client); + continue; + } + + driver->ReadLogInitialisation(); + + RenderDoc::Inst().SetProgressPtr(NULL); + + data.killsignal = true; + Threading::JoinThread(ticker); + Threading::CloseThread(ticker); + + FileIO::UnlinkFileW(cap_file.c_str()); + + SendPacket(client, ePacket_LogReady); + + ProxySerialiser *proxy = new ProxySerialiser(client, driver); + + while(client) + { + if(!proxy->Tick() || killReplay) + { + SAFE_DELETE(client); + } + } + + driver->Shutdown(); + + RDCLOG("Closing replay connection"); + + SAFE_DELETE(proxy); + SAFE_DELETE(client); + } + else + { + RDCERR("File needs driver for %ls which isn't supported!", driverName.c_str()); + + FileIO::UnlinkFileW(cap_file.c_str()); + } + + SAFE_DELETE(client); + } +} + +struct RemoteRenderer +{ + public: + RemoteRenderer(Network::Socket *sock) + : m_Socket(sock) + { + map m = RenderDoc::Inst().GetReplayDrivers(); + + m_Proxies.reserve(m.size()); + for(auto it=m.begin(); it != m.end(); ++it) m_Proxies.push_back(*it); + + { + PacketType type; + Serialiser *ser = NULL; + GetPacket(type, &ser); + + m.clear(); + + if(ser) + { + size_t count = 0; + ser->Serialise("", count); + + for(size_t i=0; i < count; i++) + { + RDCDriver driver = RDC_Unknown; + wstring name = L""; + ser->Serialise("", driver); + ser->Serialise("", name); + + m[driver] = name; + } + + delete ser; + } + } + + m_RemoteDrivers.reserve(m.size()); + for(auto it=m.begin(); it != m.end(); ++it) m_RemoteDrivers.push_back(*it); + + m_ProxyDriver = NULL; + m_ProxySerialiser = NULL; + } + ~RemoteRenderer() + { + SAFE_DELETE(m_ProxySerialiser); + SAFE_DELETE(m_Socket); + } + + void Shutdown() + { + delete this; + } + + bool Connected() { return m_Socket != NULL && m_Socket->Connected(); } + + bool LocalProxies(rdctype::array *out) + { + if(out == NULL) return false; + + create_array_uninit(*out, m_Proxies.size()); + + size_t i=0; + for(auto it=m_Proxies.begin(); it != m_Proxies.end(); ++it, ++i) + out->elems[i] = it->second; + + return true; + } + + bool RemoteSupportedReplays(rdctype::array *out) + { + if(out == NULL) return false; + + create_array_uninit(*out, m_RemoteDrivers.size()); + + size_t i=0; + for(auto it=m_RemoteDrivers.begin(); it != m_RemoteDrivers.end(); ++it, ++i) + out->elems[i] = it->second; + + return true; + } + + ReplayCreateStatus CreateProxyRenderer(uint32_t proxyid, const wchar_t *logfile, float *progress, ReplayRenderer **rend) + { + if(rend == NULL) return eReplayCreate_InternalError; + + if(proxyid >= m_Proxies.size()) + { + RDCERR("Invalid proxy driver id %d specified for remote renderer", proxyid); + return eReplayCreate_InternalError; + } + + float dummy = 0.0f; + if(progress == NULL) + progress = &dummy; + + RDCDriver proxydriver = m_Proxies[proxyid].first; + + Serialiser ser(L"", Serialiser::WRITING, false); + + if(!SendChunkedFile(m_Socket, ePacket_CopyCapture, logfile, ser, progress)) + { + SAFE_DELETE(m_Socket); + return eReplayCreate_NetworkIOFailed; + } + + RDCLOG("Sent file to replay host. Loading..."); + + PacketType type = ePacket_Noop; + while(m_Socket) + { + Serialiser *ser; + GetPacket(type, &ser); + + if(!m_Socket || type != ePacket_LogOpenProgress) break; + + ser->Serialise("", *progress); + + RDCLOG("% 3.0f%%...", (*progress)*100.0f); + } + + if(!m_Socket || type != ePacket_LogReady) + return eReplayCreate_NetworkIOFailed; + + *progress = 1.0f; + + RDCLOG("Log ready on replay host"); + + m_ProxyDriver = NULL; + auto status = RenderDoc::Inst().CreateReplayDriver(proxydriver, NULL, &m_ProxyDriver); + + if(status != eReplayCreate_Success || !m_ProxyDriver) + return status; + + ReplayRenderer *ret = new ReplayRenderer(); + + m_ProxySerialiser = new ProxySerialiser(m_Socket, m_ProxyDriver); + status = ret->SetDevice(m_ProxySerialiser); + + if(status != eReplayCreate_Success) + { + SAFE_DELETE(ret); + SAFE_DELETE(m_ProxySerialiser); + return status; + } + + *rend = ret; + + return eReplayCreate_Success; + } + private: + Network::Socket *m_Socket; + + void GetPacket(PacketType &type, Serialiser **ser) + { + vector payload; + + if(!RecvPacket(m_Socket, type, payload)) + { + SAFE_DELETE(m_Socket); + if(ser) *ser = NULL; + return; + } + + if(ser) *ser = new Serialiser(payload.size(), &payload[0], false); + } + + IReplayDriver *m_ProxyDriver; + ProxySerialiser *m_ProxySerialiser; + + vector< pair > m_Proxies; + vector< pair > m_RemoteDrivers; +}; + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteRenderer_Shutdown(RemoteRenderer *remote) +{ remote->Shutdown(); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC RemoteRenderer_LocalProxies(RemoteRenderer *remote, rdctype::array *out) +{ return remote->LocalProxies(out); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC RemoteRenderer_RemoteSupportedReplays(RemoteRenderer *remote, rdctype::array *out) +{ return remote->RemoteSupportedReplays(out); } + +extern "C" RENDERDOC_API ReplayCreateStatus RENDERDOC_CC RemoteRenderer_CreateProxyRenderer(RemoteRenderer *remote, uint32_t proxyid, const wchar_t *logfile, float *progress, ReplayRenderer **rend) +{ return remote->CreateProxyRenderer(proxyid, logfile, progress, rend); } + +extern "C" RENDERDOC_API +ReplayCreateStatus RENDERDOC_CC RENDERDOC_CreateRemoteReplayConnection(const wchar_t *host, RemoteRenderer **rend) +{ + if(rend == NULL) return eReplayCreate_InternalError; + + wstring s = L"localhost"; + if(host != NULL && host[0] != L'\0') + s = host; + + Network::Socket *sock = NULL; + + if(s != L"-") + { + sock = Network::CreateClientSocket(s.c_str(), RenderDoc_ReplayNetworkPort, 3000); + + if(sock == NULL) + return eReplayCreate_NetworkIOFailed; + } + + *rend = new RemoteRenderer(sock); + + return eReplayCreate_Success; +} diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp new file mode 100644 index 0000000000..a025e72599 --- /dev/null +++ b/renderdoc/core/replay_proxy.cpp @@ -0,0 +1,1459 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "replay_proxy.h" +#include "3rdparty/lz4/lz4.h" + +template<> +string ToStrHelper::Get(const SystemAttribute &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(eAttr_None) + TOSTR_CASE_STRINGIZE(eAttr_Position) + TOSTR_CASE_STRINGIZE(eAttr_ClipDistance) + TOSTR_CASE_STRINGIZE(eAttr_CullDistance) + TOSTR_CASE_STRINGIZE(eAttr_RTIndex) + TOSTR_CASE_STRINGIZE(eAttr_ViewportIndex) + TOSTR_CASE_STRINGIZE(eAttr_VertexIndex) + TOSTR_CASE_STRINGIZE(eAttr_PrimitiveIndex) + TOSTR_CASE_STRINGIZE(eAttr_InstanceIndex) + TOSTR_CASE_STRINGIZE(eAttr_DispatchThreadIndex) + TOSTR_CASE_STRINGIZE(eAttr_GroupIndex) + TOSTR_CASE_STRINGIZE(eAttr_GroupFlatIndex) + TOSTR_CASE_STRINGIZE(eAttr_GroupThreadIndex) + TOSTR_CASE_STRINGIZE(eAttr_GSInstanceIndex) + TOSTR_CASE_STRINGIZE(eAttr_OutputControlPointIndex) + TOSTR_CASE_STRINGIZE(eAttr_DomainLocation) + TOSTR_CASE_STRINGIZE(eAttr_IsFrontFace) + TOSTR_CASE_STRINGIZE(eAttr_MSAACoverage) + TOSTR_CASE_STRINGIZE(eAttr_MSAASampleIndex) + TOSTR_CASE_STRINGIZE(eAttr_OuterTessFactor) + TOSTR_CASE_STRINGIZE(eAttr_InsideTessFactor) + TOSTR_CASE_STRINGIZE(eAttr_ColourOutput) + TOSTR_CASE_STRINGIZE(eAttr_DepthOutput) + TOSTR_CASE_STRINGIZE(eAttr_DepthOutputGreaterEqual) + TOSTR_CASE_STRINGIZE(eAttr_DepthOutputLessEqual) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "SystemAttribute<%d>", el); + + return tostrBuf; +} + +template<> +void Serialiser::Serialise(const char *name, ResourceFormat &el) +{ + Serialise("", el.rawType); + Serialise("", el.special); + Serialise("", el.specialFormat); + Serialise("", el.strname); + Serialise("", el.compCount); + Serialise("", el.compByteWidth); + Serialise("", el.compType); + Serialise("", el.srgbCorrected); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::InputAssembler::LayoutInput &el) +{ + Serialise("", el.SemanticName); + Serialise("", el.SemanticIndex); + Serialise("", el.Format); + Serialise("", el.InputSlot); + Serialise("", el.ByteOffset); + Serialise("", el.PerInstance); + Serialise("", el.InstanceDataStepRate); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::InputAssembler &el) +{ + Serialise("", el.Topology); + Serialise("", el.ibuffer.Buffer); + Serialise("", el.ibuffer.Offset); + Serialise("", el.ibuffer.Format); + + Serialise("", el.vbuffers); + Serialise("", el.layouts); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::ShaderStage::ResourceView &el) +{ + Serialise("", el.View); + Serialise("", el.Resource); + Serialise("", el.Type); + Serialise("", el.Format); + + Serialise("", el.Structured); + Serialise("", el.BufferStructCount); + Serialise("", el.ElementOffset); + Serialise("", el.ElementWidth); + Serialise("", el.FirstElement); + Serialise("", el.NumElements); + + Serialise("", el.Flags); + Serialise("", el.HighestMip); + Serialise("", el.NumMipLevels); + Serialise("", el.MipSlice); + Serialise("", el.ArraySize); + Serialise("", el.FirstArraySlice); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::ShaderStage::Sampler &el) +{ + Serialise("", el.Samp); + Serialise("", el.AddressU); + Serialise("", el.AddressV); + Serialise("", el.AddressW); + Serialise<4>("", el.BorderColor); + Serialise("", el.Comparison); + Serialise("", el.Filter); + Serialise("", el.MaxAniso); + Serialise("", el.MaxLOD); + Serialise("", el.MinLOD); + Serialise("", el.MipLODBias); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::ShaderStage &el) +{ + Serialise("", el.Shader); + Serialise("", el.stage); + + if(m_Mode == READING) + el.ShaderDetails = NULL; + + Serialise("", el.SRVs); + Serialise("", el.UAVs); + Serialise("", el.Samplers); + Serialise("", el.ConstantBuffers); + Serialise("", el.ClassInstances); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::Rasterizer &el) +{ + Serialise("", el.m_State); + Serialise("", el.Scissors); + Serialise("", el.Viewports); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::OutputMerger::BlendState::RTBlend &el) +{ + Serialise("", el.m_Blend.Source); + Serialise("", el.m_Blend.Destination); + Serialise("", el.m_Blend.Operation); + + Serialise("", el.m_AlphaBlend.Source); + Serialise("", el.m_AlphaBlend.Destination); + Serialise("", el.m_AlphaBlend.Operation); + + Serialise("", el.LogicOp); + + Serialise("", el.Enabled); + Serialise("", el.LogicEnabled); + Serialise("", el.WriteMask); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState::OutputMerger &el) +{ + { + Serialise("", el.m_State.State); + Serialise("", el.m_State.DepthEnable); + Serialise("", el.m_State.DepthFunc); + Serialise("", el.m_State.DepthWrites); + Serialise("", el.m_State.StencilEnable); + Serialise("", el.m_State.StencilReadMask); + Serialise("", el.m_State.StencilWriteMask); + + Serialise("", el.m_State.m_FrontFace.FailOp); + Serialise("", el.m_State.m_FrontFace.DepthFailOp); + Serialise("", el.m_State.m_FrontFace.PassOp); + Serialise("", el.m_State.m_FrontFace.Func); + + Serialise("", el.m_State.m_BackFace.FailOp); + Serialise("", el.m_State.m_BackFace.DepthFailOp); + Serialise("", el.m_State.m_BackFace.PassOp); + Serialise("", el.m_State.m_BackFace.Func); + + Serialise("", el.m_State.StencilRef); + } + + { + Serialise("", el.m_BlendState.State); + Serialise("", el.m_BlendState.AlphaToCoverage); + Serialise("", el.m_BlendState.IndependentBlend); + Serialise("", el.m_BlendState.Blends); + Serialise<4>("", el.m_BlendState.BlendFactor); + + Serialise("", el.m_BlendState.SampleMask); + } + + Serialise("", el.RenderTargets); + Serialise("", el.UAVStartSlot); + Serialise("", el.UAVs); + Serialise("", el.DepthTarget); + Serialise("", el.DepthReadOnly); + Serialise("", el.StencilReadOnly); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11PipelineState &el) +{ + Serialise("", el.m_IA); + + Serialise("", el.m_VS); + Serialise("", el.m_HS); + Serialise("", el.m_DS); + Serialise("", el.m_GS); + Serialise("", el.m_PS); + Serialise("", el.m_CS); + + Serialise("", el.m_SO.Outputs); + + Serialise("", el.m_RS); + Serialise("", el.m_OM); +} + +template<> +void Serialiser::Serialise(const char *name, GLPipelineState::ShaderStage &el) +{ + Serialise("", el.Shader); + Serialise("", el.stage); + + if(m_Mode == READING) + el.ShaderDetails = NULL; +} + +template<> +void Serialiser::Serialise(const char *name, GLPipelineState &el) +{ + Serialise("", el.m_VS); + Serialise("", el.m_TES); + Serialise("", el.m_TCS); + Serialise("", el.m_GS); + Serialise("", el.m_FS); + Serialise("", el.m_CS); +} + +template<> +void Serialiser::Serialise(const char *name, SigParameter &el) +{ + Serialise("", el.varName); + Serialise("", el.semanticName); + Serialise("", el.semanticIndex); + Serialise("", el.semanticIdxName); + Serialise("", el.needSemanticIndex); + Serialise("", el.regIndex); + Serialise("", el.systemValue); + Serialise("", el.compType); + Serialise("", el.regChannelMask); + Serialise("", el.channelUsedMask); + Serialise("", el.compCount); + Serialise("", el.stream); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderVariableType &el) +{ + Serialise("", el.descriptor.name); + Serialise("", el.descriptor.rows); + Serialise("", el.descriptor.cols); + Serialise("", el.descriptor.elements); + Serialise("", el.members); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderConstant &el) +{ + Serialise("", el.name); + + uint32_t v = el.reg.vec; + uint32_t c = el.reg.comp; + + Serialise("", v); + Serialise("", c); + + if(m_Mode == READING) + { + el.reg.vec = v; + el.reg.comp = c; + } + + Serialise("", el.type); +} + +template<> +void Serialiser::Serialise(const char *name, ConstantBlock &el) +{ + Serialise("", el.name); + Serialise("", el.variables); + Serialise("", el.bufferAddress); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderResource &el) +{ + Serialise("", el.IsSampler); + Serialise("", el.IsTexture); + Serialise("", el.IsSRV); + Serialise("", el.IsUAV); + Serialise("", el.name); + Serialise("", el.variableType); + Serialise("", el.variableAddress); + Serialise("", el.bindPoint); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderReflection &el) +{ + Serialise("", el.DebugInfo.compileFlags); + Serialise("", el.DebugInfo.entryFunc); + Serialise("", el.DebugInfo.files); + + Serialise("", el.Disassembly); + + Serialise("", el.InputSig); + Serialise("", el.OutputSig); + + Serialise("", el.ConstantBlocks); + + Serialise("", el.Resources); + + Serialise("", el.Interfaces); +} + +template<> +void Serialiser::Serialise(const char *name, FetchTexture &el) +{ + Serialise("", el.name); + Serialise("", el.customName); + Serialise("", el.format); + Serialise("", el.dimension); + Serialise("", el.width); + Serialise("", el.height); + Serialise("", el.depth); + Serialise("", el.ID); + Serialise("", el.cubemap); + Serialise("", el.mips); + Serialise("", el.arraysize); + Serialise("", el.numSubresources); + Serialise("", el.creationFlags); + Serialise("", el.msQual); + Serialise("", el.msSamp); +} + +template<> +void Serialiser::Serialise(const char *name, FetchBuffer &el) +{ + Serialise("", el.name); + Serialise("", el.customName); + Serialise("", el.ID); + Serialise("", el.length); + Serialise("", el.structureSize); +} + +template<> +void Serialiser::Serialise(const char *name, APIProperties &el) +{ + Serialise("", el.pipelineType); +} + +template<> +void Serialiser::Serialise(const char *name, DebugMessage &el) +{ + Serialise("", el.category); + Serialise("", el.severity); + Serialise("", el.messageID); + Serialise("", el.description); +} + +template<> +void Serialiser::Serialise(const char *name, FetchAPIEvent &el) +{ + Serialise("", el.eventID); + Serialise("", el.context); + Serialise("", el.callstack); + Serialise("", el.eventDesc); + Serialise("", el.fileOffset); +} + +template<> +void Serialiser::Serialise(const char *name, FetchDrawcall &el) +{ + Serialise("", el.eventID); + Serialise("", el.drawcallID); + + Serialise("", el.name); + + Serialise("", el.flags); + + Serialise("", el.numIndices); + Serialise("", el.numInstances); + Serialise("", el.indexOffset); + Serialise("", el.vertexOffset); + Serialise("", el.instanceOffset); + + Serialise("", el.context); + + Serialise("", el.duration); + + if(m_Mode == READING) + { + el.parent = el.previous = el.next = 0; + } + + Serialise<8>("", el.outputs); + Serialise("", el.depthOut); + + Serialise("", el.events); + Serialise("", el.children); + Serialise("", el.debugMessages); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameRecord &el) +{ + Serialise("", el.frameInfo); + Serialise("", el.drawcallList); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderVariable &el) +{ + Serialise("", el.rows); + Serialise("", el.columns); + Serialise("", el.name); + Serialise("", el.type); + + Serialise<16>("", el.value.uv); + + Serialise("", el.members); +} + +template<> +void Serialiser::Serialise(const char *name, PostVSMeshData &el) +{ + Serialise("", el.numVerts); + Serialise("", el.topo); + Serialise("", el.buf); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderDebugState &el) +{ + Serialise("", el.registers); + Serialise("", el.outputs); + Serialise("", el.nextInstruction); +} + +template<> +void Serialiser::Serialise(const char *name, ShaderDebugTrace &el) +{ + vector< vector > cbuffers; + + Serialise("", el.inputs); + + int32_t numcbuffers = el.cbuffers.count; + Serialise("", numcbuffers); + + if(m_Mode == READING) create_array_uninit(el.cbuffers, numcbuffers); + + for(int32_t i=0; i < numcbuffers; i++) + Serialise("", el.cbuffers[i]); + + Serialise("", el.states); +} + +// don't need string representation of these enums +template<> +string ToStrHelper::Get(const SpecialFormat &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const FormatComponentType &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const PrimitiveTopology &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const ShaderStageType &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const DebugMessageCategory &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const DebugMessageSeverity &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const VarType &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const MeshDataStage &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const TextureDisplayOverlay &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const APIPipelineStateType &el) { return "<...>"; } + +// these structures we can just serialise as a blob, since they're POD. +template<> +string ToStrHelper::Get(const D3D11PipelineState::InputAssembler::VertexBuffer &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const D3D11PipelineState::Rasterizer::RasterizerState &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const D3D11PipelineState::ShaderStage::CBuffer &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const D3D11PipelineState::Rasterizer::Scissor &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const D3D11PipelineState::Rasterizer::Viewport &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const D3D11PipelineState::Streamout::Output &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const EventUsage &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const FetchFrameInfo &el) { return "<...>"; } +template<> +string ToStrHelper::Get(const ReplayLogType &el) { return "<...>"; } + +ProxySerialiser::~ProxySerialiser() +{ + SAFE_DELETE(m_FromReplaySerialiser); + SAFE_DELETE(m_ToReplaySerialiser); + + for(auto it=m_ShaderReflectionCache.begin(); it != m_ShaderReflectionCache.end(); ++it) + delete it->second; +} + +bool ProxySerialiser::SendReplayCommand(CommandPacketType type) +{ + if(!SendPacket(m_Socket, type, *m_ToReplaySerialiser)) + return false; + + m_ToReplaySerialiser->Rewind(); + + SAFE_DELETE(m_FromReplaySerialiser); + + if(!RecvPacket(m_Socket, type, &m_FromReplaySerialiser)) + return false; + + return true; +} + +void ProxySerialiser::EnsureCached(ResourceId texid, uint32_t arrayIdx, uint32_t mip) +{ + TextureCacheEntry entry = { texid, arrayIdx, mip }; + + if(m_LocalTextures.find(texid) != m_LocalTextures.end()) + return; + + if(m_TextureProxyCache.find(entry) == m_TextureProxyCache.end()) + { + if(m_ProxyTextureIds.find(texid) == m_ProxyTextureIds.end()) + { + FetchTexture tex = GetTexture(texid); + m_ProxyTextureIds[texid] = m_Proxy->CreateProxyTexture(tex); + } + + ResourceId proxyid = m_ProxyTextureIds[texid]; + + size_t size; + byte *data = GetTextureData(texid, arrayIdx, mip, size); + + if(data) + m_Proxy->SetProxyTextureData(proxyid, arrayIdx, mip, data, size); + + delete[] data; + + m_TextureProxyCache.insert(entry); + } +} + +bool ProxySerialiser::Tick() +{ + if(!m_ReplayHost) return true; + + if(!m_Socket) return false; + + CommandPacketType type; + + if(!RecvPacket(m_Socket, type, &m_ToReplaySerialiser)) + return false; + + m_FromReplaySerialiser->Rewind(); + + switch(type) + { + case eCommand_SetCtxFilter: + SetContextFilter(ResourceId(), 0, 0); + break; + case eCommand_ReplayLog: + ReplayLog(0, 0, 0, (ReplayLogType)0); + break; + case eCommand_GetAPIProperties: + GetAPIProperties(); + break; + case eCommand_GetTextures: + GetTextures(); + break; + case eCommand_GetTexture: + GetTexture(ResourceId()); + break; + case eCommand_GetBuffers: + GetTextures(); + break; + case eCommand_GetBuffer: + GetTexture(ResourceId()); + break; + case eCommand_GetShader: + GetShader(ResourceId()); + break; + case eCommand_SavePipelineState: + SavePipelineState(); + break; + case eCommand_GetUsage: + GetUsage(ResourceId()); + break; + case eCommand_GetLiveID: + GetLiveID(ResourceId()); + break; + case eCommand_GetFrameRecord: + GetFrameRecord(); + break; + case eCommand_HasResolver: + HasCallstacks(); + break; + case eCommand_InitStackResolver: + InitCallstackResolver(); + break; + case eCommand_HasStackResolver: + GetCallstackResolver(); + break; + case eCommand_GetAddressDetails: + GetAddr(0); + break; + case eCommand_FreeResource: + FreeTargetResource(ResourceId()); + break; + case eCommand_TimeDrawcalls: + { + rdctype::array l; + TimeDrawcalls(l); + break; + } + case eCommand_FillCBufferVariables: + { + vector vars; + vector data; + FillCBufferVariables(ResourceId(), 0, vars, data); + break; + } + case eCommand_GetBufferData: + GetBufferData(ResourceId(), 0, 0); + break; + case eCommand_GetTextureData: + { + size_t dummy; + GetTextureData(ResourceId(), 0, 0, dummy); + break; + } + case eCommand_InitPostVS: + InitPostVSBuffers(0, 0); + break; + case eCommand_GetPostVS: + GetPostVSBuffers(0, 0, eMeshDataStage_Unknown); + break; + case eCommand_BuildTargetShader: + BuildTargetShader("", "", 0, eShaderStage_Vertex, NULL, NULL); + break; + case eCommand_ReplaceResource: + ReplaceResource(ResourceId(), ResourceId()); + break; + case eCommand_RemoveReplacement: + RemoveReplacement(ResourceId()); + break; + case eCommand_RenderOverlay: + RenderOverlay(ResourceId(), eTexOverlay_None, 0, 0); + break; + case eCommand_DebugVertex: + DebugVertex(0, 0, 0, 0, 0, 0, 0); + break; + case eCommand_DebugPixel: + DebugPixel(0, 0, 0, 0); + break; + case eCommand_DebugThread: + { + uint32_t dummy1[3] = {0}; + uint32_t dummy2[3] = {0}; + DebugThread(0, 0, dummy1, dummy2); + break; + } + default: + RDCERR("Unexpected command"); + break; + } + + SAFE_DELETE(m_ToReplaySerialiser); + + if(!SendPacket(m_Socket, type, *m_FromReplaySerialiser)) + return false; + + return true; +} + +bool ProxySerialiser::IsRenderOutput(ResourceId id) +{ + for(int32_t i=0; i < m_D3D11PipelineState.m_OM.RenderTargets.count; i++) + { + if(m_D3D11PipelineState.m_OM.RenderTargets[i].View == id || + m_D3D11PipelineState.m_OM.RenderTargets[i].Resource == id) + return true; + } + + if(m_D3D11PipelineState.m_OM.DepthTarget.View == id || + m_D3D11PipelineState.m_OM.DepthTarget.Resource == id) + return true; + + return false; +} + +APIProperties ProxySerialiser::GetAPIProperties() +{ + APIProperties ret; + RDCEraseEl(ret); + + if(m_ReplayHost) + { + ret = m_Remote->GetAPIProperties(); + } + else + { + if(!SendReplayCommand(eCommand_GetAPIProperties)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + if(!m_ReplayHost) + { + m_APIProperties = ret; + } + + return ret; +} + +vector ProxySerialiser::GetTextures() +{ + vector ret; + + if(m_ReplayHost) + { + ret = m_Remote->GetTextures(); + } + else + { + if(!SendReplayCommand(eCommand_GetTextures)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +FetchTexture ProxySerialiser::GetTexture(ResourceId id) +{ + FetchTexture ret; + + m_ToReplaySerialiser->Serialise("", id); + + if(m_ReplayHost) + { + ret = m_Remote->GetTexture(id); + } + else + { + if(!SendReplayCommand(eCommand_GetTexture)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +vector ProxySerialiser::GetBuffers() +{ + vector ret; + + if(m_ReplayHost) + { + ret = m_Remote->GetBuffers(); + } + else + { + if(!SendReplayCommand(eCommand_GetBuffers)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +FetchBuffer ProxySerialiser::GetBuffer(ResourceId id) +{ + FetchBuffer ret; + + m_ToReplaySerialiser->Serialise("", id); + + if(m_ReplayHost) + { + ret = m_Remote->GetBuffer(id); + } + else + { + if(!SendReplayCommand(eCommand_GetBuffer)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + + +void ProxySerialiser::SavePipelineState() +{ + if(m_ReplayHost) + { + m_Remote->SavePipelineState(); + m_D3D11PipelineState = m_Remote->GetD3D11PipelineState(); + m_GLPipelineState = m_Remote->GetGLPipelineState(); + } + else + { + if(!SendReplayCommand(eCommand_SavePipelineState)) + return; + + m_D3D11PipelineState = D3D11PipelineState(); + m_GLPipelineState = GLPipelineState(); + } + + m_FromReplaySerialiser->Serialise("", m_D3D11PipelineState); + m_FromReplaySerialiser->Serialise("", m_GLPipelineState); +} + +void ProxySerialiser::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ + m_ToReplaySerialiser->Serialise("", id); + m_ToReplaySerialiser->Serialise("", firstDefEv); + m_ToReplaySerialiser->Serialise("", lastDefEv); + + if(m_ReplayHost) + { + m_Remote->SetContextFilter(id, firstDefEv, lastDefEv); + } + else + { + if(!SendReplayCommand(eCommand_SetCtxFilter)) + return; + } +} + +void ProxySerialiser::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType) +{ + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", startEventID); + m_ToReplaySerialiser->Serialise("", endEventID); + m_ToReplaySerialiser->Serialise("", replayType); + + if(m_ReplayHost) + { + m_Remote->ReplayLog(frameID, startEventID, endEventID, replayType); + } + else + { + if(!SendReplayCommand(eCommand_ReplayLog)) + return; + + m_TextureProxyCache.clear(); + } +} + +vector ProxySerialiser::GetUsage(ResourceId id) +{ + vector ret; + + m_ToReplaySerialiser->Serialise("", id); + + if(m_ReplayHost) + { + ret = m_Remote->GetUsage(id); + } + else + { + if(!SendReplayCommand(eCommand_GetUsage)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +vector ProxySerialiser::GetFrameRecord() +{ + vector ret; + + if(m_ReplayHost) + { + ret = m_Remote->GetFrameRecord(); + } + else + { + if(!SendReplayCommand(eCommand_GetFrameRecord)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +bool ProxySerialiser::HasCallstacks() +{ + bool ret = false; + + RDCASSERT(m_ReplayHost || m_ToReplaySerialiser->GetSize() == 0); + + if(m_ReplayHost) + { + ret = m_Remote->HasCallstacks(); + } + else + { + if(!SendReplayCommand(eCommand_HasResolver)) + return ret; + } + + RDCASSERT(!m_ReplayHost || m_FromReplaySerialiser->GetSize() == 0); + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +ResourceId ProxySerialiser::GetLiveID(ResourceId id) +{ + if(!m_ReplayHost && m_LiveIDs.find(id) != m_LiveIDs.end()) + return m_LiveIDs[id]; + + if(!m_ReplayHost && m_LocalTextures.find(id) != m_LocalTextures.end()) + return id; + + ResourceId ret; + + RDCASSERT(m_ReplayHost || m_ToReplaySerialiser->GetSize() == 0); + + m_ToReplaySerialiser->Serialise("", id); + + if(m_ReplayHost) + { + ret = m_Remote->GetLiveID(id); + } + else + { + if(!SendReplayCommand(eCommand_GetLiveID)) + return ret; + } + + RDCASSERT(!m_ReplayHost || m_FromReplaySerialiser->GetSize() == 0); + + m_FromReplaySerialiser->Serialise("", ret); + + if(!m_ReplayHost) + m_LiveIDs[id] = ret; + + return ret; +} + +void ProxySerialiser::CopyDrawcallTimes(rdctype::array &src, rdctype::array &dst) +{ + RDCASSERT(src.count == dst.count); + + if(src.count == 0 || dst.count == 0) + return; + + for(int32_t i=0; i < dst.count && i < src.count; i++) + { + CopyDrawcallTimes(src[i].children, dst[i].children); + dst[i].duration = src[i].duration; + } +} + +void ProxySerialiser::TimeDrawcalls(rdctype::array &arr) +{ + m_ToReplaySerialiser->Serialise("", arr); + + if(m_ReplayHost) + { + m_Remote->TimeDrawcalls(arr); + + m_FromReplaySerialiser->Serialise("", arr); + } + else + { + if(!SendReplayCommand(eCommand_TimeDrawcalls)) + return; + + // need to serialise into a dummy list then copy the times as TimeDrawcalls + // expects to modify only the times of the drawcalls in place, whereas + // serialise would completely trash the list! + rdctype::array dummy; + + m_FromReplaySerialiser->Serialise("", dummy); + + CopyDrawcallTimes(dummy, arr); + } + + return; +} + +void ProxySerialiser::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) +{ + m_ToReplaySerialiser->Serialise("", shader); + m_ToReplaySerialiser->Serialise("", cbufSlot); + m_ToReplaySerialiser->Serialise("", outvars); + m_ToReplaySerialiser->Serialise("", (vector &)data); + + if(m_ReplayHost) + { + m_Remote->FillCBufferVariables(shader, cbufSlot, outvars, data); + } + else + { + if(!SendReplayCommand(eCommand_FillCBufferVariables)) + return; + } + + m_FromReplaySerialiser->Serialise("", shader); + m_FromReplaySerialiser->Serialise("", cbufSlot); + m_FromReplaySerialiser->Serialise("", outvars); + + return; +} + +vector ProxySerialiser::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) +{ + vector ret; + + m_ToReplaySerialiser->Serialise("", buff); + m_ToReplaySerialiser->Serialise("", offset); + m_ToReplaySerialiser->Serialise("", len); + + if(m_ReplayHost) + { + ret = m_Remote->GetBufferData(buff, offset, len); + + size_t sz = ret.size(); + m_FromReplaySerialiser->Serialise("", sz); + m_FromReplaySerialiser->RawWriteBytes(&ret[0], sz); + } + else + { + if(!SendReplayCommand(eCommand_GetBufferData)) + return ret; + + size_t sz = 0; + m_FromReplaySerialiser->Serialise("", sz); + ret.resize(sz); + memcpy(&ret[0], m_FromReplaySerialiser->RawReadBytes(sz), sz); + } + + return ret; +} + +byte *ProxySerialiser::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize) +{ + m_ToReplaySerialiser->Serialise("", tex); + m_ToReplaySerialiser->Serialise("", arrayIdx); + m_ToReplaySerialiser->Serialise("", mip); + + if(m_ReplayHost) + { + byte *data = m_Remote->GetTextureData(tex, arrayIdx, mip, dataSize); + + byte *compressed = new byte[dataSize+64]; + + size_t compressedSize = (size_t)LZ4_compress((const char *)data, (char *)compressed, (int)dataSize); + + m_FromReplaySerialiser->Serialise("", dataSize); + m_FromReplaySerialiser->Serialise("", compressedSize); + m_FromReplaySerialiser->RawWriteBytes(compressed, compressedSize); + + delete[] data; + delete[] compressed; + } + else + { + if(!SendReplayCommand(eCommand_GetTextureData)) + return NULL; + + size_t compressedSize; + + m_FromReplaySerialiser->Serialise("", dataSize); + m_FromReplaySerialiser->Serialise("", compressedSize); + + byte *ret = new byte[dataSize+64]; + + byte *compressed = (byte *)m_FromReplaySerialiser->RawReadBytes(compressedSize); + + size_t uncompSize = (size_t)LZ4_decompress_fast((const char *)compressed, (char *)ret, (int)dataSize); + + return ret; + } + + return NULL; +} + +void ProxySerialiser::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) +{ + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", eventID); + + if(m_ReplayHost) + { + m_Remote->InitPostVSBuffers(frameID, eventID); + } + else + { + if(!SendReplayCommand(eCommand_InitPostVS)) + return; + } +} + +PostVSMeshData ProxySerialiser::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +{ + PostVSMeshData ret; + + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", eventID); + m_ToReplaySerialiser->Serialise("", stage); + + if(m_ReplayHost) + { + ret = m_Remote->GetPostVSBuffers(frameID, eventID, stage); + } + else + { + if(!SendReplayCommand(eCommand_GetPostVS)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +ResourceId ProxySerialiser::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID) +{ + ResourceId ret; + + m_ToReplaySerialiser->Serialise("", texid); + m_ToReplaySerialiser->Serialise("", overlay); + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", eventID); + + if(m_ReplayHost) + { + ret = m_Remote->RenderOverlay(texid, overlay, frameID, eventID); + } + else + { + if(!SendReplayCommand(eCommand_RenderOverlay)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +ShaderReflection *ProxySerialiser::GetShader(ResourceId id) +{ + if(m_ReplayHost) + { + m_ToReplaySerialiser->Serialise("", id); + + ShaderReflection *refl = m_Remote->GetShader(id); + + bool hasrefl = (refl != NULL); + m_FromReplaySerialiser->Serialise("", hasrefl); + + if(hasrefl) + m_FromReplaySerialiser->Serialise("", *refl); + + return NULL; + } + + if(m_ShaderReflectionCache.find(id) == m_ShaderReflectionCache.end()) + { + m_ToReplaySerialiser->Serialise("", id); + + if(!SendReplayCommand(eCommand_GetShader)) + return NULL; + + bool hasrefl = false; + m_FromReplaySerialiser->Serialise("", hasrefl); + + if(hasrefl) + { + m_ShaderReflectionCache[id] = new ShaderReflection(); + + m_FromReplaySerialiser->Serialise("", *m_ShaderReflectionCache[id]); + } + else + { + m_ShaderReflectionCache[id] = NULL; + } + } + + return m_ShaderReflectionCache[id]; +} + +void ProxySerialiser::FreeTargetResource(ResourceId id) +{ + m_ToReplaySerialiser->Serialise("", id); + + if(m_ReplayHost) + { + m_Remote->FreeTargetResource(id); + } + else + { + if(!SendReplayCommand(eCommand_FreeResource)) + return; + } +} + +void ProxySerialiser::InitCallstackResolver() +{ + if(m_ReplayHost) + { + m_Remote->InitCallstackResolver(); + } + else + { + if(!SendReplayCommand(eCommand_InitStackResolver)) + return; + } +} + +Callstack::StackResolver *ProxySerialiser::GetCallstackResolver() +{ + if(m_RemoteHasResolver) return this; + + bool remoteHasResolver = false; + + if(m_ReplayHost) + { + remoteHasResolver = m_Remote->GetCallstackResolver() != NULL; + } + else + { + if(!SendReplayCommand(eCommand_HasStackResolver)) + return NULL; + } + + m_FromReplaySerialiser->Serialise("", remoteHasResolver); + + if(remoteHasResolver) + { + if(!m_ReplayHost) + m_RemoteHasResolver = true; + + return this; + } + + return NULL; +} + +Callstack::AddressDetails ProxySerialiser::GetAddr(uint64_t addr) +{ + Callstack::AddressDetails ret; + + if(m_ReplayHost) + { + Callstack::StackResolver *resolv = m_Remote->GetCallstackResolver(); + if(resolv) ret = resolv->GetAddr(addr); + } + else + { + if(!SendReplayCommand(eCommand_HasStackResolver)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret.filename); + m_FromReplaySerialiser->Serialise("", ret.function); + m_FromReplaySerialiser->Serialise("", ret.line); + + return ret; +} + +void ProxySerialiser::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) +{ + uint32_t flags = compileFlags; + m_ToReplaySerialiser->Serialise("", source); + m_ToReplaySerialiser->Serialise("", entry); + m_ToReplaySerialiser->Serialise("", flags); + m_ToReplaySerialiser->Serialise("", type); + + ResourceId outId; + string outErrs; + + if(m_ReplayHost) + { + m_Remote->BuildTargetShader(source, entry, flags, type, &outId, &outErrs); + } + else + { + if(!SendReplayCommand(eCommand_BuildTargetShader)) + return; + } + + m_FromReplaySerialiser->Serialise("", outId); + m_FromReplaySerialiser->Serialise("", outErrs); + + if(!m_ReplayHost) + { + if(id) *id = outId; + if(errors) *errors = outErrs; + } +} + +void ProxySerialiser::ReplaceResource(ResourceId from, ResourceId to) +{ + m_ToReplaySerialiser->Serialise("", from); + m_ToReplaySerialiser->Serialise("", to); + + if(m_ReplayHost) + { + m_Remote->ReplaceResource(from, to); + } + else + { + if(!SendReplayCommand(eCommand_ReplaceResource)) + return; + } +} + +void ProxySerialiser::RemoveReplacement(ResourceId id) +{ + m_ToReplaySerialiser->Serialise("", id); + + if(m_ReplayHost) + { + m_Remote->RemoveReplacement(id); + } + else + { + if(!SendReplayCommand(eCommand_RemoveReplacement)) + return; + } +} + +ShaderDebugTrace ProxySerialiser::DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) +{ + ShaderDebugTrace ret; + + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", eventID); + m_ToReplaySerialiser->Serialise("", vertid); + m_ToReplaySerialiser->Serialise("", instid); + m_ToReplaySerialiser->Serialise("", idx); + m_ToReplaySerialiser->Serialise("", instOffset); + m_ToReplaySerialiser->Serialise("", vertOffset); + + if(m_ReplayHost) + { + ret = m_Remote->DebugVertex(frameID, eventID, vertid, instid, idx, instOffset, vertOffset); + } + else + { + if(!SendReplayCommand(eCommand_DebugVertex)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +ShaderDebugTrace ProxySerialiser::DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) +{ + ShaderDebugTrace ret; + + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", eventID); + m_ToReplaySerialiser->Serialise("", x); + m_ToReplaySerialiser->Serialise("", y); + + if(m_ReplayHost) + { + ret = m_Remote->DebugPixel(frameID, eventID, x, y); + } + else + { + if(!SendReplayCommand(eCommand_DebugPixel)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +ShaderDebugTrace ProxySerialiser::DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]) +{ + ShaderDebugTrace ret; + + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", eventID); + m_ToReplaySerialiser->Serialise<3>("", groupid); + m_ToReplaySerialiser->Serialise<3>("", threadid); + + if(m_ReplayHost) + { + ret = m_Remote->DebugThread(frameID, eventID, groupid, threadid); + } + else + { + if(!SendReplayCommand(eCommand_DebugThread)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h new file mode 100644 index 0000000000..fcbdb0d27b --- /dev/null +++ b/renderdoc/core/replay_proxy.h @@ -0,0 +1,372 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "os/os_specific.h" +#include "serialise/serialiser.h" +#include "socket_helpers.h" +#include "replay/replay_driver.h" + +enum CommandPacketType +{ + eCommand_SetCtxFilter, + eCommand_ReplayLog, + + eCommand_GetTextures, + eCommand_GetTexture, + eCommand_GetBuffers, + eCommand_GetBuffer, + eCommand_GetShader, + + eCommand_GetBufferData, + eCommand_GetTextureData, + + eCommand_SavePipelineState, + eCommand_GetUsage, + eCommand_GetLiveID, + eCommand_GetFrameRecord, + + eCommand_FreeResource, + eCommand_HasResolver, + + eCommand_TimeDrawcalls, + eCommand_FillCBufferVariables, + + eCommand_InitPostVS, + eCommand_GetPostVS, + + eCommand_InitStackResolver, + eCommand_HasStackResolver, + eCommand_GetAddressDetails, + + eCommand_BuildTargetShader, + eCommand_ReplaceResource, + eCommand_RemoveReplacement, + + eCommand_DebugVertex, + eCommand_DebugPixel, + eCommand_DebugThread, + + eCommand_RenderOverlay, + + eCommand_GetAPIProperties, +}; + +// This class implements IReplayDriver and StackResolver. On the local machine where the UI +// is, this can then act like a full local replay by farming out over the network to a remote +// replay where necessary to implement some functions, and using a local proxy where necessary. +// +// This class is also used on the remote replay just so we can re-use the serialisation logic +// across the network before and after implementing the IRemoteDriver parts. +class ProxySerialiser : public IReplayDriver, Callstack::StackResolver +{ + public: + ProxySerialiser(Network::Socket *sock, IReplayDriver *proxy) + : m_Socket(sock), m_Proxy(proxy), m_Remote(NULL), m_ReplayHost(false) + { + m_FromReplaySerialiser = NULL; + m_ToReplaySerialiser = new Serialiser(NULL, Serialiser::WRITING, false); + m_RemoteHasResolver = false; + } + + ProxySerialiser(Network::Socket *sock, IRemoteDriver *remote) + : m_Socket(sock), m_Proxy(NULL), m_Remote(remote), m_ReplayHost(true) + { + m_ToReplaySerialiser = NULL; + m_FromReplaySerialiser = new Serialiser(NULL, Serialiser::WRITING, false); + m_RemoteHasResolver = false; + } + + virtual ~ProxySerialiser(); + + bool IsRemoteProxy() { return !m_ReplayHost; } + void Shutdown() { delete this; } + + void ReadLogInitialisation() {} + + uint64_t MakeOutputWindow(void *w, bool depth) + { + if(m_Proxy) + return m_Proxy->MakeOutputWindow(w, depth); + return 0; + } + void DestroyOutputWindow(uint64_t id) + { + if(m_Proxy) + return m_Proxy->DestroyOutputWindow(id); + } + bool CheckResizeOutputWindow(uint64_t id) + { + if(m_Proxy) + return m_Proxy->CheckResizeOutputWindow(id); + return false; + } + void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) + { + if(m_Proxy) + return m_Proxy->GetOutputWindowDimensions(id, w, h); + } + void ClearOutputWindowColour(uint64_t id, float col[4]) + { + if(m_Proxy) + return m_Proxy->ClearOutputWindowColour(id, col); + } + void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil) + { + if(m_Proxy) + return m_Proxy->ClearOutputWindowDepth(id, depth, stencil); + } + void BindOutputWindow(uint64_t id, bool depth) + { + if(m_Proxy) + return m_Proxy->BindOutputWindow(id, depth); + } + bool IsOutputWindowVisible(uint64_t id) + { + if(m_Proxy) + return m_Proxy->IsOutputWindowVisible(id); + return false; + } + void FlipOutputWindow(uint64_t id) + { + if(m_Proxy) + return m_Proxy->FlipOutputWindow(id); + } + + void RenderCheckerboard(Vec3f light, Vec3f dark) + { + if(m_Proxy) + return m_Proxy->RenderCheckerboard(light, dark); + } + + void RenderHighlightBox(float w, float h, float scale) + { + if(m_Proxy) + return m_Proxy->RenderHighlightBox(w, h, scale); + } + + bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval) + { + if(m_Proxy) + { + EnsureCached(texid, sliceFace, mip); + return m_Proxy->GetMinMax(m_ProxyTextureIds[texid], sliceFace, mip, minval, maxval); + } + + return false; + } + + bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram) + { + if(m_Proxy) + { + EnsureCached(texid, sliceFace, mip); + return m_Proxy->GetHistogram(m_ProxyTextureIds[texid], sliceFace, mip, minval, maxval, channels, histogram); + } + + return false; + } + + bool SaveTexture(ResourceId tex, uint32_t saveMip, wstring path) + { + if(m_Proxy) + { + EnsureCached(tex, 0, saveMip); + return m_Proxy->SaveTexture(m_ProxyTextureIds[tex], saveMip, path); + } + + return false; + } + + bool RenderTexture(TextureDisplay cfg) + { + if(m_Proxy) + { + EnsureCached(cfg.texid, cfg.sliceFace, cfg.mip); + cfg.texid = m_ProxyTextureIds[cfg.texid]; + return m_Proxy->RenderTexture(cfg); + } + + return false; + } + + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]) + { + if(m_Proxy) + { + EnsureCached(texture, sliceFace, mip); + m_Proxy->PickPixel(m_ProxyTextureIds[texture], x, y, sliceFace, mip, pixel); + } + } + + void RenderMesh(int frameID, vector eventID, MeshDisplay cfg) + { + if(m_Proxy) + m_Proxy->RenderCheckerboard(Vec3f(0.7f, 0.3f, 0.3f), Vec3f(0.3f, 0.3f, 0.7f)); + } + + void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) + { + if(m_Proxy) + { + m_Proxy->BuildCustomShader(source, entry, compileFlags, type, id, errors); + } + else + { + if(id) *id = ResourceId(); + if(errors) *errors = "Unsupported BuildShader call on proxy without local renderer"; + } + } + + void FreeCustomShader(ResourceId id) + { + if(m_Proxy) + m_Proxy->FreeTargetResource(id); + } + + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) + { + if(m_Proxy) + { + EnsureCached(texid, 0, mip); + texid = m_ProxyTextureIds[texid]; + ResourceId customResourceId = m_Proxy->ApplyCustomShader(shader, texid, mip); + m_LocalTextures.insert(customResourceId); + m_ProxyTextureIds[customResourceId] = customResourceId; + return customResourceId; + } + + return ResourceId(); + } + + bool Tick(); + + vector GetBuffers(); + FetchBuffer GetBuffer(ResourceId id); + + vector GetTextures(); + FetchTexture GetTexture(ResourceId id); + + APIProperties GetAPIProperties(); + + void SavePipelineState(); + D3D11PipelineState GetD3D11PipelineState() { return m_D3D11PipelineState; } + GLPipelineState GetGLPipelineState() { return m_GLPipelineState; } + + void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); + void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); + + vector GetUsage(ResourceId id); + vector GetFrameRecord(); + + bool IsRenderOutput(ResourceId id); + + ResourceId GetLiveID(ResourceId id); + + void TimeDrawcalls(rdctype::array &arr); + + void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data); + + vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize); + + void InitPostVSBuffers(uint32_t frameID, uint32_t eventID); + PostVSMeshData GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + + ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID); + + ShaderReflection *GetShader(ResourceId id); + + bool HasCallstacks(); + void InitCallstackResolver(); + Callstack::StackResolver *GetCallstackResolver(); + // implementing Callstack::StackResolver + Callstack::AddressDetails GetAddr(uint64_t addr); + + void FreeTargetResource(ResourceId id); + + ShaderDebugTrace DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); + ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y); + ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]); + + void BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); + void ReplaceResource(ResourceId from, ResourceId to); + void RemoveReplacement(ResourceId id); + + // will never be used + ResourceId CreateProxyTexture(FetchTexture templateTex) + { + RDCERR("Calling proxy-render functions on a proxy serialiser"); + return ResourceId(); + } + + void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize) + { + RDCERR("Calling proxy-render functions on a proxy serialiser"); + } + + private: + bool SendReplayCommand(CommandPacketType type); + void CopyDrawcallTimes(rdctype::array &src, rdctype::array &dst); + + void EnsureCached(ResourceId texid, uint32_t arrayIdx, uint32_t mip); + + struct TextureCacheEntry + { + ResourceId replayid; + uint32_t arrayIdx; + uint32_t mip; + + bool operator <(const TextureCacheEntry &o) const + { + if(replayid != o.replayid) + return replayid < o.replayid; + if(arrayIdx != o.arrayIdx) + return arrayIdx < o.arrayIdx; + return mip < o.mip; + } + }; + set m_TextureProxyCache; + set m_LocalTextures; + map m_ProxyTextureIds; + + map m_LiveIDs; + + map m_ShaderReflectionCache; + + Network::Socket *m_Socket; + Serialiser *m_FromReplaySerialiser; + Serialiser *m_ToReplaySerialiser; + IReplayDriver *m_Proxy; + IRemoteDriver *m_Remote; + bool m_ReplayHost; + + bool m_RemoteHasResolver; + + APIProperties m_APIProperties; + D3D11PipelineState m_D3D11PipelineState; + GLPipelineState m_GLPipelineState; +}; diff --git a/renderdoc/core/resource_manager.cpp b/renderdoc/core/resource_manager.cpp new file mode 100644 index 0000000000..9b97d1cd62 --- /dev/null +++ b/renderdoc/core/resource_manager.cpp @@ -0,0 +1,86 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "resource_manager.h" + +void ResourceRecord::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType) +{ + ResourceManager::MarkReferenced(m_FrameRefs, id, refType); +} + +void ResourceRecord::AddResourceReferences(ResourceRecordHandler *mgr) +{ + for(auto it=m_FrameRefs.begin(); it != m_FrameRefs.end(); ++it) + { + mgr->MarkResourceFrameReferenced(it->first, it->second); + } +} + +void ResourceRecord::Delete(ResourceRecordHandler *mgr) +{ + RefCount--; + RDCASSERT(RefCount >= 0); + if(RefCount <= 0) + { + for(auto it = Parents.begin(); it != Parents.end(); ++it) + (*it)->Delete(mgr); + + Parents.clear(); + Length = -1; + DataPtr = NULL; + + for(auto it=m_FrameRefs.begin(); it != m_FrameRefs.end(); ++it) + { + if(it->second == eFrameRef_Write || + it->second == eFrameRef_ReadAndWrite || + it->second == eFrameRef_ReadBeforeWrite) + { + // lost a write to this resource, must mark it as gpu dirty. + mgr->MarkPendingDirty(it->first); + } + } + + for(auto it=m_Chunks.begin(); it != m_Chunks.end(); ++it) + SAFE_DELETE(it->second); + m_Chunks.clear(); + + for(int i=0; i < NumSubResources; i++) + { + for(auto it=SubResources[i]->m_Chunks.begin(); it != SubResources[i]->m_Chunks.end(); ++it) + SAFE_DELETE(it->second); + + SAFE_DELETE(SubResources[i]); + } + + SAFE_DELETE_ARRAY(SubResources); + + if(ResID != ResourceId()) + mgr->RemoveResourceRecord(ResID); + + delete this; + } +} + + diff --git a/renderdoc/core/resource_manager.h b/renderdoc/core/resource_manager.h new file mode 100644 index 0000000000..568eca2e0e --- /dev/null +++ b/renderdoc/core/resource_manager.h @@ -0,0 +1,1161 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "core/core.h" + +#include "os/os_specific.h" + +#include "serialise/serialiser.h" +#include "common/threading.h" + +#include +#include +using std::set; +using std::map; + +// in what way (read, write, etc) was a resource referenced in a frame - +// used to determine if initial contents are needed and to what degree +enum FrameRefType +{ + eFrameRef_Unknown, // for the initial start of frame pipeline state - can't be marked as written/read yet until first action. + + // Inputs + eFrameRef_Read, + eFrameRef_Write, + + // States + eFrameRef_ReadOnly, + eFrameRef_ReadAndWrite, + eFrameRef_ReadBeforeWrite, +}; + +class ResourceRecordHandler +{ + public: + virtual void MarkDirtyResource(ResourceId id) = 0; + virtual void MarkPendingDirty(ResourceId id) = 0; + virtual void RemoveResourceRecord(ResourceId id) = 0; + virtual void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType) = 0; +}; + +// This is a generic resource record, that APIs can inherit from and use. +// A resource is an API object that gets tracked on its own, has dependencies on other resources +// and has its own stream of chunks. +// +// This is used to track the necessary resources for a frame, and include only those required +// for the captured frame in its log. It also handles anything resource-specific such as +// shadow CPU copies of data. +struct ResourceRecord +{ + ResourceRecord(ResourceId id, bool lock) + : RefCount(1), ResID(id), UpdateCount(0), + DataInSerialiser(false), DataPtr(NULL), DataOffset(0), + Length(-1), DataWritten(false), SpecialResource(false), + NumSubResources(0), SubResources(NULL) + { + m_ChunkLock = NULL; + + if(lock) + m_ChunkLock = new Threading::CriticalSection(); + } + + ~ResourceRecord() + { + SAFE_DELETE(m_ChunkLock); + } + + void AddParent(ResourceRecord *r) + { + if(Parents.find(r) == Parents.end()) + { + r->AddRef(); + Parents.insert(r); + } + } + + void FreeParents(ResourceRecordHandler *mgr) + { + for(auto it = Parents.begin(); it != Parents.end(); ++it) + (*it)->Delete(mgr); + + Parents.clear(); + } + + void MarkDataUnwritten() + { + DataWritten = false; + } + + void Insert(map &recordlist) + { + bool dataWritten = DataWritten; + + DataWritten = true; + + for(auto it = Parents.begin(); it != Parents.end(); ++it) + { + if(!(*it)->DataWritten) + { + (*it)->Insert(recordlist); + } + } + + if(!dataWritten) + { + recordlist.insert(m_Chunks.begin(), m_Chunks.end()); + + for(int i=0; i < NumSubResources; i++) + SubResources[i]->Insert(recordlist); + } + } + + void AddRef() { RefCount++; } + int GetRefCount() { return RefCount; } + void Delete(ResourceRecordHandler *mgr); + + ResourceId GetResourceID() { return ResID; } + + void AddChunk(Chunk *chunk, int32_t ID = 0) + { + LockChunks(); + if(ID == 0) ID = GetID(); + m_Chunks[ID] = chunk; + UnlockChunks(); + } + + void LockChunks() { if(m_ChunkLock) m_ChunkLock->Lock(); } + void UnlockChunks() { if(m_ChunkLock) m_ChunkLock->Unlock(); } + + bool HasChunks() + { + return !m_Chunks.empty(); + } + + size_t NumChunks() + { + return m_Chunks.size(); + } + + void SwapChunks(ResourceRecord *other) + { + LockChunks(); + other->LockChunks(); + m_Chunks.swap(other->m_Chunks); + m_FrameRefs.swap(other->m_FrameRefs); + other->UnlockChunks(); + UnlockChunks(); + } + + Chunk *GetLastChunk() + { + RDCASSERT(HasChunks()); + return m_Chunks.rbegin()->second; + } + + void PopChunk() + { + m_Chunks.erase(m_Chunks.rbegin()->first); + } + + byte *GetDataPtr() + { + return DataPtr + DataOffset; + } + + void SetDataOffset(uint64_t offs) + { + DataOffset = offs; + } + + void SetDataPtr(byte *ptr) + { + DataPtr = ptr; + + for(int i=0; i < NumSubResources; i++) + SubResources[i]->SetDataPtr(ptr); + } + + void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType); + void AddResourceReferences(ResourceRecordHandler *mgr); + + int UpdateCount; + + bool DataInSerialiser; + int32_t Length; + + bool SpecialResource; // like the swap chain back buffers + + int NumSubResources; + ResourceRecord **SubResources; + +protected: + byte *DataPtr; + uint64_t DataOffset; + bool DataWritten; + + int RefCount; + + ResourceId ResID; + + std::set Parents; + + int32_t GetID() + { + static volatile int32_t globalIDCounter = 10; + + return Atomic::Inc32(&globalIDCounter); + } + + map m_FrameRefs; + + std::map m_Chunks; + Threading::CriticalSection *m_ChunkLock; +}; + +// the resource manager is a utility class that's not required but is likely wanted by any API implementation. +// It keeps track of resource records, which resources are alive and allows you to query for them by ID. It tracks +// which resources are marked as dirty (needing their initial contents fetched before capture). +// +// For APIs that wrap their resources it provides tracking for that. +// +// In the replay application it will also track which 'live' resources are representing which 'original' +// resources from the application when it was captured. +template +class ResourceManager : public ResourceRecordHandler +{ + public: + ResourceManager(); + virtual ~ResourceManager(); + + void Shutdown(); + + /////////////////////////////////////////// + // Capture-side methods + + // while capturing, resource records containing chunk streams and metadata for resources + RecordType *GetResourceRecord(ResourceId id); + bool HasResourceRecord(ResourceId id); + RecordType *AddResourceRecord(ResourceId id); + inline void RemoveResourceRecord(ResourceId id); + + // while capturing or replaying, resources and their live IDs + void AddCurrentResource(ResourceId id, ResourceType res); + bool HasCurrentResource(ResourceId id); + ResourceType GetCurrentResource(ResourceId id); + void ReleaseCurrentResource(ResourceId id); + + void MarkInFrame(bool inFrame) { m_InFrame = inFrame; } + void ReleaseInFrameResources(); + + // insert the chunks for the resources referenced in the frame + void InsertReferencedChunks(Serialiser *ser); + + // mark resource records as unwritten, ready to be written to a new logfile. + void MarkUnwrittenResources(); + + // clear the list of frame-referenced resources - e.g. if you're about to recapture a frame + void ClearReferencedResources(); + + // indicates this resource could have been modified by the GPU, + // so it's now suspect and the data we have on it might well be out of date + // and to be correct its contents should be serialised out at the start + // of the frame. + inline void MarkDirtyResource(ResourceId res); + + // for use when we might be mid-capture, this will get flushed to dirty state before the + // next frame but is safe to use mid-capture + void MarkPendingDirty(ResourceId res); + void FlushPendingDirty(); + + // this can be used when the resource is cleared or similar and it's in a known state + void MarkCleanResource(ResourceId res); + + // returns if the resource has been marked as dirty + bool IsResourceDirty(ResourceId res); + + // call callbacks to prepare initial contents for dirty resources + void PrepareInitialContents(); + + ResourceType GetInitialContents(ResourceId id); + void SetInitialContents(ResourceId id, ResourceType res, uint32_t data); + + // generate chunks for initial contents and insert. + void InsertInitialContentsChunks(Serialiser *chunkSer, Serialiser *fileSer); + + // Serialise out which resources need initial contents, along with whether their + // initial contents are in the serialised stream (e.g. RTs might still want to be + // cleared on frame init). + void Serialise_InitialContentsNeeded(Serialiser *ser); + + + // handle marking a resource referenced for read or write and storing RAW access etc. + static bool MarkReferenced(map &refs, ResourceId id, FrameRefType refType); + + // mark resource referenced somewhere in the main frame-affecting calls. + // That means this resource should be included in the final serialise out + inline void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType); + + // check if this resource was read before being written to - can be used to detect if + // initial states are necessary + bool ReadBeforeWrite(ResourceId id); + + /////////////////////////////////////////// + // Replay-side methods + + // Live resources to replace serialised IDs + void AddLiveResource(ResourceId origid, ResourceType livePtr); + bool HasLiveResource(ResourceId origid); + ResourceType GetLiveResource(ResourceId origid); + void EraseLiveResource(ResourceId origid); + + // when asked for a given id, return the resource for a replacement id + void ReplaceResource(ResourceId from, ResourceId to); + void RemoveReplacement(ResourceId id); + + // fetch original ID for a real ID or vice-versa. + ResourceId GetOriginalID(ResourceId id); + ResourceId GetLiveID(ResourceId id); + + // Serialise in which resources need initial contents and set them up. + void CreateInitialContents(Serialiser *ser); + + // Apply the initial contents for the resources that need them, used at the start of a frame + void ApplyInitialContents(); + + // Resource wrapping, allows for querying and adding/removing of wrapper layers around resources + void AddWrapper(ResourceType wrap, ResourceType real); + bool HasWrapper(ResourceType real); + ResourceType GetWrapper(ResourceType real); + void RemoveWrapper(ResourceType real); + + protected: + // 'interface' to implement by derived classes + virtual bool SerialisableResource(ResourceId id, RecordType *record) = 0; + virtual ResourceId GetID(ResourceType res) = 0; + + virtual bool ResourceTypeRelease(ResourceType res) = 0; + + virtual bool Need_InitialState(ResourceType res) = 0; + virtual bool Need_InitialStateChunk(ResourceType res) = 0; + virtual bool Prepare_InitialState(ResourceType res) = 0; + virtual bool Serialise_InitialState(ResourceType res) = 0; + virtual void Create_InitialState(ResourceId id, ResourceType live, bool hasData) = 0; + virtual void Apply_InitialState(ResourceType live, ResourceType initial, uint32_t count) = 0; + + private: + bool m_InFrame; + + // very coarse lock, protects EVERYTHING. This could certainly be improved and it may be a bottleneck + // for performance. Given that the main use cases are write-rarely read-often the lock should be optimised + // for that as we only want to make sure we're not modifying the objects together, by far the most common + // operation is looking up data. + Threading::CriticalSection m_Lock; + + // easy optimisation win - don't use maps everywhere. It's convenient but not optimal, and profiling will + // likely prove that some or all of these could be a problem + + // used during capture - map from real resource to its wrapper (other way can be done just with an Unwrap) + map m_WrapperMap; + + // used during capture - holds resources referenced in current frame (and how they're referenced) + map m_FrameReferencedResources; + + // used during capture - holds resources marked as dirty, needing initial contents + set m_DirtyResources; + set m_PendingDirtyResources; + + // used during capture or replay - holds initial contents + map m_InitialContents; + map m_InitialCounts; + + // used during capture or replay - map of resources currently alive with their real IDs, used in capture and replay. + map m_CurrentResourceMap; + + // used during replay - maps back and forth from original id to live id and vice-versa + map m_OriginalIDs, m_LiveIDs; + + // used during replay - holds resources allocated and the original id that they represent + // for a) in-frame creations and b) pre-frame creations respectively. + map m_InframeResourceMap, m_LiveResourceMap; + + // used during capture - holds resource records by id. + map m_ResourceRecords; + + // used during replay - holds current resource replacements + map m_Replacements; +}; + +template +ResourceManager::ResourceManager() +{ + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(ResourceManager)); + + m_InFrame = false; +} + +template +void ResourceManager::Shutdown() +{ + while(!m_LiveResourceMap.empty()) + { + auto it = m_LiveResourceMap.begin(); + ResourceTypeRelease(it->second); + if(!m_LiveResourceMap.empty()) + m_LiveResourceMap.erase(m_LiveResourceMap.begin()); + } + + while(!m_InframeResourceMap.empty()) + { + auto it = m_InframeResourceMap.begin(); + ResourceTypeRelease(it->second); + if(!m_InframeResourceMap.empty()) + m_InframeResourceMap.erase(m_InframeResourceMap.begin()); + } + + while(!m_InitialContents.empty()) + { + auto it = m_InitialContents.begin(); + ResourceTypeRelease(it->second); + if(!m_InitialContents.empty()) + m_InitialContents.erase(m_InitialContents.begin()); + } + + RDCASSERT(m_ResourceRecords.empty()); +} + +template +ResourceManager::~ResourceManager() +{ + RDCASSERT(m_LiveResourceMap.empty()); + RDCASSERT(m_InframeResourceMap.empty()); + RDCASSERT(m_InitialContents.empty()); + RDCASSERT(m_ResourceRecords.empty()); + + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); +} + +template +bool ResourceManager::MarkReferenced(map &refs, ResourceId id, FrameRefType refType) +{ + if(refs.find(id) == refs.end()) + { + if(refType == eFrameRef_Read) + refs[id] = eFrameRef_ReadOnly; + else if(refType == eFrameRef_Write) + refs[id] = eFrameRef_ReadAndWrite; + else // unknown or existing state + refs[id] = refType; + + return true; + } + else + { + if(refType == eFrameRef_Unknown) + { + // nothing + } + else if(refs[id] == eFrameRef_Unknown) + { + if(refType == eFrameRef_ReadBeforeWrite) + refs[id] = eFrameRef_ReadBeforeWrite; + else if(refType == eFrameRef_Read || refType == eFrameRef_ReadOnly) + refs[id] = eFrameRef_ReadOnly; + else + refs[id] = eFrameRef_ReadAndWrite; + } + else if(refs[id] == eFrameRef_ReadOnly && refType == eFrameRef_Write) + { + refs[id] = eFrameRef_ReadBeforeWrite; + } + } + + return false; +} + +template +void ResourceManager::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType) +{ + SCOPED_LOCK(m_Lock); + + if(id == ResourceId()) + return; + + bool newRef = MarkReferenced(m_FrameReferencedResources, id, refType); + + if(newRef) + { + RecordType *record = GetResourceRecord(id); + + if(record) + record->AddRef(); + } +} + +template +bool ResourceManager::ReadBeforeWrite(ResourceId id) +{ + if(m_FrameReferencedResources.find(id) != m_FrameReferencedResources.end()) + return m_FrameReferencedResources[id] == eFrameRef_ReadBeforeWrite || + m_FrameReferencedResources[id] == eFrameRef_ReadOnly; + + return false; +} + +template +void ResourceManager::MarkDirtyResource(ResourceId res) +{ + SCOPED_LOCK(m_Lock); + + if(res == ResourceId()) + return; + + m_DirtyResources.insert(res); +} + +template +void ResourceManager::MarkPendingDirty(ResourceId res) +{ + SCOPED_LOCK(m_Lock); + + if(res == ResourceId()) + return; + + m_PendingDirtyResources.insert(res); +} + +template +void ResourceManager::FlushPendingDirty() +{ + SCOPED_LOCK(m_Lock); + + m_DirtyResources.insert(m_PendingDirtyResources.begin(), m_PendingDirtyResources.end()); + m_PendingDirtyResources.clear(); +} + +template +bool ResourceManager::IsResourceDirty(ResourceId res) +{ + SCOPED_LOCK(m_Lock); + + if(res == ResourceId()) + return false; + + return m_DirtyResources.find(res) != m_DirtyResources.end(); +} + +template +void ResourceManager::MarkCleanResource(ResourceId res) +{ + SCOPED_LOCK(m_Lock); + + if(res == ResourceId()) + return; + + if(IsResourceDirty(res)) + { + m_DirtyResources.erase(res); + } +} + +template +void ResourceManager::SetInitialContents(ResourceId id, ResourceType res, uint32_t data) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(id != ResourceId()); + + auto it = m_InitialContents.find(id); + + if(it != m_InitialContents.end()) + { + ResourceTypeRelease(it->second); + m_InitialContents.erase(it); + } + + m_InitialContents[id] = res; + m_InitialCounts[id] = data; +} + +template +ResourceType ResourceManager::GetInitialContents(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + if(id == ResourceId()) + return (ResourceType)RecordType::NullResource; + + if(m_InitialContents.find(id) != m_InitialContents.end()) + return m_InitialContents[id]; + + return (ResourceType)RecordType::NullResource; +} + +template +void ResourceManager::Serialise_InitialContentsNeeded(Serialiser *ser) +{ + SCOPED_LOCK(m_Lock); + + struct WrittenRecord { ResourceId id; bool written; }; + vector written; + + // reasonable estimate, and these records are small + written.reserve(m_FrameReferencedResources.size()); + + for(auto it=m_FrameReferencedResources.begin(); it != m_FrameReferencedResources.end(); ++it) + { + RecordType *record = GetResourceRecord(it->first); + + if(it->second != eFrameRef_ReadOnly && it->second != eFrameRef_Unknown) + { + WrittenRecord wr = { it->first, record ? record->DataInSerialiser : true }; + + written.push_back(wr); + } + } + + for(auto it=m_DirtyResources.begin(); it != m_DirtyResources.end(); ++it) + { + ResourceId id = *it; + auto ref = m_FrameReferencedResources.find(id); + if(ref == m_FrameReferencedResources.end() || ref->second == eFrameRef_ReadOnly) + { + WrittenRecord wr = { id, true }; + + written.push_back(wr); + } + } + + uint32_t numWritten = (uint32_t)written.size(); + ser->Serialise("NumWrittenResources", numWritten); + + for(auto it=written.begin(); it != written.end(); ++it) + { + ser->Serialise("id", it->id); + ser->Serialise("WrittenData", it->written); + } +} + +template +void ResourceManager::CreateInitialContents(Serialiser *ser) +{ + set neededInitials; + + uint32_t NumWrittenResources = 0; + ser->Serialise("NumWrittenResources", NumWrittenResources); + + for(uint32_t i=0; i < NumWrittenResources; i++) + { + ResourceId id = ResourceId(); + bool WrittenData = false; + + ser->Serialise("id", id); + ser->Serialise("WrittenData", WrittenData); + + neededInitials.insert(id); + + if(HasLiveResource(id) && m_InitialContents.find(id) == m_InitialContents.end()) + Create_InitialState(id, GetLiveResource(id), WrittenData); + } + + for(auto it=m_InitialContents.begin(); it != m_InitialContents.end(); ) + { + ResourceId id = it->first; + + if(neededInitials.find(id) == neededInitials.end()) + { + ResourceTypeRelease(it->second); + ++it; + m_InitialContents.erase(id); + } + else + { + ++it; + } + } +} + +template +void ResourceManager::ApplyInitialContents() +{ + RDCDEBUG("Applying initial contents"); + uint32_t numContents = 0; + for(auto it=m_InitialContents.begin(); it != m_InitialContents.end(); ++it) + { + ResourceId id = it->first; + + if(HasLiveResource(id)) + { + ResourceType live = GetLiveResource(id); + ResourceType initial = it->second; + uint32_t count = 0; + if(m_InitialCounts.find(id) != m_InitialCounts.end()) + count = m_InitialCounts[id]; + + numContents++; + + Apply_InitialState(live, initial, count); + } + } + RDCDEBUG("Applied %d", numContents); +} + +template +void ResourceManager::MarkUnwrittenResources() +{ + SCOPED_LOCK(m_Lock); + + for(auto it=m_ResourceRecords.begin(); it != m_ResourceRecords.end(); ++it) + { + it->second->MarkDataUnwritten(); + } +} + +template +void ResourceManager::InsertReferencedChunks(Serialiser *ser) +{ + map sortedChunks; + + SCOPED_LOCK(m_Lock); + + RDCDEBUG("%u frame resource records", (uint32_t)m_FrameReferencedResources.size()); + + if(RenderDoc::Inst().GetCaptureOptions().RefAllResources) + { + for(auto it=m_ResourceRecords.begin(); it != m_ResourceRecords.end(); ++it) + { + if(!SerialisableResource(it->first, it->second)) + continue; + + it->second->Insert(sortedChunks); + } + } + else + { + for(auto it=m_FrameReferencedResources.begin(); it != m_FrameReferencedResources.end(); ++it) + { + RecordType *record = GetResourceRecord(it->first); + if(record) + record->Insert(sortedChunks); + } + } + + RDCDEBUG("%u frame resource chunks", (uint32_t)sortedChunks.size()); + + for(auto it = sortedChunks.begin(); it != sortedChunks.end(); it++) + { + ser->Insert(it->second); + } + + RDCDEBUG("inserted to serialiser"); +} + +template +void ResourceManager::PrepareInitialContents() +{ + for(auto it=m_DirtyResources.begin(); it != m_DirtyResources.end(); ++it) + { + ResourceId id = *it; + + if(!HasCurrentResource(id)) continue; + + RecordType *record = GetResourceRecord(id); + ResourceType res = GetCurrentResource(id); + + if(record == NULL || record->SpecialResource) continue; + + RDCDEBUG("Dirty Resource %llu - %p", id, res); + + Prepare_InitialState(res); + } + + // need to save the structure count for unordered access views + + for(auto it=m_WrapperMap.begin(); it != m_WrapperMap.end(); ++it) + { + if(it->second == (ResourceType)RecordType::NullResource) continue; + + if(Need_InitialState(it->second)) + { + RDCDEBUG("UAV %llu - %p", GetID(it->second), it->second); + + Prepare_InitialState(it->second); + } + } +} + +template +void ResourceManager::InsertInitialContentsChunks(Serialiser *chunkSerialiser, Serialiser *fileSerialiser) +{ + SCOPED_LOCK(m_Lock); + + for(auto it=m_DirtyResources.begin(); it != m_DirtyResources.end(); ++it) + { + ResourceId id = *it; + + if(m_FrameReferencedResources.find(id) == m_FrameReferencedResources.end()) + { + RDCDEBUG("Resource %llu is GPU dirty but not referenced - skipping", id); + continue; + } + + if(!HasCurrentResource(id)) continue; + + RecordType *record = GetResourceRecord(id); + ResourceType res = GetCurrentResource(id); + + if(record == NULL || record->SpecialResource) continue; + + RDCDEBUG("Dirty Resource %llu - %p", id, res); + + if(!Need_InitialStateChunk(res)) + { + // just need to grab data, don't create chunk + Serialise_InitialState(res); + continue; + } + + ScopedContext scope(chunkSerialiser, NULL, "Initial Contents", "Initial Contents", INITIAL_CONTENTS, false); + + Serialise_InitialState(res); + + fileSerialiser->Insert(scope.Get(true)); + } + + // need to save the structure count for unordered access views + + for(auto it=m_WrapperMap.begin(); it != m_WrapperMap.end(); ++it) + { + if(it->second == (ResourceType)RecordType::NullResource) continue; + + if(Need_InitialState(it->second)) + { + RDCDEBUG("Referenced UAV %llu - %p", GetID(it->second), it->second); + + ScopedContext scope(chunkSerialiser, NULL, "Initial Contents", "Initial Contents", INITIAL_CONTENTS, false); + + Serialise_InitialState(it->second); + + fileSerialiser->Insert(scope.Get(true)); + } + } +} + +template +void ResourceManager::ReleaseInFrameResources() +{ + SCOPED_LOCK(m_Lock); + + // clean up last frame's temporaries - we needed to keep them around so they were valid for + // pipeline inspection etc after replaying the last log. + for(auto it = m_InframeResourceMap.begin(); it != m_InframeResourceMap.end(); ++it) + { + ResourceTypeRelease(it->second); + } + + m_InframeResourceMap.clear(); +} + +template +void ResourceManager::ClearReferencedResources() +{ + SCOPED_LOCK(m_Lock); + + for(auto it=m_FrameReferencedResources.begin(); it != m_FrameReferencedResources.end(); ++it) + { + RecordType *record = GetResourceRecord(it->first); + + if(record) + record->Delete(this); + } + + m_FrameReferencedResources.clear(); +} + +template +void ResourceManager::ReplaceResource(ResourceId from, ResourceId to) +{ + SCOPED_LOCK(m_Lock); + + if(HasLiveResource(to)) + m_Replacements[from] = to; +} + +template +void ResourceManager::RemoveReplacement(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + auto it = m_Replacements.find(id); + + if(it == m_Replacements.end()) + return; + + m_Replacements.erase(it); +} + +template +RecordType *ResourceManager::GetResourceRecord(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + auto it = m_ResourceRecords.find(id); + + if(it == m_ResourceRecords.end()) + return NULL; + + return it->second; +} + +template +bool ResourceManager::HasResourceRecord(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + auto it = m_ResourceRecords.find(id); + + if(it == m_ResourceRecords.end()) + return false; + + return true; +} + +template +RecordType *ResourceManager::AddResourceRecord(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(m_ResourceRecords.find(id) == m_ResourceRecords.end()); + + return (m_ResourceRecords[id] = new RecordType(id)); +} + +template +void ResourceManager::RemoveResourceRecord(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(m_ResourceRecords.find(id) != m_ResourceRecords.end()); + + m_ResourceRecords.erase(id); +} + +template +void ResourceManager::AddWrapper(ResourceType wrap, ResourceType real) +{ + SCOPED_LOCK(m_Lock); + + if(wrap == (ResourceType)RecordType::NullResource || real == (ResourceType)RecordType::NullResource) + { + RDCERR("Invalid state creating resource wrapper - wrapped or real resource is NULL"); + } + + if(m_WrapperMap[real] != (ResourceType)RecordType::NullResource) + { + RDCERR("Overriding wrapper for 0x%p - to 0x%p", real, wrap); + } + + m_WrapperMap[real] = wrap; +} + +template +void ResourceManager::RemoveWrapper(ResourceType real) +{ + SCOPED_LOCK(m_Lock); + + if(real == (ResourceType)RecordType::NullResource || !HasWrapper(real)) + { + RDCERR("Invalid state removing resource wrapper - real resource is NULL or doesn't have wrapper"); + } + + m_WrapperMap.erase( m_WrapperMap.find(real) ); +} + +template +bool ResourceManager::HasWrapper(ResourceType real) +{ + SCOPED_LOCK(m_Lock); + + if(real == (ResourceType)RecordType::NullResource) + return false; + + return (m_WrapperMap.find(real) != m_WrapperMap.end()); +} + +template +ResourceType ResourceManager::GetWrapper(ResourceType real) +{ + SCOPED_LOCK(m_Lock); + + if(real == (ResourceType)RecordType::NullResource) + return (ResourceType)RecordType::NullResource; + + if(real != (ResourceType)RecordType::NullResource && !HasWrapper(real)) + { + RDCERR("Invalid state removing resource wrapper - real resource isn't NULL and doesn't have wrapper"); + } + + return m_WrapperMap[real]; +} + +template +void ResourceManager::AddLiveResource(ResourceId origid, ResourceType livePtr) +{ + SCOPED_LOCK(m_Lock); + + if(origid == ResourceId() || livePtr == (ResourceType)RecordType::NullResource) + { + RDCERR("Invalid state adding resource mapping - id is invalid or live pointer is NULL"); + } + + m_OriginalIDs[GetID(livePtr)] = origid; + m_LiveIDs[origid] = GetID(livePtr); + + if(m_InFrame && m_InframeResourceMap.find(origid) != m_InframeResourceMap.end()) + { + ResourceTypeRelease(m_InframeResourceMap[origid]); + m_InframeResourceMap.erase(origid); + } + else if(!m_InFrame && m_LiveResourceMap.find(origid) != m_LiveResourceMap.end()) + { + RDCERR("Releasing live resource for duplicate creation: %llu", origid); + ResourceTypeRelease(m_LiveResourceMap[origid]); + m_LiveResourceMap.erase(origid); + } + + if(m_InFrame) + m_InframeResourceMap[origid] = livePtr; + else + m_LiveResourceMap[origid] = livePtr; +} + +template +bool ResourceManager::HasLiveResource(ResourceId origid) +{ + SCOPED_LOCK(m_Lock); + + if(origid == ResourceId()) + return false; + + return (m_Replacements.find(origid) != m_Replacements.end() || + m_InframeResourceMap.find(origid) != m_InframeResourceMap.end() || + m_LiveResourceMap.find(origid) != m_LiveResourceMap.end()); +} + +template +ResourceType ResourceManager::GetLiveResource(ResourceId origid) +{ + SCOPED_LOCK(m_Lock); + + if(origid == ResourceId()) + return (ResourceType)RecordType::NullResource; + + RDCASSERT(HasLiveResource(origid)); + + if(m_Replacements.find(origid) != m_Replacements.end()) + return GetLiveResource(m_Replacements[origid]); + + if(m_InframeResourceMap.find(origid) != m_InframeResourceMap.end()) + return m_InframeResourceMap[origid]; + + return m_LiveResourceMap[origid]; +} + +template +void ResourceManager::EraseLiveResource(ResourceId origid) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(HasLiveResource(origid)); + + if(m_InframeResourceMap.find(origid) != m_InframeResourceMap.end()) + { + m_InframeResourceMap.erase(origid); + } + else + { + m_LiveResourceMap.erase(origid); + } +} + +template +void ResourceManager::AddCurrentResource(ResourceId id, ResourceType res) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(m_CurrentResourceMap.find(id) == m_CurrentResourceMap.end()); + m_CurrentResourceMap[id] = res; +} + +template +bool ResourceManager::HasCurrentResource(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + return m_CurrentResourceMap.find(id) != m_CurrentResourceMap.end(); +} + +template +ResourceType ResourceManager::GetCurrentResource(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(m_CurrentResourceMap.find(id) != m_CurrentResourceMap.end()); + return m_CurrentResourceMap[id]; +} + +template +void ResourceManager::ReleaseCurrentResource(ResourceId id) +{ + SCOPED_LOCK(m_Lock); + + RDCASSERT(m_CurrentResourceMap.find(id) != m_CurrentResourceMap.end()); + m_CurrentResourceMap.erase(id); +} + +template +ResourceId ResourceManager::GetOriginalID(ResourceId id) +{ + if(id == ResourceId()) + return id; + + RDCASSERT(m_OriginalIDs.find(id) != m_OriginalIDs.end()); + return m_OriginalIDs[id]; +} + +template +ResourceId ResourceManager::GetLiveID(ResourceId id) +{ + if(id == ResourceId()) + return id; + + RDCASSERT(m_LiveIDs.find(id) != m_LiveIDs.end()); + return m_LiveIDs[id]; +} + + diff --git a/renderdoc/core/socket_helpers.h b/renderdoc/core/socket_helpers.h new file mode 100644 index 0000000000..2020b6f946 --- /dev/null +++ b/renderdoc/core/socket_helpers.h @@ -0,0 +1,234 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +template +bool RecvPacket(Network::Socket *sock, PacketTypeEnum &type, vector &payload) +{ + if(sock == NULL) return false; + + uint32_t t = 0; + if(!sock->RecvDataBlocking(&t, sizeof(t))) + return false; + + uint32_t payloadLength = 0; + if(!sock->RecvDataBlocking(&payloadLength, sizeof(payloadLength))) + return false; + + if(payloadLength > 0) + { + payload.resize(payloadLength); + + if(!sock->RecvDataBlocking(&payload[0], payloadLength)) + return false; + } + + type = (PacketTypeEnum)t; + + return true; +} + +template +bool RecvPacket(Network::Socket *sock, PacketTypeEnum &type, Serialiser **ser) +{ + if(sock == NULL) return false; + + vector payload; + bool ret = RecvPacket(sock, type, payload); + if(!ret) + { + *ser = NULL; + return false; + } + + *ser = new Serialiser(payload.size(), &payload[0], false); + + return true; +} + +template +bool SendPacket(Network::Socket *sock, PacketTypeEnum type) +{ + if(sock == NULL) return false; + + uint32_t payloadLength = 0; + + uint32_t t = (uint32_t)type; + if(!sock->SendDataBlocking(&t, sizeof(t))) + return false; + + if(!sock->SendDataBlocking(&payloadLength, sizeof(payloadLength))) + return false; + + return true; +} + +template +bool SendPacket(Network::Socket *sock, PacketTypeEnum type, const Serialiser &ser) +{ + if(sock == NULL) return false; + + uint32_t t = (uint32_t)type; + if(!sock->SendDataBlocking(&t, sizeof(t))) + return false; + + uint32_t payloadLength = ser.GetOffset()&0xffffffff; + if(!sock->SendDataBlocking(&payloadLength, sizeof(payloadLength))) + return false; + + if(!sock->SendDataBlocking(ser.GetRawPtr(0), payloadLength)) + return false; + + return true; +} + +template +bool RecvChunkedFile(Network::Socket *sock, PacketTypeEnum packetType, const wchar_t *logfile, Serialiser *&ser, float *progress) +{ + if(sock == NULL) return false; + + vector payload; + PacketTypeEnum type; + + if(!RecvPacket(sock, type, payload)) + return false; + + if(type != packetType) + return false; + + ser = new Serialiser(payload.size(), &payload[0], false); + + uint64_t fileLength; + uint32_t bufLength; + uint32_t numBuffers; + + uint64_t sz = ser->GetSize(); + ser->SetOffset(sz - sizeof(uint64_t) - sizeof(uint32_t)*2); + + ser->Serialise("", fileLength); + ser->Serialise("", bufLength); + ser->Serialise("", numBuffers); + + ser->SetOffset(0); + + FILE *f = FileIO::fopen(logfile, L"wb"); + + if(f == NULL) + { + return false; + } + + if(progress) *progress = 0.0001f; + + for(uint32_t i=0; i < numBuffers; i++) + { + if(!RecvPacket(sock, type, payload)) + { + FileIO::fclose(f); + return false; + } + + if(type != packetType) + { + FileIO::fclose(f); + return false; + } + + FileIO::fwrite(&payload[0], 1, payload.size(), f); + + if(progress) *progress = float(i+1)/float(numBuffers); + } + + FileIO::fclose(f); + + return true; +} + +template +bool SendChunkedFile(Network::Socket *sock, PacketTypeEnum type, const wchar_t *logfile, Serialiser &ser, float *progress) +{ + if(sock == NULL) return false; + + FILE *f = FileIO::fopen(logfile, L"rb"); + + if(f == NULL) + { + return false; + } + + FileIO::fseek64(f, 0, SEEK_END); + uint64_t fileLen = FileIO::ftell64(f); + FileIO::fseek64(f, 0, SEEK_SET); + + uint32_t bufLen = (uint32_t)RDCMIN((uint64_t)4*1024*1024, fileLen); + uint64_t n = fileLen / (uint64_t)bufLen; + uint32_t numBufs = (uint32_t)n; + if(fileLen % (uint64_t)bufLen > 0) numBufs++; // last remaining buffer + + ser.Serialise("", fileLen); + ser.Serialise("", bufLen); + ser.Serialise("", numBufs); + + if(!SendPacket(sock, type, ser)) + { + FileIO::fclose(f); + return false; + } + + byte *buf = new byte[bufLen]; + + uint32_t t = (uint32_t)type; + + if(progress) *progress = 0.0001f; + + for(uint32_t i=0; i < numBufs; i++) + { + uint32_t payloadLength = RDCMIN(bufLen, (uint32_t)(fileLen&0xffffffff)); + + FileIO::fread(buf, 1, payloadLength, f); + + if(!sock->SendDataBlocking(&t, sizeof(t)) || + !sock->SendDataBlocking(&payloadLength, sizeof(payloadLength)) || + !sock->SendDataBlocking(buf, payloadLength)) + { + break; + } + + fileLen -= payloadLength; + if(progress) *progress = float(i+1)/float(numBufs); + } + + delete[] buf; + + FileIO::fclose(f); + + if(fileLen != 0) + { + return false; + } + + return true; +} diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h new file mode 100644 index 0000000000..3a777128cf --- /dev/null +++ b/renderdoc/data/embedded_files.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#define DECLARE_EMBED(filename) \ + extern char CONCAT( CONCAT(_binary_, filename) , _start) ; \ + extern char CONCAT( CONCAT(_binary_, filename) , _end) ; + +DECLARE_EMBED(blit_vert); +DECLARE_EMBED(blit_frag); +DECLARE_EMBED(texdisplay_frag); +DECLARE_EMBED(checkerboard_frag); +DECLARE_EMBED(mesh_vert); +DECLARE_EMBED(generic_vert); +DECLARE_EMBED(generic_frag); + +#undef DECLARE_EMBED diff --git a/renderdoc/data/glsl/blit.frag b/renderdoc/data/glsl/blit.frag new file mode 100644 index 0000000000..883819e44d --- /dev/null +++ b/renderdoc/data/glsl/blit.frag @@ -0,0 +1,33 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +layout (binding = 0) uniform sampler2D tex0; +layout (location = 0) out vec4 color_out; + +void main(void) +{ + color_out = texture2D(tex0, gl_FragCoord.xy/textureSize(tex0, 0)); +} diff --git a/renderdoc/data/glsl/blit.vert b/renderdoc/data/glsl/blit.vert new file mode 100644 index 0000000000..a6283fa73e --- /dev/null +++ b/renderdoc/data/glsl/blit.vert @@ -0,0 +1,35 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +void main(void) +{ + const vec4 verts[4] = vec4[4](vec4(-1.0, -1.0, 0.5, 1.0), + vec4( 1.0, -1.0, 0.5, 1.0), + vec4(-1.0, 1.0, 0.5, 1.0), + vec4( 1.0, 1.0, 0.5, 1.0)); + + gl_Position = verts[gl_VertexID]; +} diff --git a/renderdoc/data/glsl/checkerboard.frag b/renderdoc/data/glsl/checkerboard.frag new file mode 100644 index 0000000000..771c8540a1 --- /dev/null +++ b/renderdoc/data/glsl/checkerboard.frag @@ -0,0 +1,50 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +layout (location = 0) out vec4 color_out; + +layout (binding = 0, std140) uniform checker +{ + vec4 lightCol; + vec4 darkCol; +}; + +void main(void) +{ + vec2 ab = mod(gl_FragCoord.xy, 128.0f.xx); + + if( + (ab.x < 64 && ab.y < 64) || + (ab.x > 64 && ab.y > 64) + ) + { + color_out = vec4(sqrt(lightCol.rgb), 1); + } + else + { + color_out = vec4(sqrt(darkCol.rgb), 1); + } +} diff --git a/renderdoc/data/glsl/generic.frag b/renderdoc/data/glsl/generic.frag new file mode 100644 index 0000000000..87a7630ba0 --- /dev/null +++ b/renderdoc/data/glsl/generic.frag @@ -0,0 +1,34 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +layout (location = 0) out vec4 color_out; + +uniform vec4 RENDERDOC_GenericFS_Color; + +void main(void) +{ + color_out = RENDERDOC_GenericFS_Color; +} diff --git a/renderdoc/data/glsl/generic.vert b/renderdoc/data/glsl/generic.vert new file mode 100644 index 0000000000..317764829e --- /dev/null +++ b/renderdoc/data/glsl/generic.vert @@ -0,0 +1,35 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +layout (location = 0) in vec4 position; + +uniform vec4 RENDERDOC_GenericVS_Offset; +uniform vec4 RENDERDOC_GenericVS_Scale; + +void main(void) +{ + gl_Position = position*RENDERDOC_GenericVS_Scale + RENDERDOC_GenericVS_Offset; +} diff --git a/renderdoc/data/glsl/mesh.vert b/renderdoc/data/glsl/mesh.vert new file mode 100644 index 0000000000..1ecac3821e --- /dev/null +++ b/renderdoc/data/glsl/mesh.vert @@ -0,0 +1,34 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +layout (location = 0) in vec4 position; + +uniform mat4 ModelViewProj; + +void main(void) +{ + gl_Position = ModelViewProj * position; +} diff --git a/renderdoc/data/glsl/texdisplay.frag b/renderdoc/data/glsl/texdisplay.frag new file mode 100644 index 0000000000..15a34553d8 --- /dev/null +++ b/renderdoc/data/glsl/texdisplay.frag @@ -0,0 +1,104 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#version 420 core + +layout (binding = 0, std140) uniform texdisplay +{ + vec2 Position; + float Scale; + float HDRMul; + + vec4 Channels; + + float RangeMinimum; + float InverseRangeSize; + float MipLevel; + float dummy2; + + vec3 TextureResolutionPS; + int OutputDisplayFormat; + + vec2 OutputRes; + int RawOutput; + float Slice; +}; + +layout (binding = 0) uniform sampler2D tex0; +layout (location = 0) out vec4 color_out; + +void main(void) +{ + // calc screen co-ords with origin top left, modified by Position + vec2 scr = vec2(gl_FragCoord.x, OutputRes.y - gl_FragCoord.y) - Position.xy; + + // calc UVs in texture + vec2 uv = scr/(textureSize(tex0,0)*Scale); + + // discard if we're rendering outside input texture + if(uv.x < 0 || uv.y < 0 || uv.x > 1 || uv.y > 1) discard; + + // sample the texture. + // TODO: handle uint/sint/float textures (OutputDisplayFormat). + // TODO: Use MipLevel and Slice parameters + // TODO: Sample from a point or linear sampler depending on if we're + // upscaling (point) or downscaling mip 0 (linear) + vec4 col = texture(tex0, vec2(uv.x, 1.0f-uv.y)); + + if(RawOutput != 0) + { + color_out = col; + return; + } + + // RGBM encoding + if(HDRMul > 0.0f) + { + col = vec4(col.rgb * col.a * HDRMul, 1.0f); + } + + col = ((col - RangeMinimum)*InverseRangeSize); + + col = mix(vec4(0,0,0,1), col, Channels); + + // TODO: check OutputDisplayFormat to see if we should highlight NaNs or clipping + // else + { + // if only one channel is selected + if(dot(Channels, 1.0f.xxxx) == 1.0f.xxxx) + { + // if it's alpha, just move it into rgb + // otherwise, select the channel that's on and replicate it across all channels + if(Channels.a == 1) + col = vec4(col.aaa, 1); + else + col = vec4(dot(col.rgb, 1.0f.xxx).xxx, 1.0f); + } + } + + // TODO: Check OutputDisplayFormat for SRGB handling + // TODO: Figure out SRGB in opengl at all :) + + color_out = col; +} \ No newline at end of file diff --git a/renderdoc/data/hlsl/debugcbuffers.h b/renderdoc/data/hlsl/debugcbuffers.h new file mode 100644 index 0000000000..f83aea1bee --- /dev/null +++ b/renderdoc/data/hlsl/debugcbuffers.h @@ -0,0 +1,149 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// use some preprocessor hacks to compile the same header in both hlsl and C++ so we can define +// classes that represent a whole cbuffer +#if defined(__cplusplus) + +#define cbuffer struct +#define float2 Vec2f +#define float3 Vec3f +#define float4 Vec4f +#define float4x4 Matrix4f +#define uint uint32_t +#define row_major + +#define REG(r) + +#else + +#define REG(r) : register(r) + +#endif + +cbuffer FontCBuffer REG(b0) +{ + float2 TextPosition; + float CharacterOffsetX; + float TextSize; + + float2 CharacterSize; + float2 FontScreenAspect; +}; + +cbuffer DebugVertexCBuffer REG(b0) +{ + float2 Position; + float2 SpriteSize; + + float2 TextureResolution; + float2 ScreenAspect; + + row_major float4x4 ModelViewProj; + + float Scale; + float3 dummy1; +}; + +cbuffer DebugGeometryCBuffer REG(b0) +{ + row_major float4x4 InvProj; +}; + +cbuffer DebugPixelCBufferData REG(b0) +{ + float4 Channels; + + float RangeMinimum; + float InverseRangeSize; + float MipLevel; + int padding; + + float3 WireframeColour; + int OutputDisplayFormat; + + float Slice; + float ScalePS; + float2 Padding; + + int RawOutput; + float3 TextureResolutionPS; +}; + +cbuffer HistogramCBufferData REG(b0) +{ + uint HistogramChannels; + float HistogramMin; + float HistogramMax; + uint HistogramFlags; + + float HistogramSlice; + uint HistogramMip; + float2 Padding2; + + float3 HistogramTextureResolution; + float Padding3; +}; + +// some constants available to both C++ and HLSL for configuring display +#define CUBEMAP_FACE_RIGHT 0 +#define CUBEMAP_FACE_LEFT 1 +#define CUBEMAP_FACE_UP 2 +#define CUBEMAP_FACE_DOWN 3 +#define CUBEMAP_FACE_FRONT 4 +#define CUBEMAP_FACE_BACK 5 + +#define RESTYPE_TEX1D 0x1 +#define RESTYPE_TEX2D 0x2 +#define RESTYPE_TEX3D 0x3 +#define RESTYPE_DEPTH 0x4 +#define RESTYPE_DEPTH_STENCIL 0x5 +#define RESTYPE_DEPTH_MS 0x6 +#define RESTYPE_DEPTH_STENCIL_MS 0x7 + +#define MESHDISPLAY_SOLID 0x1 +#define MESHDISPLAY_FACELIT 0x2 +#define MESHDISPLAY_TEXCOORD 0x3 +#define MESHDISPLAY_COLOR 0x4 + +#define TEXDISPLAY_TYPEMASK 0xF +#define TEXDISPLAY_NANS 0x0100 +#define TEXDISPLAY_CLIPPING 0x0200 +#define TEXDISPLAY_UINT_TEX 0x0400 +#define TEXDISPLAY_SINT_TEX 0x0800 +#define TEXDISPLAY_GAMMA_CURVE 0x1000 + + +// histogram/minmax is calculated in blocks of NxN each with MxM tiles. +// e.g. a tile is 32x32 pixels, then this is arranged in blocks of 32x32 tiles. +// 1 compute thread = 1 tile, 1 compute group = 1 block +// +// NOTE because of this a block can cover more than the texture (think of a 1280x720 +// texture covered by 2x1 blocks) +// +// these values are in each dimension +#define HGRAM_PIXELS_PER_TILE 64 +#define HGRAM_TILES_PER_BLOCK 32 + +#define HGRAM_NUM_BUCKETS 256 diff --git a/renderdoc/data/hlsl/debugcommon.hlsl b/renderdoc/data/hlsl/debugcommon.hlsl new file mode 100644 index 0000000000..bdc65a0baf --- /dev/null +++ b/renderdoc/data/hlsl/debugcommon.hlsl @@ -0,0 +1,136 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// this file provides a couple of functions that, given the basic type, will go and +// figure out which resource to sample from and load from it then return the value + +struct a2v +{ + float3 pos : POSITION; +}; + +struct v2f +{ + float4 pos : SV_Position; + float4 tex : TEXCOORD0; +}; + +SamplerState pointSampler : register(s0); +SamplerState linearSampler : register(s1); + +Texture1DArray texDisplayTex1DArray : register(t1); +Texture2DArray texDisplayTex2DArray : register(t2); +Texture3D texDisplayTex3D : register(t3); +Texture2DArray texDisplayTexDepthArray : register(t4); +Texture2DArray texDisplayTexStencilArray : register(t5); +Texture2DMSArray texDisplayTexDepthMSArray : register(t6); +Texture2DMSArray texDisplayTexStencilMSArray : register(t7); +Texture2DArray texDisplayTexCubeArray : register(t8); + +Texture1DArray texDisplayUIntTex1DArray : register(t11); +Texture2DArray texDisplayUIntTex2DArray : register(t12); +Texture3D texDisplayUIntTex3D : register(t13); + +Texture1DArray texDisplayIntTex1DArray : register(t21); +Texture2DArray texDisplayIntTex2DArray : register(t22); +Texture3D texDisplayIntTex3D : register(t23); + +uint4 SampleTextureUInt4(uint type, float2 uv, float slice, float mip, float3 texRes) +{ + uint4 col = 0; + + if(type == RESTYPE_TEX1D) + col = texDisplayUIntTex1DArray.Load(int3(uv.x*texRes.x, slice, mip)); + else if(type == RESTYPE_TEX3D) + col = texDisplayUIntTex3D.Load(int4(uv.xy*texRes.xy, slice*texRes.z, mip)); + else if(type == RESTYPE_TEX2D) + col = texDisplayUIntTex2DArray.Load(int4(uv.xy*texRes.xy, slice, mip)); + + return col; +} + +int4 SampleTextureInt4(uint type, float2 uv, float slice, float mip, float3 texRes) +{ + int4 col = 0; + + if(type == RESTYPE_TEX1D) + col = texDisplayIntTex1DArray.Load(int3(uv.x*texRes.x, slice, mip)); + else if(type == RESTYPE_TEX3D) + col = texDisplayIntTex3D.Load(int4(uv.xy*texRes.xy, slice*texRes.z, mip)); + else if(type == RESTYPE_TEX2D) + col = texDisplayIntTex2DArray.Load(int4(uv.xy*texRes.xy, slice, mip)); + + return col; +} + +float4 SampleTextureFloat4(uint type, bool linearSample, float2 uv, float slice, float mip, float3 texRes) +{ + float4 col = 0; + + if(type == RESTYPE_TEX1D) + { + if(linearSample) + col = texDisplayTex1DArray.SampleLevel(linearSampler, float2(uv.x, slice), mip); + else + col = texDisplayTex1DArray.Load(int3(uv.x*texRes.x, slice, mip)); + } + else if(type == RESTYPE_TEX3D) + { + if(linearSample) + col = texDisplayTex3D.SampleLevel(linearSampler, float3(uv.xy, slice), mip); + else + col = texDisplayTex3D.Load(int4(uv.xy*texRes.xy, slice*texRes.z, mip)); + } + else if(type == RESTYPE_DEPTH) + { + col.r = texDisplayTexDepthArray.Load(int4(uv.xy*texRes.xy, slice, mip)).r; + col.gba = float3(0, 0, 1); + } + else if(type == RESTYPE_DEPTH_STENCIL) + { + col.r = texDisplayTexDepthArray.Load(int4(uv.xy*texRes.xy, slice, mip)).r; + col.g = texDisplayTexStencilArray.Load(int4(uv.xy*texRes.xy, slice, mip)).g/255.0f; + col.ba = float2(0, 1); + } + else if(type == RESTYPE_DEPTH_MS) + { + col.r = texDisplayTexDepthMSArray.Load(int3(uv.xy*texRes.xy, slice), 0).r; + col.gba = float3(0, 0, 1); + } + else if(type == RESTYPE_DEPTH_STENCIL_MS) + { + col.r = texDisplayTexDepthMSArray.Load(int3(uv.xy*texRes.xy, slice), 0).r; + col.g = texDisplayTexStencilMSArray.Load(int3(uv.xy*texRes.xy, slice), 0).g/255.0f; + col.ba = float2(0, 1); + } + else if(type == RESTYPE_TEX2D) + { + if(linearSample) + col = texDisplayTex2DArray.SampleLevel(linearSampler, float3(uv.xy, slice), mip); + else + col = texDisplayTex2DArray.Load(int4(uv.xy*texRes.xy, slice, mip)); + } + + return col; +} diff --git a/renderdoc/data/hlsl/debugdisplay.hlsl b/renderdoc/data/hlsl/debugdisplay.hlsl new file mode 100644 index 0000000000..851126dbb4 --- /dev/null +++ b/renderdoc/data/hlsl/debugdisplay.hlsl @@ -0,0 +1,329 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + + +v2f RENDERDOC_DebugVS(a2v IN) +{ + v2f OUT = (v2f)0; + OUT.pos = float4(Position.xy + (float2(IN.pos.z,0) + IN.pos.xy*TextureResolution.xy)*Scale*ScreenAspect.xy, 0, 1)-float4(1.0,-1.0,0,0); + OUT.tex.xy = float2(IN.pos.x, -IN.pos.y); + return OUT; +} + +// main texture display shader, used for the texture viewer. It samples the right resource +// for the type and applies things like the range check and channel masking. +// It also does a couple of overlays that we can get 'free' like NaN/inf checks +// or range clipping +float4 RENDERDOC_TexDisplayPS(v2f IN) : SV_Target0 +{ + bool uintTex = OutputDisplayFormat & TEXDISPLAY_UINT_TEX; + bool sintTex = OutputDisplayFormat & TEXDISPLAY_SINT_TEX; + + float4 col = 0; + uint4 ucol = 0; + int4 scol = 0; + + if(uintTex) + { + ucol = SampleTextureUInt4(OutputDisplayFormat & TEXDISPLAY_TYPEMASK, + IN.tex.xy, Slice, MipLevel, TextureResolutionPS); + } + else if(sintTex) + { + scol = SampleTextureInt4 (OutputDisplayFormat & TEXDISPLAY_TYPEMASK, + IN.tex.xy, Slice, MipLevel, TextureResolutionPS); + } + else + { + col = SampleTextureFloat4(OutputDisplayFormat & TEXDISPLAY_TYPEMASK, (ScalePS < 1 && MipLevel == 0), + IN.tex.xy, Slice, MipLevel, TextureResolutionPS); + } + + if(RawOutput) + { + if(uintTex) + return asfloat(ucol); + else if(sintTex) + return asfloat(scol); + else + return col; + } + + // RGBM encoding + if(WireframeColour.x > 0.0f) + { + if(uintTex) + ucol = float4(ucol.rgb * ucol.a * (uint)(WireframeColour.x), 1.0f); + else if(sintTex) + scol = float4(scol.rgb * scol.a * (int)(WireframeColour.x), 1.0f); + else + col = float4(col.rgb * col.a * WireframeColour.x, 1.0f); + } + + if(uintTex) + col = (float4)(ucol); + else if(sintTex) + col = (float4)(scol); + + col = ((col - RangeMinimum)*InverseRangeSize); + + col = lerp(float4(0,0,0,1), col, Channels); + + // show nans, infs and negatives + if(OutputDisplayFormat & TEXDISPLAY_NANS) + { + if(isnan(col.r) || isnan(col.g) || isnan(col.b) || isnan(col.a)) + return float4(1, 0, 0, 1); + + if(isinf(col.r) || isinf(col.g) || isinf(col.b) || isinf(col.a)) + return float4(0, 1, 0, 1); + + if(col.r < 0 || col.g < 0 || col.b < 0 || col.a < 0) + return float4(0, 0, 1, 1); + + col = float4(dot(col.xyz, float3(0.2126, 0.7152, 0.0722)).xxx, 1); + } + else if(OutputDisplayFormat & TEXDISPLAY_CLIPPING) + { + if(col.r < 0 || col.g < 0 || col.b < 0 || col.a < 0) + return float4(1, 0, 0, 1); + + if(col.r > 1 || col.g > 1 || col.b > 1 || col.a > 1) + return float4(0, 1, 0, 1); + + col = float4(dot(col.xyz, float3(0.2126, 0.7152, 0.0722)).xxx, 1); + } + else + { + // if only one channel is selected + if(dot(Channels, 1) == 1) + { + // if it's alpha, just move it into rgb + // otherwise, select the channel that's on and replicate it across all channels + if(Channels.a == 1) + col = float4(col.aaa, 1); + else + col = float4(dot(col.rgb, 1).xxx, 1); + } + } + + if(OutputDisplayFormat & TEXDISPLAY_GAMMA_CURVE) + { + col.rgb = pow(saturate(col.rgb), 2.2f); + } + + return col; +} + +struct MultipleOutput +{ + float4 col0 : SV_Target0; + float4 col1 : SV_Target1; + float4 col2 : SV_Target2; + float4 col3 : SV_Target3; + float4 col4 : SV_Target4; + float4 col5 : SV_Target5; + float4 col6 : SV_Target6; + float4 col7 : SV_Target7; +}; + +struct wireframeV2F +{ + float4 pos : SV_Position; + float3 norm : Normal; + float3 color : COLOR; + float2 tex : TEXCOORD0; +}; + +wireframeV2F RENDERDOC_WireframeHomogVS(float4 pos : POSITION, uint vid : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + OUT.pos = mul(pos, ModelViewProj); + + float2 psprite[4] = + { + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2( 1.0f, 1.0f) + }; + + OUT.pos.xy += SpriteSize.xy*0.01f*psprite[vid%4]*OUT.pos.w; + + return OUT; +} + +struct meshA2V +{ + float3 pos : pos; + float2 tex : tex; + float3 color : col; +}; + +wireframeV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + + OUT.pos = mul(float4(IN.pos, 1), ModelViewProj); + OUT.norm = float3(0, 0, 1); + OUT.color = IN.color; + OUT.tex = IN.tex; + + return OUT; +} + +[maxvertexcount(3)] +void RENDERDOC_MeshGS(triangle wireframeV2F input[3], inout TriangleStream TriStream) +{ + wireframeV2F output; + + float4 faceEdgeA = mul(input[1].pos, InvProj) - mul(input[0].pos, InvProj); + float4 faceEdgeB = mul(input[2].pos, InvProj) - mul(input[0].pos, InvProj); + float3 faceNormal = normalize( cross(faceEdgeA.xyz, faceEdgeB.xyz) ); + + for(int i=0; i<3; i++) + { + output.pos = input[i].pos; + output.norm = faceNormal; + output.color = input[i].color; + output.tex = input[i].tex; + TriStream.Append(output); + } + TriStream.RestartStrip(); +} + +float4 RENDERDOC_MeshPS(wireframeV2F IN) : SV_Target0 +{ + uint type = OutputDisplayFormat; + + if(type == MESHDISPLAY_TEXCOORD) + return float4(IN.tex.xy, 0, 1); + else if(type == MESHDISPLAY_COLOR) + return float4(IN.color.xyz, 1); + else if(type == MESHDISPLAY_FACELIT) + { + float3 lightDir = normalize(float3(0, -0.3f, -1)); + + return float4(WireframeColour.xyz*saturate(dot(lightDir, IN.norm)), 1); + } + else //if(type == MESHDISPLAY_SOLID) + return float4(WireframeColour.xyz, 1); +} + +wireframeV2F RENDERDOC_WireframeVS(float3 pos : POSITION, uint vid : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + OUT.pos = mul(float4(pos, 1), ModelViewProj); + + float2 psprite[4] = + { + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2( 1.0f, 1.0f) + }; + + OUT.pos.xy += SpriteSize.xy*0.01f*psprite[vid%4]*OUT.pos.w; + + return OUT; +} + +wireframeV2F RENDERDOC_FullscreenVS(uint id : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + + float4 pos[] = { + float4( -1.0f, 1.0f, 0.0f, 1.0f), + float4( 3.0f, 1.0f, 0.0f, 1.0f), + float4( -1.0f, -3.0f, 0.0f, 1.0f) + }; + + float2 uv[] = { + float2(0.0f, 0.0f), + float2(2.0f, 0.0f), + float2(0.0f, 2.0f) + }; + + OUT.pos = pos[id]; + OUT.tex = uv[id]; + OUT.norm = float3(0, 0, 1); + OUT.color = float3(1, 1, 1); + + return OUT; +} + +MultipleOutput RENDERDOC_WireframePS(wireframeV2F IN) +{ + MultipleOutput OUT = (MultipleOutput)0; + + OUT.col0 = + OUT.col1 = + OUT.col2 = + OUT.col3 = + OUT.col4 = + OUT.col5 = + OUT.col6 = + OUT.col7 = + float4(WireframeColour.xyz, 1); + + return OUT; +} + +cbuffer overlayconsts : register(b1) +{ + float4 overlaycol; +}; + +MultipleOutput RENDERDOC_OverlayPS(float4 IN : SV_Position) +{ + MultipleOutput OUT = (MultipleOutput)0; + + OUT.col0 = + OUT.col1 = + OUT.col2 = + OUT.col3 = + OUT.col4 = + OUT.col5 = + OUT.col6 = + OUT.col7 = + overlaycol; + + return OUT; +} + +float4 RENDERDOC_CheckerboardPS(float4 IN : SV_Position) : SV_Target0 +{ + float2 ab = fmod(IN.xy, 128.0.xx); + + if( + (ab.x < 64 && ab.y < 64) || + (ab.x > 64 && ab.y > 64) + ) + { + return float4(sqrt(WireframeColour.rgb), 1); + } + + return float4(sqrt(Channels.rgb), 1); +} diff --git a/renderdoc/data/hlsl/debugtext.hlsl b/renderdoc/data/hlsl/debugtext.hlsl new file mode 100644 index 0000000000..a069d7c19d --- /dev/null +++ b/renderdoc/data/hlsl/debugtext.hlsl @@ -0,0 +1,64 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// text shader, used for the overlay in game so that we can pass indices in the positon stream +// and it figures out the right place in the text texture to sample. + +struct a2v +{ + float3 pos : POSITION; + uint tex : TEXCOORD0; +}; + +struct v2f +{ + float4 pos : SV_POSITION; + float4 tex : TEXCOORD0; +}; + +v2f RENDERDOC_TextVS(a2v IN) +{ + v2f OUT = (v2f)0; + + OUT.pos = float4((float2(IN.pos.z,0) + IN.pos.xy)*TextSize*FontScreenAspect.xy + TextPosition.xy, 0, 1)-float4(1,-1,0,0); + OUT.tex.xy = (IN.pos.xy+float2(0,1))*CharacterSize.xy + float2((IN.tex.x-1)*CharacterOffsetX, 0); + + if(IN.tex.x == 0) + OUT.tex.xy = 0; + return OUT; +} + +SamplerState pointSample : register(s0); +SamplerState linearSample : register(s1); + +Texture2D debugTexture : register(t0); + +float4 RENDERDOC_TextPS(v2f IN) : SV_Target0 +{ + IN.tex.y = 1 - IN.tex.y; + + float4 text = debugTexture.Sample(linearSample, IN.tex.xy).xxxx; + + return text + float4(0.0.xxx, 0.5); +} diff --git a/renderdoc/data/hlsl/histogram.hlsl b/renderdoc/data/hlsl/histogram.hlsl new file mode 100644 index 0000000000..bdbb64a9b1 --- /dev/null +++ b/renderdoc/data/hlsl/histogram.hlsl @@ -0,0 +1,355 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// compute shaders that figure out the min/max values or histogram in a texture heirarchically +// note that we have to conditionally compile this shader for float/uint/sint as doing that +// dynamically produces a shader with too many temp registers unfortunately. + +RWBuffer MinMaxDestFloat : register(u0); +RWBuffer MinMaxDestUInt : register(u1); +RWBuffer MinMaxDestInt : register(u2); + +[numthreads(HGRAM_TILES_PER_BLOCK, HGRAM_TILES_PER_BLOCK, 1)] +void RENDERDOC_TileMinMaxCS(uint3 tid : SV_GroupThreadID, uint3 gid : SV_GroupID) +{ + uint texType = SHADER_RESTYPE; + + uint3 texDim = uint3(HistogramTextureResolution); + + uint blocksX = (int)ceil(float(texDim.x)/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + + uint2 topleft = (gid.xy*HGRAM_TILES_PER_BLOCK + tid.xy)*HGRAM_PIXELS_PER_TILE; + + uint outIdx = (tid.y*HGRAM_TILES_PER_BLOCK + tid.x) + (gid.y*blocksX + gid.x)*(HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK); + + int i=0; + +#if UINT_TEX + { + uint4 minval = 0; + uint4 maxval = 0; + + for(uint y=topleft.y; y < min(texDim.y, topleft.y + HGRAM_PIXELS_PER_TILE); y++) + { + for(uint x=topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) + { + uint4 data = SampleTextureUInt4(texType, float2(x, y)/float2(texDim.xy), + HistogramSlice, HistogramMip, texDim); + + if(i == 0) + { + minval = maxval = data; + } + else + { + minval = min(minval, data); + maxval = max(maxval, data); + } + + i++; + } + } + + MinMaxDestUInt[outIdx*2+0] = minval; + MinMaxDestUInt[outIdx*2+1] = maxval; + return; + } +#elif SINT_TEX + { + int4 minval = 0; + int4 maxval = 0; + + for(uint y=topleft.y; y < min(texDim.y, topleft.y + HGRAM_PIXELS_PER_TILE); y++) + { + for(uint x=topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) + { + int4 data = SampleTextureInt4(texType, float2(x, y)/float2(texDim.xy), + HistogramSlice, HistogramMip, texDim); + + if(i == 0) + { + minval = maxval = data; + } + else + { + minval = min(minval, data); + maxval = max(maxval, data); + } + + i++; + } + } + + MinMaxDestInt[outIdx*2+0] = minval; + MinMaxDestInt[outIdx*2+1] = maxval; + return; + } +#else + { + float4 minval = 0; + float4 maxval = 0; + + for(uint y=topleft.y; y < min(texDim.y, topleft.y + HGRAM_PIXELS_PER_TILE); y++) + { + for(uint x=topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) + { + float4 data = SampleTextureFloat4(texType, false, float2(x, y)/float2(texDim.xy), + HistogramSlice, HistogramMip, texDim); + + if(i == 0) + { + minval = maxval = data; + } + else + { + minval = min(minval, data); + maxval = max(maxval, data); + } + + i++; + } + } + + MinMaxDestFloat[outIdx*2+0] = minval; + MinMaxDestFloat[outIdx*2+1] = maxval; + return; + } +#endif +} + +Buffer MinMaxResultSourceFloat : register(t0); +Buffer MinMaxResultSourceUInt : register(t1); +Buffer MinMaxResultSourceInt : register(t2); + +RWBuffer MinMaxResultDestFloat : register(u0); +RWBuffer MinMaxResultDestUInt : register(u1); +RWBuffer MinMaxResultDestInt : register(u2); + +[numthreads(1,1,1)] +void RENDERDOC_ResultMinMaxCS() +{ + uint3 texDim = uint3(HistogramTextureResolution); + + uint blocksX = (int)ceil(float(texDim.x)/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + uint blocksY = (int)ceil(float(texDim.y)/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + +#if UINT_TEX + uint4 minvalU = MinMaxResultSourceUInt[0]; + uint4 maxvalU = MinMaxResultSourceUInt[1]; +#elif SINT_TEX + int4 minvalI = MinMaxResultSourceInt[0]; + int4 maxvalI = MinMaxResultSourceInt[1]; +#else + float4 minvalF = MinMaxResultSourceFloat[0]; + float4 maxvalF = MinMaxResultSourceFloat[1]; +#endif + + // i is the tile we're looking at + for(uint i=1; i < blocksX*blocksY*HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK; i++) + { + uint blockIdx = i/(HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK); + uint tileIdx = i%(HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK); + + // which block and tile is this in + uint2 blockXY = uint2(blockIdx % blocksX, blockIdx / blocksX); + uint2 tileXY = uint2(tileIdx % HGRAM_TILES_PER_BLOCK, tileIdx / HGRAM_TILES_PER_BLOCK); + + // if this is at least partially within the texture, include it. + if(blockXY.x*(HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK) + tileXY.x*HGRAM_PIXELS_PER_TILE < texDim.x && + blockXY.y*(HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK) + tileXY.y*HGRAM_PIXELS_PER_TILE < texDim.y) + { +#if UINT_TEX + minvalU = min(minvalU, MinMaxResultSourceUInt[i*2 + 0]); + maxvalU = max(maxvalU, MinMaxResultSourceUInt[i*2 + 1]); +#elif SINT_TEX + minvalI = min(minvalI, MinMaxResultSourceInt[i*2 + 0]); + maxvalI = max(maxvalI, MinMaxResultSourceInt[i*2 + 1]); +#else + minvalF = min(minvalF, MinMaxResultSourceFloat[i*2 + 0]); + maxvalF = max(maxvalF, MinMaxResultSourceFloat[i*2 + 1]); +#endif + } + } + +#if UINT_TEX + MinMaxResultDestUInt[0] = minvalU; + MinMaxResultDestUInt[1] = maxvalU; +#elif SINT_TEX + MinMaxResultDestInt[0] = minvalI; + MinMaxResultDestInt[1] = maxvalI; +#else + MinMaxResultDestFloat[0] = minvalF; + MinMaxResultDestFloat[1] = maxvalF; +#endif +} + +RWBuffer HistogramDest : register(u0); + +[numthreads(HGRAM_TILES_PER_BLOCK, HGRAM_TILES_PER_BLOCK, 1)] +void RENDERDOC_HistogramCS(uint3 tid : SV_GroupThreadID, uint3 gid : SV_GroupID) +{ + uint texType = SHADER_RESTYPE; + + uint3 texDim = uint3(HistogramTextureResolution); + + uint blocksX = (int)ceil(float(texDim.x)/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + + uint2 topleft = (gid.xy*HGRAM_TILES_PER_BLOCK + tid.xy)*HGRAM_PIXELS_PER_TILE; + + int i=0; + + for(uint y=topleft.y; y < min(texDim.y, topleft.y + HGRAM_PIXELS_PER_TILE); y++) + { + for(uint x=topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) + { + uint bucketIdx = HGRAM_NUM_BUCKETS+1; + +#if UINT_TEX + { + uint4 data = SampleTextureUInt4(texType, float2(x, y)/float2(texDim.xy), + HistogramSlice, HistogramMip, texDim); + + float divisor = 0.0f; + uint sum = 0; + if(HistogramChannels & 0x1) + { + sum += data.x; + divisor += 1.0f; + } + if(HistogramChannels & 0x2) + { + sum += data.y; + divisor += 1.0f; + } + if(HistogramChannels & 0x4) + { + sum += data.z; + divisor += 1.0f; + } + if(HistogramChannels & 0x8) + { + sum += data.w; + divisor += 1.0f; + } + + if(divisor > 0.0f) + { + float val = float(sum)/divisor; + + float normalisedVal = (val - HistogramMin)/(HistogramMax - HistogramMin); + + if(normalisedVal < 0.0f) + normalisedVal = 2.0f; + + bucketIdx = (uint)floor(normalisedVal*HGRAM_NUM_BUCKETS); + } + } +#elif SINT_TEX + { + int4 data = SampleTextureInt4(texType, float2(x, y)/float2(texDim.xy), + HistogramSlice, HistogramMip, texDim); + + float divisor = 0.0f; + int sum = 0; + if(HistogramChannels & 0x1) + { + sum += data.x; + divisor += 1.0f; + } + if(HistogramChannels & 0x2) + { + sum += data.y; + divisor += 1.0f; + } + if(HistogramChannels & 0x4) + { + sum += data.z; + divisor += 1.0f; + } + if(HistogramChannels & 0x8) + { + sum += data.w; + divisor += 1.0f; + } + + if(divisor > 0.0f) + { + float val = float(sum)/divisor; + + float normalisedVal = (val - HistogramMin)/(HistogramMax - HistogramMin); + + if(normalisedVal < 0.0f) + normalisedVal = 2.0f; + + bucketIdx = (uint)floor(normalisedVal*HGRAM_NUM_BUCKETS); + } + } +#else + { + float4 data = SampleTextureFloat4(texType, false, float2(x, y)/float2(texDim.xy), + HistogramSlice, HistogramMip, texDim); + + float divisor = 0.0f; + float sum = 0.0f; + if(HistogramChannels & 0x1) + { + sum += data.x; + divisor += 1.0f; + } + if(HistogramChannels & 0x2) + { + sum += data.y; + divisor += 1.0f; + } + if(HistogramChannels & 0x4) + { + sum += data.z; + divisor += 1.0f; + } + if(HistogramChannels & 0x8) + { + sum += data.w; + divisor += 1.0f; + } + + if(divisor > 0.0f) + { + float val = sum/divisor; + + float normalisedVal = (val - HistogramMin)/(HistogramMax - HistogramMin); + + if(normalisedVal < 0.0f) + normalisedVal = 2.0f; + + bucketIdx = (uint)floor(normalisedVal*HGRAM_NUM_BUCKETS); + } + } +#endif + + if(bucketIdx >= 0 && bucketIdx < HGRAM_NUM_BUCKETS) + InterlockedAdd(HistogramDest[bucketIdx], 1); + } + } +} + diff --git a/renderdoc/data/hlsl/multisample.hlsl b/renderdoc/data/hlsl/multisample.hlsl new file mode 100644 index 0000000000..75fd1ce871 --- /dev/null +++ b/renderdoc/data/hlsl/multisample.hlsl @@ -0,0 +1,214 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// when serialising out a multisampled texture to disk from the app we're capturing +// (or serialising it back in, for that matter), we copy each sample to a slice in a +// 2DArray texture, and vice-versa. These shaders do that copy as appropriate. + +struct wireframeV2F +{ + float4 pos : SV_Position; + float3 norm : Normal; + float3 color : COLOR; + float2 tex : TEXCOORD0; +}; + +cbuffer msarraycopyconsts : register(b0) +{ + uint sampleCount; + uint currentStencil; + uint currentSample; + uint currentSlice; +}; + +Texture2DMSArray sourceMS2 : register(t1); +Texture2DMSArray sourceMS4 : register(t2); +Texture2DMSArray sourceMS8 : register(t3); +Texture2DMSArray sourceMS16 : register(t4); +Texture2DMSArray sourceMS32 : register(t5); + +uint4 RENDERDOC_CopyMSToArray(wireframeV2F IN) : SV_Target0 +{ + uint3 srcCoord = uint3(IN.pos.x, IN.pos.y, currentSlice); + + if(sampleCount == 2) + { + return sourceMS2.Load(srcCoord, currentSample); + } + else if(sampleCount == 4) + { + return sourceMS4.Load(srcCoord, currentSample); + } + else if(sampleCount == 8) + { + return sourceMS8.Load(srcCoord, currentSample); + } + else if(sampleCount == 16) + { + return sourceMS16.Load(srcCoord, currentSample); + } + else if(sampleCount == 32) + { + return sourceMS32.Load(srcCoord, currentSample); + } + + return 0; +} + +Texture2DMSArray sourceFloatMS2 : register(t1); +Texture2DMSArray sourceFloatMS4 : register(t2); +Texture2DMSArray sourceFloatMS8 : register(t3); +Texture2DMSArray sourceFloatMS16 : register(t4); +Texture2DMSArray sourceFloatMS32 : register(t5); + +float4 RENDERDOC_FloatCopyMSToArray(wireframeV2F IN) : SV_Target0 +{ + uint3 srcCoord = uint3(IN.pos.x, IN.pos.y, currentSlice); + + if(sampleCount == 2) + { + return sourceFloatMS2.Load(srcCoord, currentSample); + } + else if(sampleCount == 4) + { + return sourceFloatMS4.Load(srcCoord, currentSample); + } + else if(sampleCount == 8) + { + return sourceFloatMS8.Load(srcCoord, currentSample); + } + else if(sampleCount == 16) + { + return sourceFloatMS16.Load(srcCoord, currentSample); + } + else if(sampleCount == 32) + { + return sourceFloatMS32.Load(srcCoord, currentSample); + } + + return 0; +} + +Texture2DMSArray sourceDepthMS2 : register(t1); +Texture2DMSArray sourceDepthMS4 : register(t2); +Texture2DMSArray sourceDepthMS8 : register(t3); +Texture2DMSArray sourceDepthMS16 : register(t4); +Texture2DMSArray sourceDepthMS32 : register(t5); + +Texture2DMSArray sourceStencilMS2 : register(t11); +Texture2DMSArray sourceStencilMS4 : register(t12); +Texture2DMSArray sourceStencilMS8 : register(t13); +Texture2DMSArray sourceStencilMS16 : register(t14); +Texture2DMSArray sourceStencilMS32 : register(t15); + +float RENDERDOC_DepthCopyMSToArray(wireframeV2F IN) : SV_Depth +{ + uint3 srcCoord = uint3(IN.pos.x, IN.pos.y, currentSlice); + + if(currentStencil < 256) + { + if(sampleCount == 2) + { + if(sourceStencilMS2.Load(srcCoord, currentSample).y != currentStencil) + discard; + } + else if(sampleCount == 4) + { + if(sourceStencilMS4.Load(srcCoord, currentSample).y != currentStencil) + discard; + } + else if(sampleCount == 8) + { + if(sourceStencilMS8.Load(srcCoord, currentSample).y != currentStencil) + discard; + } + else if(sampleCount == 16) + { + if(sourceStencilMS16.Load(srcCoord, currentSample).y != currentStencil) + discard; + } + else if(sampleCount == 32) + { + if(sourceStencilMS32.Load(srcCoord, currentSample).y != currentStencil) + discard; + } + } + + if(sampleCount == 2) + { + return sourceDepthMS2.Load(srcCoord, currentSample).x; + } + else if(sampleCount == 4) + { + return sourceDepthMS4.Load(srcCoord, currentSample).x; + } + else if(sampleCount == 8) + { + return sourceDepthMS8.Load(srcCoord, currentSample).x; + } + else if(sampleCount == 16) + { + return sourceDepthMS16.Load(srcCoord, currentSample).x; + } + else if(sampleCount == 32) + { + return sourceDepthMS32.Load(srcCoord, currentSample).x; + } + + return 0; +} + +Texture2DArray sourceArray : register(t0); + +uint4 RENDERDOC_CopyArrayToMS(wireframeV2F IN, uint curSample : SV_SampleIndex) : SV_Target0 +{ + uint4 srcCoord = uint4(IN.pos.x, IN.pos.y, currentSlice*sampleCount + curSample, 0); + + return sourceArray.Load(srcCoord); +} + +Texture2DArray sourceFloatArray : register(t0); + +float4 RENDERDOC_FloatCopyArrayToMS(wireframeV2F IN, uint curSample : SV_SampleIndex) : SV_Target0 +{ + uint4 srcCoord = uint4(IN.pos.x, IN.pos.y, currentSlice*sampleCount + curSample, 0); + + return sourceFloatArray.Load(srcCoord); +} + +Texture2DArray sourceDepthArray : register(t0); +Texture2DArray sourceStencilArray : register(t1); + +float RENDERDOC_DepthCopyArrayToMS(wireframeV2F IN, uint curSample : SV_SampleIndex) : SV_Depth +{ + uint4 srcCoord = uint4(IN.pos.x, IN.pos.y, currentSlice*sampleCount + curSample, 0); + + if(currentStencil < 1000) + { + if(sourceStencilArray.Load(srcCoord).y != currentStencil) + discard; + } + + return sourceDepthArray.Load(srcCoord).x; +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc new file mode 100644 index 0000000000..b77caaa7f4 --- /dev/null +++ b/renderdoc/data/renderdoc.rc @@ -0,0 +1,129 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define IDC_STATIC -1 +#include + + + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define IDC_STATIC -1\r\n" + "#include \r\n" + "\r\n" + "\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United Kingdom) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RENDERDOC_VERSION_MAJOR,RENDERDOC_VERSION_MINOR,0,0 + PRODUCTVERSION RENDERDOC_VERSION_MAJOR,RENDERDOC_VERSION_MINOR,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "CompanyName", "Crytek" + VALUE "FileDescription", "Core DLL for RenderDoc - http://renderdoc.org/" + VALUE "FileVersion", RENDERDOC_VERSION_STRING ".0.0" + VALUE "InternalName", "renderdoc.dll" + VALUE "LegalCopyright", "Copyright © 2014 Crytek" + VALUE "OriginalFilename", "renderdoc.dll" + VALUE "ProductName", "RenderDoc" + VALUE "ProductVersion", RENDERDOC_VERSION_STRING ".0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // English (United Kingdom) resources +///////////////////////////////////////////////////////////////////////////// + +RESOURCE_debugdisplay_hlsl TYPE_EMBED "hlsl/debugdisplay.hlsl" +RESOURCE_debugtext_hlsl TYPE_EMBED "hlsl/debugtext.hlsl" +RESOURCE_debugcommon_hlsl TYPE_EMBED "hlsl/debugcommon.hlsl" +RESOURCE_histogram_hlsl TYPE_EMBED "hlsl/histogram.hlsl" +RESOURCE_debugcbuffers_h TYPE_EMBED "hlsl/debugcbuffers.h" +RESOURCE_multisample_hlsl TYPE_EMBED "hlsl/multisample.hlsl" + +RESOURCE_blit_vert TYPE_EMBED "glsl/blit.vert" +RESOURCE_blit_frag TYPE_EMBED "glsl/blit.frag" +RESOURCE_texdisplay_frag TYPE_EMBED "glsl/texdisplay.frag" +RESOURCE_checkerboard_frag TYPE_EMBED "glsl/checkerboard.frag" +RESOURCE_generic_vert TYPE_EMBED "glsl/generic.vert" +RESOURCE_generic_frag TYPE_EMBED "glsl/generic.frag" +RESOURCE_mesh_vert TYPE_EMBED "glsl/mesh.vert" + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h new file mode 100644 index 0000000000..05b771a8b2 --- /dev/null +++ b/renderdoc/data/resource.h @@ -0,0 +1,43 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by renderdoc.rc +// +#define TYPE_EMBED 256 + +#define RESOURCE_debugdisplay_hlsl 101 +#define RESOURCE_debugtext_hlsl 102 +#define RESOURCE_debugcbuffers_h 103 +#define RESOURCE_debugcommon_hlsl 104 +#define RESOURCE_histogram_hlsl 105 +#define RESOURCE_multisample_hlsl 106 + +#define RESOURCE_blit_vert 201 +#define RESOURCE_blit_frag 202 +#define RESOURCE_texdisplay_frag 203 +#define RESOURCE_checkerboard_frag 204 +#define RESOURCE_generic_vert 205 +#define RESOURCE_generic_frag 206 +#define RESOURCE_mesh_vert 207 + +#if !defined(STRINGIZE) +#define STRINGIZE2(a) #a +#define STRINGIZE(a) STRINGIZE2(a) +#endif + +#define RENDERDOC_VERSION_MAJOR 0 +#define RENDERDOC_VERSION_MINOR 20 +#define GIT_COMMIT_HASH "NO_GIT_COMMIT_HASH_DEFINED" +//#define RENDERDOC_OFFICIAL_BUILD // used to determine whether to submit auto crash reports +#define RENDERDOC_VERSION_STRING STRINGIZE(RENDERDOC_VERSION_MAJOR) "." STRINGIZE(RENDERDOC_VERSION_MINOR) +#define RENDERDOC_VERSION_STRING_W WIDEN(STRINGIZE(RENDERDOC_VERSION_MAJOR)) L"." WIDEN(STRINGIZE(RENDERDOC_VERSION_MINOR)) + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_COMMAND_VALUE 40029 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp new file mode 100644 index 0000000000..8fefe6265f --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -0,0 +1,2688 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "maths/vec.h" +#include "d3d11_manager.h" +#include "d3d11_context.h" +#include "d3d11_debug.h" +#include "shaders/dxbc_debug.h" +#include "maths/formatpacking.h" +#include "data/resource.h" +#include "serialise/serialiser.h" +#include "common/string_utils.h" + +#include "driver/d3d11/d3d11_resources.h" +#include "driver/d3d11/d3d11_renderstate.h" + +void D3D11DebugManager::FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, + const vector &invars, vector &outvars, + const vector &data) +{ + using namespace DXBC; + using namespace ShaderDebug; + + size_t o = offset; + + for(size_t v=0; v < invars.size(); v++) + { + size_t vec = o + invars[v].descriptor.offset/16; + size_t comp = (invars[v].descriptor.offset - (invars[v].descriptor.offset&~0xf))/4; + size_t sz = RDCMAX(1U, invars[v].type.descriptor.bytesize/16); + + offset = vec + sz; + + string basename = prefix + invars[v].name; + + uint32_t rows = invars[v].type.descriptor.rows; + uint32_t cols = invars[v].type.descriptor.cols; + uint32_t elems = RDCMAX(1U,invars[v].type.descriptor.elements); + + if(!invars[v].type.members.empty()) + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "[%d]", elems); + + ShaderVariable var; + var.name = basename; + var.rows = var.columns = 0; + var.type = eVar_Float; + + std::vector varmembers; + + if(elems > 1) + { + for(uint32_t i=0; i < elems; i++) + { + StringFormat::snprintf(buf, 63, "[%d]", i); + + if(flatten) + { + FillCBufferVariables(basename + buf + ".", vec, flatten, invars[v].type.members, outvars, data); + } + else + { + ShaderVariable vr; + vr.name = basename + buf; + vr.rows = vr.columns = 0; + vr.type = eVar_Float; + + std::vector mems; + + FillCBufferVariables("", vec, flatten, invars[v].type.members, mems, data); + + vr.members = mems; + + varmembers.push_back(vr); + } + } + } + else + { + if(flatten) + FillCBufferVariables(basename + ".", vec, flatten, invars[v].type.members, outvars, data); + else + FillCBufferVariables("", vec, flatten, invars[v].type.members, varmembers, data); + } + + if(!flatten) + { + var.members = varmembers; + outvars.push_back(var); + } + + continue; + } + + size_t elemByteSize = 4; + VarType type = eVar_Float; + switch(invars[v].type.descriptor.type) + { + case VARTYPE_INT: + type = eVar_Int; + break; + case VARTYPE_FLOAT: + type = eVar_Float; + break; + case VARTYPE_BOOL: + case VARTYPE_UINT: + case VARTYPE_UINT8: + type = eVar_UInt; + break; + case VARTYPE_DOUBLE: + elemByteSize = 8; + type = eVar_Double; + break; + default: + RDCFATAL("Unexpected type in constant buffer"); + } + + bool columnMajor = invars[v].type.descriptor.varClass == CLASS_MATRIX_COLUMNS; + + size_t outIdx = vec; + if(!flatten) + { + outIdx = outvars.size(); + outvars.resize(RDCMAX(outIdx+1, outvars.size())); + } + else + { + if(columnMajor) + outvars.resize(RDCMAX(outIdx+cols*elems, outvars.size())); + else + outvars.resize(RDCMAX(outIdx+rows*elems, outvars.size())); + } + + size_t dataOffset = vec*16 + comp*4; + + if(outvars[outIdx].name.count > 0) + { + RDCASSERT(flatten); + + RDCASSERT(outvars[vec].rows == 1); + RDCASSERT(outvars[vec].columns == comp); + RDCASSERT(rows == 1); + + string combinedName = outvars[outIdx].name.elems; + combinedName += ", " + basename; + outvars[outIdx].name = combinedName; + outvars[outIdx].rows = 1; + outvars[outIdx].columns += cols; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&outvars[outIdx].value.uv[comp], d, RDCMIN(data.size()-dataOffset, elemByteSize*cols)); + } + } + else + { + outvars[outIdx].name = basename; + outvars[outIdx].rows = 1; + outvars[outIdx].type = type; + outvars[outIdx].columns = cols; + + ShaderVariable &var = outvars[outIdx]; + + bool isArray = invars[v].type.descriptor.elements > 1; + + if(rows*elems == 1) + { + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&outvars[outIdx].value.uv[flatten ? comp : 0], d, RDCMIN(data.size()-dataOffset, elemByteSize*cols)); + } + } + else if(!isArray && !flatten) + { + outvars[outIdx].rows = rows; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + RDCASSERT(rows <= 4 && rows*cols <= 16); + + if(columnMajor) + { + uint32_t tmp[16] = {0}; + memcpy(tmp, d, RDCMIN(data.size()-dataOffset, elemByteSize*rows*cols)); + + // transpose + for(size_t r=0; r < rows; r++) + for(size_t c=0; c < cols; c++) + outvars[outIdx].value.uv[r*cols+c] = tmp[c*rows+r]; + } + else // CLASS_MATRIX_ROWS or other data not to transpose. + { + memcpy(&outvars[outIdx].value.uv[0], d, RDCMIN(data.size()-dataOffset, elemByteSize*rows*cols)); + } + } + } + else if(rows*elems > 1) + { + char buf[64] = {0}; + + var.name = outvars[outIdx].name; + + vector varmembers; + vector *out = &outvars; + size_t rowCopy = 1; + + uint32_t registers = rows; + uint32_t regLen = cols; + const char *regName = "row"; + + if(!flatten) + { + var.rows = 0; + var.columns = 0; + outIdx = 0; + out = &varmembers; + varmembers.resize(elems); + rowCopy = rows; + rows = 1; + registers = 1; + } + else + { + if(columnMajor) + { + registers = cols; + regLen = rows; + regName = "col"; + } + } + + string base = outvars[outIdx].name.elems; + + for(size_t r=0; r < registers*elems; r++) + { + if(isArray && registers > 1) + StringFormat::snprintf(buf, 63, "[%d].%hs%d", r/registers, regName, r%registers); + else if(registers > 1) + StringFormat::snprintf(buf, 63, ".%hs%d", regName, r); + else + StringFormat::snprintf(buf, 63, "[%d]", r); + + (*out)[outIdx+r].name = base + buf; + (*out)[outIdx+r].rows = (uint32_t)rowCopy; + (*out)[outIdx+r].type = type; + (*out)[outIdx+r].columns = regLen; + + size_t dataOffset = (vec+r*rowCopy)*16; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&((*out)[outIdx+r].value.uv[0]), d, RDCMIN(data.size()-dataOffset, elemByteSize*rowCopy*regLen)); + + if(!flatten && columnMajor) + { + ShaderVariable tmp = (*out)[outIdx]; + // transpose + for(size_t r=0; r < rows; r++) + for(size_t c=0; c < cols; c++) + (*out)[outIdx].value.uv[r*cols+c] = tmp.value.uv[c*rows+r]; + } + } + } + + if(!flatten) + var.members = varmembers; + } + } + } +} + +void D3D11DebugManager::FillCBufferVariables(const vector &invars, vector &outvars, + bool flattenVec4s, const vector &data) +{ + size_t zero = 0; + + vector v; + FillCBufferVariables("", zero, flattenVec4s, invars, v, data); + + outvars.reserve(v.size()); + for(size_t i=0; i < v.size(); i++) + outvars.push_back(v[i]); +} + +ShaderDebug::State D3D11DebugManager::CreateShaderDebugState(ShaderDebugTrace &trace, int quadIdx, DXBC::DXBCFile *dxbc, vector *cbufData) +{ + using namespace DXBC; + using namespace ShaderDebug; + + State initialState = State(quadIdx, &trace, dxbc, m_WrappedDevice); + + // use pixel shader here to get inputs + + uint32_t maxReg = 0; + for(size_t i=0; i < dxbc->m_InputSig.size(); i++) + maxReg = RDCMAX(maxReg, dxbc->m_InputSig[i].regIndex); + + create_array(trace.inputs, maxReg+1); + for(size_t i=0; i < dxbc->m_InputSig.size(); i++) + { + char buf[64] = {0}; + + SigParameter &sig = dxbc->m_InputSig[i]; + + StringFormat::snprintf(buf, 63, "v%d", sig.regIndex); + + ShaderVariable v; + + v.name = StringFormat::Fmt("%hs (%hs)", buf, sig.semanticIdxName.elems); + v.rows = 1; + v.columns = + sig.regChannelMask & 0x8 ? 4 : + sig.regChannelMask & 0x4 ? 3 : + sig.regChannelMask & 0x2 ? 2 : + sig.regChannelMask & 0x1 ? 1 : + 0; + + if(sig.compType == eCompType_UInt) + v.type = eVar_UInt; + else if(sig.compType == eCompType_SInt) + v.type = eVar_Int; + + if(trace.inputs[sig.regIndex].columns == 0) + trace.inputs[sig.regIndex] = v; + else + trace.inputs[sig.regIndex].columns = RDCMAX(trace.inputs[sig.regIndex].columns, v.columns); + } + + uint32_t specialOutputs = 0; + maxReg = 0; + for(size_t i=0; i < dxbc->m_OutputSig.size(); i++) + { + if(dxbc->m_OutputSig[i].regIndex == ~0U) + specialOutputs++; + else + maxReg = RDCMAX(maxReg, dxbc->m_OutputSig[i].regIndex); + } + + create_array(initialState.outputs, maxReg+1 + specialOutputs); + for(size_t i=0; i < dxbc->m_OutputSig.size(); i++) + { + SigParameter &sig = dxbc->m_OutputSig[i]; + + if(sig.regIndex == ~0U) + continue; + + char buf[64] = {0}; + + StringFormat::snprintf(buf, 63, "o%d", sig.regIndex); + + ShaderVariable v; + + v.name = StringFormat::Fmt("%hs (%hs)", buf, sig.semanticIdxName.elems); + v.rows = 1; + v.columns = + sig.regChannelMask & 0x8 ? 4 : + sig.regChannelMask & 0x4 ? 3 : + sig.regChannelMask & 0x2 ? 2 : + sig.regChannelMask & 0x1 ? 1 : + 0; + + if(initialState.outputs[sig.regIndex].columns == 0) + initialState.outputs[sig.regIndex] = v; + else + initialState.outputs[sig.regIndex].columns = RDCMAX(initialState.outputs[sig.regIndex].columns, v.columns); + } + + for(size_t i=0; i < dxbc->m_OutputSig.size(); i++) + { + SigParameter &sig = dxbc->m_OutputSig[i]; + + if(sig.regIndex != ~0U) + continue; + + ShaderVariable v; + + if(sig.systemValue == eAttr_OutputControlPointIndex) v.name = "vOutputControlPointID"; + else if(sig.systemValue == eAttr_DepthOutput) v.name = "oDepth"; + else if(sig.systemValue == eAttr_DepthOutputLessEqual) v.name = "oDepthLessEqual"; + else if(sig.systemValue == eAttr_DepthOutputGreaterEqual) v.name = "oDepthGreaterEqual"; + else if(sig.systemValue == eAttr_MSAACoverage) v.name = "oMask"; + //if(sig.systemValue == TYPE_OUTPUT_CONTROL_POINT) str = "oOutputControlPoint"; + else + { + RDCERR("Unhandled output: %hs (%d)", sig.semanticName, sig.systemValue); + continue; + } + + v.rows = 1; + v.columns = + sig.regChannelMask & 0x8 ? 4 : + sig.regChannelMask & 0x4 ? 3 : + sig.regChannelMask & 0x2 ? 2 : + sig.regChannelMask & 0x1 ? 1 : + 0; + + initialState.outputs[maxReg+i] = v; + } + + create_array(trace.cbuffers, dxbc->m_CBuffers.size()); + for(size_t i=0; i < dxbc->m_CBuffers.size(); i++) + { + if(dxbc->m_CBuffers[i].descriptor.type != CBuffer::Descriptor::TYPE_CBUFFER) + continue; + + vector vars; + + FillCBufferVariables(dxbc->m_CBuffers[i].variables, vars, true, cbufData[i]); + + trace.cbuffers[i] = vars; + + for(int32_t c=0; c < trace.cbuffers[i].count; c++) + trace.cbuffers[i][c].name = StringFormat::Fmt("cb%u[%u] (%hs)", (uint32_t)i, (uint32_t)c, trace.cbuffers[i][c].name.elems); + } + + initialState.Init(); + + return initialState; +} + +void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global, uint32_t UAVStartSlot, ID3D11UnorderedAccessView **UAVs, ID3D11ShaderResourceView **SRVs) +{ + for(int i=0; UAVs != NULL && i+UAVStartSlot < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + int dsti = i+UAVStartSlot; + if(UAVs[i]) + { + ID3D11Resource *res = NULL; + UAVs[i]->GetResource(&res); + + global.uavs[dsti].hiddenCounter = GetStructCount(UAVs[i]); + + D3D11_UNORDERED_ACCESS_VIEW_DESC udesc; + UAVs[i]->GetDesc(&udesc); + + if(udesc.Format != DXGI_FORMAT_UNKNOWN) + { + ResourceFormat fmt = MakeResourceFormat(udesc.Format); + + global.uavs[dsti].format.byteWidth = fmt.compByteWidth; + global.uavs[dsti].format.numComps = fmt.compCount; + global.uavs[dsti].format.fmt = fmt.compType; + + if(udesc.Format == DXGI_FORMAT_R11G11B10_FLOAT) + global.uavs[dsti].format.byteWidth = 11; + if(udesc.Format == DXGI_FORMAT_R10G10B10A2_UINT || udesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) + global.uavs[dsti].format.byteWidth = 10; + } + + if(udesc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER) + { + global.uavs[dsti].firstElement = udesc.Buffer.FirstElement; + global.uavs[dsti].numElements = udesc.Buffer.NumElements; + } + + if(res) + { + if(WrappedID3D11Buffer::IsAlloc(res)) + { + global.uavs[dsti].data = GetBufferData((ID3D11Buffer *)res, 0, 0); + } + else + { + RDCERR("UAVs of textures currently not supported in shader debugging"); + } + } + + SAFE_RELEASE(res); + } + } + + for(int i=0; SRVs != NULL && i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + { + if(SRVs[i]) + { + ID3D11Resource *res = NULL; + SRVs[i]->GetResource(&res); + + D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; + SRVs[i]->GetDesc(&sdesc); + + if(sdesc.Format != DXGI_FORMAT_UNKNOWN) + { + ResourceFormat fmt = MakeResourceFormat(sdesc.Format); + + global.srvs[i].format.byteWidth = fmt.compByteWidth; + global.srvs[i].format.numComps = fmt.compCount; + global.srvs[i].format.fmt = fmt.compType; + + if(sdesc.Format == DXGI_FORMAT_R11G11B10_FLOAT) + global.srvs[i].format.byteWidth = 11; + if(sdesc.Format == DXGI_FORMAT_R10G10B10A2_UINT || sdesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) + global.srvs[i].format.byteWidth = 10; + } + + if(sdesc.ViewDimension == D3D11_SRV_DIMENSION_BUFFER) + { + // I know this isn't what the docs say, but as best as I can tell + // this is how it's used. + global.srvs[i].firstElement = sdesc.Buffer.FirstElement; + global.srvs[i].numElements = sdesc.Buffer.NumElements; + } + else if(sdesc.ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) + { + global.srvs[i].firstElement = sdesc.BufferEx.FirstElement; + global.srvs[i].numElements = sdesc.BufferEx.NumElements; + } + + if(res) + { + if(WrappedID3D11Buffer::IsAlloc(res)) + { + global.srvs[i].data = GetBufferData((ID3D11Buffer *)res, 0, 0); + } + } + + SAFE_RELEASE(res); + } + } +} + +// struct that saves pointers as we iterate through to where we ultimately +// want to copy the data to +struct DataOutput +{ + DataOutput(int regster, int element, int numWords) { reg = regster; elem = element; numwords = numWords; } + + int reg; + int elem; + + int numwords; +}; + +struct DebugHit +{ + uint32_t numHits; + float posx; float posy; + float depth; + uint32_t primitive; + uint32_t rawdata; // arbitrary, depending on shader +}; + +ShaderDebugTrace D3D11DebugManager::DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) +{ + using namespace DXBC; + using namespace ShaderDebug; + + ShaderDebugTrace empty; + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw); + + ID3D11VertexShader *stateVS = NULL; + m_WrappedContext->VSGetShader(&stateVS, NULL, NULL); + + WrappedID3D11Shader *vs = (WrappedID3D11Shader *)stateVS; + + SAFE_RELEASE(stateVS); + + if(!vs) + return empty; + + DXBCFile *dxbc = vs->GetDXBC(); + + if(!dxbc) + return empty; + + D3D11RenderState *rs = m_WrappedContext->GetCurrentPipelineState(); + + vector inputlayout = m_WrappedDevice->GetLayoutDesc(rs->IA.Layout); + + set vertexbuffers; + uint32_t trackingOffs[32] = {0}; + + // need special handling for other step rates + for(size_t i=0; i < inputlayout.size(); i++) + { + RDCASSERT(inputlayout[i].InstanceDataStepRate <= 1); + + UINT slot = RDCCLAMP(inputlayout[i].InputSlot, 0U, UINT(D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT-1)); + + vertexbuffers.insert(slot); + + if(inputlayout[i].AlignedByteOffset == ~0U) + { + inputlayout[i].AlignedByteOffset = trackingOffs[slot]; + } + else + { + trackingOffs[slot] = inputlayout[i].AlignedByteOffset; + } + + ResourceFormat fmt = MakeResourceFormat(inputlayout[i].Format); + + trackingOffs[slot] += fmt.compByteWidth * fmt.compCount; + } + + vector vertData[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + vector instData[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + + for(auto it=vertexbuffers.begin(); it != vertexbuffers.end(); ++it) + { + UINT i = *it; + if(rs->IA.VBs[i]) + { + vertData[i] = GetBufferData(rs->IA.VBs[i], rs->IA.Offsets[i] + rs->IA.Strides[i]*(vertOffset+idx), rs->IA.Strides[i]); + instData[i] = GetBufferData(rs->IA.VBs[i], rs->IA.Offsets[i] + rs->IA.Strides[i]*(instOffset+instid), rs->IA.Strides[i]); + } + } + + vector cbufData[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + if(rs->VS.ConstantBuffers[i]) + cbufData[i] = GetBufferData(rs->VS.ConstantBuffers[i], rs->VS.CBOffsets[i]*sizeof(Vec4f), 0); + + ShaderDebugTrace ret; + + GlobalState global; + CreateShaderGlobalState(global, 0, NULL, rs->VS.SRVs); + State initialState = CreateShaderDebugState(ret, -1, dxbc, cbufData); + + for(int32_t i=0; i < ret.inputs.count; i++) + { + if(dxbc->m_InputSig[i].systemValue == eAttr_None || + dxbc->m_InputSig[i].systemValue == eAttr_Position) // SV_Position seems to get promoted automatically, but it's invalid for vertex input + { + const D3D11_INPUT_ELEMENT_DESC *el = NULL; + + string signame = strlower(string(dxbc->m_InputSig[i].semanticName.elems)); + + for(size_t l=0; l < inputlayout.size(); l++) + { + string layoutname = strlower(string(inputlayout[l].SemanticName)); + + if(signame == layoutname && + dxbc->m_InputSig[i].semanticIndex == inputlayout[l].SemanticIndex) + { + el = &inputlayout[l]; + break; + } + if(signame == layoutname + ToStr::Get(inputlayout[l].SemanticIndex)) + { + el = &inputlayout[l]; + break; + } + } + + RDCASSERT(el); + + if(!el) + continue; + + byte *srcData = NULL; + size_t dataSize = 0; + + if(el->InputSlotClass == D3D11_INPUT_PER_VERTEX_DATA) + { + if(vertData[el->InputSlot].size() >= el->AlignedByteOffset) + { + srcData = &vertData[el->InputSlot][el->AlignedByteOffset]; + dataSize = vertData[el->InputSlot].size()-el->AlignedByteOffset; + } + } + else + { + if(instData[el->InputSlot].size() >= el->AlignedByteOffset) + { + srcData = &instData[el->InputSlot][el->AlignedByteOffset]; + dataSize = instData[el->InputSlot].size()-el->AlignedByteOffset; + } + } + + ResourceFormat fmt = MakeResourceFormat(el->Format); + + // more data needed than is provided + if(dxbc->m_InputSig[i].compCount > fmt.compCount) + { + ret.inputs[i].value.u.w = 1; + + if(fmt.compType == eCompType_Float) + ret.inputs[i].value.f.w = 1.0f; + } + + // interpret special formats + if(fmt.special) + { + Vec3f *v3 = (Vec3f *)ret.inputs[i].value.fv; + Vec4f *v4 = (Vec4f *)ret.inputs[i].value.fv; + + // only pull in all or nothing from these, + // if there's only e.g. 3 bytes remaining don't read and unpack some of + // a 4-byte special format + size_t packedsize = 4; + if (fmt.specialFormat == eSpecial_B8G8R8A8 || fmt.specialFormat == eSpecial_B5G5R5A1 || + fmt.specialFormat == eSpecial_B5G6R5 || fmt.specialFormat == eSpecial_B4G4R4A4) + packedsize = 2; + + if(srcData == NULL || packedsize > dataSize) + { + ret.inputs[i].value.u.x = + ret.inputs[i].value.u.y = + ret.inputs[i].value.u.z = + ret.inputs[i].value.u.w = 0; + } + else if (fmt.specialFormat == eSpecial_B8G8R8A8) + { + ret.inputs[i].value.f.x = float(srcData[2])/255.0f; + ret.inputs[i].value.f.y = float(srcData[1])/255.0f; + ret.inputs[i].value.f.z = float(srcData[0])/255.0f; + ret.inputs[i].value.f.w = float(srcData[3])/255.0f; + } + else if (fmt.specialFormat == eSpecial_B5G5R5A1) + { + uint16_t packed = ((uint16_t *)srcData)[0]; + *v4 = ConvertFromB5G5R5A1(packed); + } + else if (fmt.specialFormat == eSpecial_B5G6R5) + { + uint16_t packed = ((uint16_t *)srcData)[0]; + *v3 = ConvertFromB5G6R5(packed); + } + else if (fmt.specialFormat == eSpecial_B4G4R4A4) + { + uint16_t packed = ((uint16_t *)srcData)[0]; + *v4 = ConvertFromB4G4R4A4(packed); + } + else if (fmt.specialFormat == eSpecial_R10G10B10A2) + { + uint32_t packed = ((uint32_t *)srcData)[0]; + + if (fmt.compType == eCompType_UInt) + { + ret.inputs[i].value.u.z = (packed >> 0) & 0x3ff; + ret.inputs[i].value.u.y = (packed >> 10) & 0x3ff; + ret.inputs[i].value.u.x = (packed >> 20) & 0x3ff; + ret.inputs[i].value.u.w = (packed >> 30) & 0x003; + } + else + { + *v4 = ConvertFromR10G10B10A2(packed); + } + } + else if (fmt.special && fmt.specialFormat == eSpecial_R11G11B10) + { + uint32_t packed = ((uint32_t *)srcData)[0]; + *v3 = ConvertFromR11G11B10(packed); + } + } + else + { + for(uint32_t c=0; c < fmt.compCount; c++) + { + if(srcData == NULL || fmt.compByteWidth > dataSize) + { + ret.inputs[i].value.uv[c] = 0; + continue; + } + + dataSize -= fmt.compByteWidth; + + if(fmt.compByteWidth == 1) + { + byte *src = srcData+c*fmt.compByteWidth; + + if(fmt.compType == eCompType_UInt) + ret.inputs[i].value.uv[c] = *src; + else if(fmt.compType == eCompType_SInt) + ret.inputs[i].value.iv[c] = *((int8_t *)src); + else if(fmt.compType == eCompType_UNorm) + ret.inputs[i].value.fv[c] = float(*src)/255.0f; + else if(fmt.compType == eCompType_SNorm) + { + signed char *schar = (signed char *)src; + + // -128 is mapped to -1, then -127 to -127 are mapped to -1 to 1 + if(*schar == -128) + ret.inputs[i].value.fv[c] = -1.0f; + else + ret.inputs[i].value.fv[c] = float(*schar)/127.0f; + } + else + RDCERR("Unexpected component type"); + } + else if(fmt.compByteWidth == 2) + { + uint16_t *src = (uint16_t *)(srcData+c*fmt.compByteWidth); + + if(fmt.compType == eCompType_Float) + ret.inputs[i].value.fv[c] = ConvertFromHalf(*src); + else if(fmt.compType == eCompType_UInt) + ret.inputs[i].value.uv[c] = *src; + else if(fmt.compType == eCompType_SInt) + ret.inputs[i].value.iv[c] = *((int16_t *)src); + else if(fmt.compType == eCompType_UNorm) + ret.inputs[i].value.fv[c] = float(*src)/float(UINT16_MAX); + else if(fmt.compType == eCompType_SNorm) + { + int16_t *sint = (int16_t *)src; + + // -32768 is mapped to -1, then -32767 to -32767 are mapped to -1 to 1 + if(*sint == -32768) + ret.inputs[i].value.fv[c] = -1.0f; + else + ret.inputs[i].value.fv[c] = float(*sint)/32767.0f; + } + else + RDCERR("Unexpected component type"); + } + else if(fmt.compByteWidth == 4) + { + uint32_t *src = (uint32_t *)(srcData+c*fmt.compByteWidth); + + if(fmt.compType == eCompType_Float || + fmt.compType == eCompType_UInt || + fmt.compType == eCompType_SInt) + memcpy(&ret.inputs[i].value.uv[c], src, 4); + else + RDCERR("Unexpected component type"); + } + } + } + } + else if(dxbc->m_InputSig[i].systemValue == eAttr_VertexIndex) + { + if(dxbc->m_InputSig[i].compType == eCompType_Float) + ret.inputs[i].value.f.x = + ret.inputs[i].value.f.y = + ret.inputs[i].value.f.z = + ret.inputs[i].value.f.w = (float)vertid; + else + ret.inputs[i].value.u.x = + ret.inputs[i].value.u.y = + ret.inputs[i].value.u.z = + ret.inputs[i].value.u.w = vertid; + } + else if(dxbc->m_InputSig[i].systemValue == eAttr_InstanceIndex) + { + if(dxbc->m_InputSig[i].compType == eCompType_Float) + ret.inputs[i].value.f.x = + ret.inputs[i].value.f.y = + ret.inputs[i].value.f.z = + ret.inputs[i].value.f.w = (float)instid; + else + ret.inputs[i].value.u.x = + ret.inputs[i].value.u.y = + ret.inputs[i].value.u.z = + ret.inputs[i].value.u.w = instid; + } + else + { + RDCERR("Unhandled system value semantic on VS input"); + } + } + + State last; + + vector states; + + states.push_back((State)initialState); + + while(true) + { + if(initialState.Finished()) + break; + + initialState = initialState.GetNext(global, NULL); + + states.push_back((State)initialState); + } + + ret.states = states; + + return ret; +} + +ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) +{ + using namespace DXBC; + using namespace ShaderDebug; + + ShaderDebugTrace empty; + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw); + + ID3D11PixelShader *statePS = NULL; + m_WrappedContext->PSGetShader(&statePS, NULL, NULL); + + WrappedID3D11Shader *ps = (WrappedID3D11Shader *)statePS; + + SAFE_RELEASE(statePS); + + if(!ps) + return empty; + + D3D11RenderState *rs = m_WrappedContext->GetCurrentPipelineState(); + + DXBCFile *dxbc = ps->GetDXBC(); + + if(!dxbc) + return empty; + + vector initialValues; + + string extractHlsl = "struct PSInput\n{\n"; + + int structureStride = 0; + + if(dxbc->m_InputSig.empty()) + { + extractHlsl += "float4 input_dummy : SV_Position;\n"; + + initialValues.push_back(DataOutput(-1, 0, 4)); + + structureStride += 4; + } + + vector floatInputs; + + for(size_t i=0; i < dxbc->m_InputSig.size(); i++) + { + extractHlsl += " "; + if(dxbc->m_InputSig[i].compType == eCompType_Float) + extractHlsl += "float"; + else if(dxbc->m_InputSig[i].compType == eCompType_SInt) + extractHlsl += "int"; + else if(dxbc->m_InputSig[i].compType == eCompType_UInt) + extractHlsl += "uint"; + else + RDCERR("Unexpected input signature type: %d", dxbc->m_InputSig[i].compType); + + int numCols = + (dxbc->m_InputSig[i].regChannelMask & 0x1 ? 1 : 0) + + (dxbc->m_InputSig[i].regChannelMask & 0x2 ? 1 : 0) + + (dxbc->m_InputSig[i].regChannelMask & 0x4 ? 1 : 0) + + (dxbc->m_InputSig[i].regChannelMask & 0x8 ? 1 : 0); + + structureStride += 4*numCols; + + string name = dxbc->m_InputSig[i].semanticIdxName.elems; + + extractHlsl += ToStr::Get((uint32_t)numCols) + " input_" + name + " : " + name; + + if(dxbc->m_InputSig[i].compType == eCompType_Float) + floatInputs.push_back("input_" + name); + + extractHlsl += ";\n"; + + int firstElem = + dxbc->m_InputSig[i].regChannelMask & 0x1 ? 0 : + dxbc->m_InputSig[i].regChannelMask & 0x2 ? 1 : + dxbc->m_InputSig[i].regChannelMask & 0x4 ? 2 : + dxbc->m_InputSig[i].regChannelMask & 0x8 ? 3 : + -1; + + initialValues.push_back(DataOutput(dxbc->m_InputSig[i].regIndex, firstElem, numCols)); + } + + extractHlsl += "};\n\n"; + + uint32_t overdrawLevels = 100; // maximum number of overdraw levels + + extractHlsl += "struct PSInitialData { uint hit; float3 pos; uint prim; PSInput IN; float derivValid; PSInput INddx; PSInput INddy; };\n\n"; + extractHlsl += "RWStructuredBuffer PSInitialBuffer : register(u0);\n\n"; + extractHlsl += "void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim : SV_PrimitiveID)\n{\n"; + extractHlsl += "if(abs(debug_pixelPos.x - " + ToStr::Get(x) + ".5) < 2 && abs(debug_pixelPos.y - " + ToStr::Get(y) + ".5) < 2) {\n"; + extractHlsl += "uint idx = 0;\n"; + extractHlsl += "InterlockedAdd(PSInitialBuffer[0].hit, 1, idx);\n"; + extractHlsl += "if(idx < " + ToStr::Get(overdrawLevels) + ") {\n"; + extractHlsl += "PSInitialBuffer[idx].pos = debug_pixelPos.xyz;\n"; + extractHlsl += "PSInitialBuffer[idx].prim = prim;\n"; + extractHlsl += "PSInitialBuffer[idx].IN = IN;\n"; + extractHlsl += "PSInitialBuffer[idx].derivValid = ddx(debug_pixelPos.x);\n"; + extractHlsl += "PSInitialBuffer[idx].INddx = (PSInput)0;\n"; + extractHlsl += "PSInitialBuffer[idx].INddy = (PSInput)0;\n"; + for(size_t i=0; i < floatInputs.size(); i++) + { + const string &name = floatInputs[i]; + extractHlsl += "PSInitialBuffer[idx].INddx." + name + " = ddx(IN." + name + ");\n"; + extractHlsl += "PSInitialBuffer[idx].INddy." + name + " = ddy(IN." + name + ");\n"; + } + extractHlsl += "}\n}\n}"; + + ID3D11PixelShader *extract = MakePShader(extractHlsl.c_str(), "ExtractInputsPS", "ps_5_0"); + + // uint hit; float3 pos; uint prim; float derivValid; PSInput IN, INddx, INddy; + uint32_t structStride = sizeof(uint32_t) + sizeof(float)*3 + sizeof(uint32_t) + sizeof(float) + structureStride*3; + + HRESULT hr = S_OK; + + D3D11_BUFFER_DESC bdesc; + bdesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + bdesc.CPUAccessFlags = 0; + bdesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bdesc.Usage = D3D11_USAGE_DEFAULT; + bdesc.StructureByteStride = structStride; + bdesc.ByteWidth = bdesc.StructureByteStride * overdrawLevels; + + ID3D11Buffer *initialBuf = NULL; + hr = m_pDevice->CreateBuffer(&bdesc, NULL, &initialBuf); + + if(FAILED(hr)) + { + RDCERR("Failed to create buffer %08x", hr); + return empty; + } + + bdesc.BindFlags = 0; + bdesc.MiscFlags = 0; + bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bdesc.Usage = D3D11_USAGE_STAGING; + bdesc.StructureByteStride = 0; + + ID3D11Buffer *stageBuf = NULL; + hr = m_pDevice->CreateBuffer(&bdesc, NULL, &stageBuf); + + if(FAILED(hr)) + { + RDCERR("Failed to create buffer %08x", hr); + return empty; + } + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavdesc; + uavdesc.Format = DXGI_FORMAT_UNKNOWN; + uavdesc.Buffer.FirstElement = 0; + uavdesc.Buffer.Flags = 0; + uavdesc.Buffer.NumElements = overdrawLevels; + uavdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + + ID3D11UnorderedAccessView *initialUAV = NULL; + hr = m_pDevice->CreateUnorderedAccessView(initialBuf, &uavdesc, &initialUAV); + + if(FAILED(hr)) + { + RDCERR("Failed to create buffer %08x", hr); + return empty; + } + + UINT zero = 0; + m_pImmediateContext->ClearUnorderedAccessViewUint(initialUAV, &zero); + + UINT count = (UINT)-1; + ID3D11DepthStencilView *depthView = NULL; + m_pImmediateContext->OMGetRenderTargets(0, NULL, &depthView); + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, depthView, 0, 1, &initialUAV, &count); + m_pImmediateContext->PSSetShader(extract, NULL, 0); + + SAFE_RELEASE(depthView); + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + m_pImmediateContext->CopyResource(stageBuf, initialBuf); + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = m_pImmediateContext->Map(stageBuf, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map stage buff %08x", hr); + return empty; + } + + byte *initialData = new byte[bdesc.ByteWidth]; + memcpy(initialData, mapped.pData, bdesc.ByteWidth); + + m_pImmediateContext->Unmap(stageBuf, 0); + + SAFE_RELEASE(initialUAV); + SAFE_RELEASE(initialBuf); + SAFE_RELEASE(stageBuf); + + SAFE_RELEASE(extract); + + DebugHit *buf = (DebugHit *)initialData; + + if(buf[0].numHits == 0) + { + RDCLOG("No hit for this event"); + return empty; + } + + // if we encounter multiple hits at our destination pixel co-ord (or any other) we + // really need to check depth state here, but that's difficult so skip it for now + // we can iterate over the hits and get the depth of each from the second element + // in each struct, but we also need the test depth AND need to be able to resolve + // the depth test in the same way for each fragment. + // + // For now, just take the first. Later need to modify buf to point at the data of + // the actual passing fragment. + // also with alpha blending on we'd need to be able to pick the right one anyway. + // so really here we just need to be able to get the depth result of each hit and + // let the user choose, since multiple might pass & apply. + + + // our debugging quad. Order is TL, TR, BL, BR + State quad[4]; + + // figure out the TL pixel's coords. Assume even top left (towards 0,0) + int xTL = x&(~1); + int yTL = y&(~1); + + // get the index of our desired pixel + int destIdx = (x-xTL) + 2*(y-yTL); + + vector cbufData[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + if(rs->PS.ConstantBuffers[i]) + cbufData[i] = GetBufferData(rs->PS.ConstantBuffers[i], rs->PS.CBOffsets[i]*sizeof(Vec4f), 0); + + D3D11_COMPARISON_FUNC depthFunc = D3D11_COMPARISON_LESS; + + if(rs->OM.DepthStencilState) + { + D3D11_DEPTH_STENCIL_DESC desc; + rs->OM.DepthStencilState->GetDesc(&desc); + depthFunc = desc.DepthFunc; + } + + DebugHit *winner = NULL; + + for(size_t i=0; i < buf[0].numHits; i++) + { + DebugHit *hit = (DebugHit *)(initialData+i*structStride); + + // only interested in destination pixel + if(hit->posx != (float)x + 0.5 || hit->posy != (float)y + 0.5) + continue; + + if(winner == NULL || depthFunc == D3D11_COMPARISON_ALWAYS || depthFunc == D3D11_COMPARISON_NEVER || + depthFunc == D3D11_COMPARISON_NOT_EQUAL || depthFunc == D3D11_COMPARISON_EQUAL) + { + winner = hit; + continue; + } + + if( + (depthFunc == D3D11_COMPARISON_LESS && hit->depth < winner->depth) || + (depthFunc == D3D11_COMPARISON_LESS_EQUAL && hit->depth <= winner->depth) || + (depthFunc == D3D11_COMPARISON_GREATER && hit->depth > winner->depth) || + (depthFunc == D3D11_COMPARISON_GREATER_EQUAL && hit->depth >= winner->depth) + ) + { + winner = hit; + } + } + + if(winner == NULL) + { + RDCLOG("Couldn't find any pixels that passed depth test at target co-ordinates"); + return empty; + } + + ShaderDebugTrace traces[4]; + + GlobalState global; + CreateShaderGlobalState(global, rs->OM.UAVStartSlot, rs->OM.UAVs, rs->PS.SRVs); + + { + DebugHit *hit = winner; + + State initialState = CreateShaderDebugState(traces[destIdx], destIdx, dxbc, cbufData); + + uint32_t *data = &hit->rawdata; + + for(size_t i=0; i < initialValues.size(); i++) + { + int32_t *rawout = NULL; + + if(initialValues[i].reg >= 0) + { + rawout = &traces[destIdx].inputs[initialValues[i].reg].value.iv[initialValues[i].elem]; + + memcpy(rawout, data, initialValues[i].numwords*4); + } + + data += initialValues[i].numwords; + } + + for(int i=0; i < 4; i++) + { + if(i != destIdx) + traces[i] = traces[destIdx]; + quad[i] = initialState; + quad[i].SetTrace(&traces[i]); + } + + float *ddx = (float *)data; + + // ddx(SV_Position.x) MUST be 1.0 + if(*ddx != 1.0f) + { + RDCERR("Derivatives invalid"); + return empty; + } + + ddx++; + + for(size_t i=0; i < initialValues.size(); i++) + { + if(initialValues[i].reg >= 0) + { + // left + if(destIdx == 0 || destIdx == 2) + { + for(int w=0; w < initialValues[i].numwords; w++) + { + traces[1].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddx[w]; + traces[3].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddx[w]; + } + } + else + { + for(int w=0; w < initialValues[i].numwords; w++) + { + traces[0].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddx[w]; + traces[2].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddx[w]; + } + } + } + + ddx += initialValues[i].numwords; + } + + float *ddy = ddx; + + for(size_t i=0; i < initialValues.size(); i++) + { + if(initialValues[i].reg >= 0) + { + // top + if(destIdx == 0 || destIdx == 1) + { + for(int w=0; w < initialValues[i].numwords; w++) + { + traces[2].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddy[w]; + traces[3].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddy[w]; + } + } + else + { + for(int w=0; w < initialValues[i].numwords; w++) + { + traces[0].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddy[w]; + traces[1].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddy[w]; + } + } + } + + ddy += initialValues[i].numwords; + } + } + + vector states; + + states.push_back((State)quad[destIdx]); + + // simulate lockstep until all threads are finished + bool finished = true; + do + { + for(size_t i = 0; i < 4; i++) + { + if(!quad[i].Finished()) + quad[i] = quad[i].GetNext(global, quad); + } + + states.push_back((State)quad[destIdx]); + + finished = quad[destIdx].Finished(); + } + while(!finished); + + traces[destIdx].states = states; + + return traces[destIdx]; +} + +ShaderDebugTrace D3D11DebugManager::DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]) +{ + using namespace DXBC; + using namespace ShaderDebug; + + ShaderDebugTrace empty; + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw); + + ID3D11ComputeShader *stateCS = NULL; + m_WrappedContext->CSGetShader(&stateCS, NULL, NULL); + + WrappedID3D11Shader *cs = (WrappedID3D11Shader *)stateCS; + + SAFE_RELEASE(stateCS); + + if(!cs) + return empty; + + DXBCFile *dxbc = cs->GetDXBC(); + + if(!dxbc) + return empty; + + D3D11RenderState *rs = m_WrappedContext->GetCurrentPipelineState(); + + vector cbufData[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + if(rs->CS.ConstantBuffers[i]) + cbufData[i] = GetBufferData(rs->CS.ConstantBuffers[i], rs->CS.CBOffsets[i]*sizeof(Vec4f), 0); + + ShaderDebugTrace ret; + + GlobalState global; + CreateShaderGlobalState(global, 0, rs->CS.UAVs, rs->CS.SRVs); + State initialState = CreateShaderDebugState(ret, -1, dxbc, cbufData); + + for(int i=0; i < 3; i++) + { + initialState.semantics.GroupID[i] = groupid[i]; + initialState.semantics.ThreadID[i] = threadid[i]; + } + + vector states; + + states.push_back((State)initialState); + + while(true) + { + if(initialState.Finished()) + break; + + initialState = initialState.GetNext(global, NULL); + + states.push_back((State)initialState); + } + + ret.states = states; + + return ret; +} + +void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]) +{ + m_pImmediateContext->OMSetRenderTargets(1, &m_DebugRender.PickPixelRT, NULL); + + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + m_pImmediateContext->ClearRenderTargetView(m_DebugRender.PickPixelRT, color); + + D3D11_VIEWPORT viewport; + RDCEraseEl(viewport); + + int oldW = GetWidth(), oldH = GetHeight(); + + SetOutputDimensions(100, 100); + + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = 100; + viewport.Height = 100; + + m_pImmediateContext->RSSetViewports(1, &viewport); + + { + TextureDisplay texDisplay; + + texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true; + texDisplay.HDRMul = -1.0f; + texDisplay.mip = mip; + texDisplay.CustomShader = ResourceId(); + texDisplay.sliceFace = sliceFace; + texDisplay.rangemin = 0.0f; + texDisplay.rangemax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.texid = texture; + texDisplay.rawoutput = true; + texDisplay.offx = -float(x); + texDisplay.offy = -float(y); + + RenderTexture(texDisplay); + } + + D3D11_BOX box; + box.front = 0; + box.back = 1; + box.left = 0; + box.right = 1; + box.top = 0; + box.bottom = 1; + + ID3D11Resource *res = NULL; + m_DebugRender.PickPixelRT->GetResource(&res); + + m_pImmediateContext->CopySubresourceRegion(m_DebugRender.PickPixelStageTex, 0, 0, 0, 0, res, 0, &box); + + SAFE_RELEASE(res); + + D3D11_MAPPED_SUBRESOURCE mapped; + mapped.pData = NULL; + HRESULT hr = m_pImmediateContext->Map(m_DebugRender.PickPixelStageTex, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map stage buff %08x", hr); + } + + float *pix = (float *)mapped.pData; + + if(pix == NULL) + { + RDCERR("Failed to map pick-pixel staging texture."); + } + else + { + pixel[0] = pix[0]; + pixel[1] = pix[1]; + pixel[2] = pix[2]; + pixel[3] = pix[3]; + } + + SetOutputDimensions(oldW, oldH); + + m_pImmediateContext->Unmap(m_DebugRender.PickPixelStageTex, 0); +} + +// from MSDN +struct DDS_PIXELFORMAT { + DWORD dwSize; + DWORD dwFlags; + DWORD dwFourCC; + DWORD dwRGBBitCount; + DWORD dwRBitMask; + DWORD dwGBitMask; + DWORD dwBBitMask; + DWORD dwABitMask; +}; + +struct DDS_HEADER { + DWORD dwSize; + DWORD dwFlags; + DWORD dwHeight; + DWORD dwWidth; + DWORD dwPitchOrLinearSize; + DWORD dwDepth; + DWORD dwMipMapCount; + DWORD dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + DWORD dwCaps; + DWORD dwCaps2; + DWORD dwCaps3; + DWORD dwCaps4; + DWORD dwReserved2; +}; + +struct DDS_HEADER_DXT10 { + DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + UINT miscFlag; + UINT arraySize; + UINT reserved; +}; + +#define DDSD_CAPS 0x1 +#define DDSD_HEIGHT 0x2 +#define DDSD_WIDTH 0x4 +#define DDSD_PITCH 0x8 +#define DDSD_PIXELFORMAT 0x1000 +#define DDSD_MIPMAPCOUNT 0x20000 +#define DDSD_LINEARSIZE 0x80000 +#define DDSD_DEPTH 0x800000 + +#define DDSCAPS_COMPLEX 0x8 +#define DDSCAPS_MIPMAP 0x400000 +#define DDSCAPS_TEXTURE 0x1000 + +#define DDSCAPS2_CUBEMAP 0xff00 // d3d10+ requires all cubemap faces +#define DDSCAPS2_VOLUME 0x200000 + +#define DDPF_ALPHAPIXELS 0x1 +#define DDPF_ALPHA 0x2 +#define DDPF_FOURCC 0x4 +#define DDPF_RGB 0x40 +#define DDPF_YUV 0x200 +#define DDPF_LUMINANCE 0x20000 +#define DDPF_RGBA (DDPF_RGB|DDPF_ALPHAPIXELS) + +bool D3D11DebugManager::SaveTexture(ResourceId id, uint32_t saveMip, wstring path) +{ + WrappedID3D11Texture2D *wrapTex = (WrappedID3D11Texture2D *)WrappedID3D11Texture2D::m_TextureList[id].m_Texture; + + if(path.find(L".dds") != wstring::npos) + { + D3D11_TEXTURE2D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + ID3D11Texture2D *dummyTex = NULL; + + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &dummyTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to save. %08x", hr); + return false; + } + + m_pImmediateContext->CopyResource(dummyTex, wrapTex->GetReal()); + + DWORD magic = 0x20534444; + DDS_HEADER header; + DDS_HEADER_DXT10 headerDXT10; + RDCEraseEl(header); + RDCEraseEl(headerDXT10); + + header.dwSize = sizeof(DDS_HEADER); + + header.ddspf.dwSize = sizeof(DDS_PIXELFORMAT); + + header.dwWidth = desc.Width; + header.dwHeight = desc.Height; + header.dwDepth = 0; + header.dwMipMapCount = desc.MipLevels; + + header.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + if(desc.MipLevels > 1) + header.dwFlags |= DDSD_MIPMAPCOUNT; + if(IsDepthFormat(desc.Format)) + header.dwFlags |= DDSD_DEPTH; + if(IsBlockFormat(desc.Format)) + header.dwFlags |= DDSD_LINEARSIZE; + else + header.dwFlags |= DDSD_PITCH; + + header.dwCaps = DDSCAPS_TEXTURE; + /* + // spec compliant, but seems to confuse DirectX Texture Tool :( + if(desc.MipLevels > 1) + header.dwCaps |= DDSCAPS_MIPMAP; + if(desc.MipLevels > 1 || desc.ArraySize > 1) + header.dwCaps |= DDSCAPS_COMPLEX; + */ + if(desc.ArraySize > 1) + header.dwCaps |= DDSCAPS_COMPLEX; + + header.dwCaps2 = desc.ArraySize > 1 ? DDSCAPS2_VOLUME : 0; + + headerDXT10.dxgiFormat = GetTypedFormat(desc.Format); + headerDXT10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + headerDXT10.arraySize = desc.ArraySize; + + if(desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) + { + header.dwCaps2 = DDSCAPS2_CUBEMAP; + headerDXT10.arraySize /= 6; + } + + if(IsBlockFormat(desc.Format)) + { + int blockSize = GetFormatBPP(desc.Format) / 8; + header.dwPitchOrLinearSize = RDCMAX(1U, ((desc.Width+3)/4)) * blockSize; + } + else if(desc.Format == DXGI_FORMAT_R8G8_B8G8_UNORM || + desc.Format == DXGI_FORMAT_G8R8_G8B8_UNORM) + { + header.dwPitchOrLinearSize = ((desc.Width+1) >> 1) * 4; + } + else + { + header.dwPitchOrLinearSize = (desc.Width * GetFormatBPP(desc.Format) + 7) / 8; + } + + + bool dx10Header = false; + + // special case a couple of formats to write out non-DX10 style, for + // backwards compatibility + switch(desc.Format) + { + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + { + header.ddspf.dwFlags = DDPF_RGBA; + header.ddspf.dwRGBBitCount = 32; + header.ddspf.dwRBitMask = 0x000000ff; + header.ddspf.dwGBitMask = 0x0000ff00; + header.ddspf.dwBBitMask = 0x00ff0000; + header.ddspf.dwABitMask = 0xff000000; + break; + } + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '1'); + break; + } + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '3'); + break; + } + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '5'); + break; + } + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '4', 'U'); + break; + } + case DXGI_FORMAT_BC4_SNORM: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '4', 'S'); + break; + } + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('A', 'T', 'I', '2'); + break; + } + case DXGI_FORMAT_BC5_SNORM: + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '5', 'S'); + break; + } + default: + { + // just write out DX10 header + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', '1', '0'); + + dx10Header = true; + break; + } + } + + FILE *f = FileIO::fopen(path.c_str(), L"wb"); + + if(f) + { + FileIO::fwrite(&magic, sizeof(magic), 1, f); + FileIO::fwrite(&header, sizeof(header), 1, f); + if(dx10Header) + FileIO::fwrite(&headerDXT10, sizeof(headerDXT10), 1, f); + + UINT i=0; + for(UINT slice=0; slice < RDCMAX(1U,desc.ArraySize); slice++) + { + for(UINT mip=0; mip < RDCMAX(1U,desc.MipLevels); mip++) + { + D3D11_MAPPED_SUBRESOURCE mapped; + hr = m_pImmediateContext->Map(dummyTex, i, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Couldn't map subresource. %08x", hr); + FileIO::fclose(f); + return false; + } + + byte *data = (byte *)mapped.pData; + + UINT numRows = (desc.Height>>mip); + UINT pitch = (header.dwPitchOrLinearSize>>mip); + + // pitch/rows are in blocks, not pixels, for block formats. + if(IsBlockFormat(desc.Format)) + { + numRows = RDCMAX(1U, numRows/4); + // at least one block + pitch = RDCMAX(pitch, GetFormatBPP(desc.Format)/8); + } + + for(UINT row=0; row < numRows; row++) + { + FileIO::fwrite(data, 1, pitch, f); + + data += mapped.RowPitch; + } + + m_pImmediateContext->Unmap(dummyTex, i); + + i++; + } + } + } + + FileIO::fclose(f); + + SAFE_RELEASE(dummyTex); + + return true; + } + + RDCERR("Unknown file-type"); + + return false; +} + +byte *D3D11DebugManager::GetTextureData(ResourceId id, uint32_t arrayIdx, uint32_t mip, size_t &dataSize) +{ + ID3D11Resource *dummyTex = NULL; + + uint32_t subresource = 0; + uint32_t mips = 0; + + dataSize = 0; + size_t bytesize = 0; + + if(WrappedID3D11Texture1D::m_TextureList.find(id) != WrappedID3D11Texture1D::m_TextureList.end()) + { + WrappedID3D11Texture1D *wrapTex = (WrappedID3D11Texture1D *)WrappedID3D11Texture1D::m_TextureList[id].m_Texture; + + D3D11_TEXTURE1D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + ID3D11Texture1D *d = NULL; + + mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, 1, 1); + + if(mip >= mips || arrayIdx >= desc.ArraySize) return NULL; + + subresource = arrayIdx*mips + mip; + + HRESULT hr = m_WrappedDevice->CreateTexture1D(&desc, NULL, &d); + + dummyTex = d; + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to retrieve data. %08x", hr); + return NULL; + } + + bytesize = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + + m_pImmediateContext->CopyResource(UNWRAP(WrappedID3D11Texture1D, d), wrapTex->GetReal()); + } + else if(WrappedID3D11Texture2D::m_TextureList.find(id) != WrappedID3D11Texture2D::m_TextureList.end()) + { + WrappedID3D11Texture2D *wrapTex = (WrappedID3D11Texture2D *)WrappedID3D11Texture2D::m_TextureList[id].m_Texture; + + D3D11_TEXTURE2D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + ID3D11Texture2D *d = NULL; + + mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, 1); + + if(mip >= mips || arrayIdx >= desc.ArraySize) return NULL; + + subresource = arrayIdx*mips + mip; + + HRESULT hr = m_WrappedDevice->CreateTexture2D(&desc, NULL, &d); + + dummyTex = d; + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to retrieve data. %08x", hr); + return NULL; + } + + bytesize = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + + m_pImmediateContext->CopyResource(UNWRAP(WrappedID3D11Texture2D, d), wrapTex->GetReal()); + } + else if(WrappedID3D11Texture3D::m_TextureList.find(id) != WrappedID3D11Texture3D::m_TextureList.end()) + { + WrappedID3D11Texture3D *wrapTex = (WrappedID3D11Texture3D *)WrappedID3D11Texture3D::m_TextureList[id].m_Texture; + + D3D11_TEXTURE3D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + ID3D11Texture3D *d = NULL; + + mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, desc.Depth); + + if(mip >= mips) return NULL; + + subresource = mip; + + HRESULT hr = m_WrappedDevice->CreateTexture3D(&desc, NULL, &d); + + dummyTex = d; + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to retrieve data. %08x", hr); + return NULL; + } + + bytesize = GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, mip); + + m_pImmediateContext->CopyResource(UNWRAP(WrappedID3D11Texture3D, d), wrapTex->GetReal()); + } + + MapIntercept intercept; + + D3D11_MAPPED_SUBRESOURCE mapped = {0}; + HRESULT hr = m_pImmediateContext->Map(m_ResourceManager->UnwrapResource(dummyTex), subresource, D3D11_MAP_READ, 0, &mapped); + + byte *ret = NULL; + + if(SUCCEEDED(hr)) + { + ret = new byte[bytesize]; + dataSize = bytesize; + intercept.InitWrappedResource(dummyTex, subresource, ret); + intercept.SetD3D(mapped); + intercept.CopyFromD3D(); + } + else + { + RDCERR("Couldn't map staging texture to retrieve data. %08x", hr); + } + + SAFE_RELEASE(dummyTex); + + return ret; +} + +void D3D11DebugManager::FillTimers(uint32_t frameID, uint32_t &eventStart, rdctype::array &draws, vector &timers, int &reuseIdx) +{ + const D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 }; + + if(draws.count == 0) return; + + for(int32_t i=0; i < draws.count; i++) + { + FetchDrawcall &d = draws[i]; + FillTimers(frameID, eventStart, d.children, timers, reuseIdx); + + if(d.events.count == 0) continue; + + GPUTimer *timer = NULL; + + if(reuseIdx == -1) + { + timers.push_back(GPUTimer()); + + timer = &timers.back(); + timer->drawcall = &d; + } + else + { + timer = &timers[reuseIdx++]; + } + + HRESULT hr = S_OK; + + if(reuseIdx == -1) + { + hr = m_pDevice->CreateQuery(&qdesc, &timer->before); + RDCASSERT(SUCCEEDED(hr)); + hr = m_pDevice->CreateQuery(&qdesc, &timer->after); + RDCASSERT(SUCCEEDED(hr)); + } + + m_WrappedDevice->ReplayLog(frameID, eventStart, d.eventID, eReplay_WithoutDraw); + + m_pImmediateContext->Flush(); + + m_pImmediateContext->End(timer->before); + m_WrappedDevice->ReplayLog(frameID, eventStart, d.eventID, eReplay_OnlyDraw); + m_pImmediateContext->End(timer->after); + + eventStart = d.eventID+1; + } +} + +void D3D11DebugManager::TimeDrawcalls(rdctype::array &arr) +{ + SCOPED_TIMER("Drawcall timing"); + + vector timers; + + D3D11_QUERY_DESC disjointdesc = { D3D11_QUERY_TIMESTAMP_DISJOINT, 0 }; + ID3D11Query *disjoint = NULL; + + D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 }; + ID3D11Query *start = NULL; + + HRESULT hr = S_OK; + + hr = m_pDevice->CreateQuery(&disjointdesc, &disjoint); + if(FAILED(hr)) + { + RDCERR("Failed to create disjoint query %08x", hr); + return; + } + + hr = m_pDevice->CreateQuery(&qdesc, &start); + if(FAILED(hr)) + { + RDCERR("Failed to create start query %08x", hr); + return; + } + + for(int loop=0; loop < 1; loop++) + { + { + m_pImmediateContext->Begin(disjoint); + + m_pImmediateContext->End(start); + + uint32_t ev = 0; + int reuse = loop == 0 ? -1 : 0; + FillTimers(0, ev, arr, timers, reuse); + + m_pImmediateContext->End(disjoint); + } + + { + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; + do + { + hr = m_pImmediateContext->GetData(disjoint, &disjointData, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), 0); + } while(hr == S_FALSE); + RDCASSERT(hr == S_OK); + + RDCASSERT(!disjointData.Disjoint); + + double ticksToSecs = double(disjointData.Frequency); + + UINT64 a=0; + m_pImmediateContext->GetData(start, &a, sizeof(UINT64), 0); + + for(size_t i=0; i < timers.size(); i++) + { + hr = m_pImmediateContext->GetData(timers[i].before, &a, sizeof(UINT64), 0); + RDCASSERT(hr == S_OK); + + UINT64 b=0; + hr = m_pImmediateContext->GetData(timers[i].after, &b, sizeof(UINT64), 0); + RDCASSERT(hr == S_OK); + + timers[i].drawcall->duration = (double(b-a)/ticksToSecs); + + a = b; + } + } + } + + for(size_t i=0; i < timers.size(); i++) + { + SAFE_RELEASE(timers[i].before); + SAFE_RELEASE(timers[i].after); + } + + SAFE_RELEASE(disjoint); + SAFE_RELEASE(start); +} + +ResourceId D3D11DebugManager::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) +{ + TextureShaderDetails details = GetShaderDetails(texid, false); + + CreateCustomShaderTex(details.texWidth, details.texHeight); + + m_pImmediateContext->OMSetRenderTargets(1, &m_CustomShaderRTV, NULL); + + float clr[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + m_pImmediateContext->ClearRenderTargetView(m_CustomShaderRTV, clr); + + D3D11_VIEWPORT viewport; + RDCEraseEl(viewport); + + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = (float)details.texWidth; + viewport.Height = (float)details.texHeight; + + m_pImmediateContext->RSSetViewports(1, &viewport); + + TextureDisplay disp; + disp.Red = disp.Green = disp.Blue = disp.Alpha = true; + disp.offx = 0.0f; + disp.offy = 0.0f; + disp.CustomShader = shader; + disp.texid = texid; + disp.lightBackgroundColour = disp.darkBackgroundColour = FloatVector(0,0,0,0); + disp.HDRMul = -1.0f; + disp.mip = mip; + disp.overlay = eTexOverlay_None; + disp.rangemin = 0.0f; + disp.rangemax = 1.0f; + disp.rawoutput = false; + disp.scale = 1.0f; + disp.sliceFace = 0; + + SetOutputDimensions(details.texWidth, details.texHeight); + + RenderTexture(disp); + + return m_CustomShaderResourceId; +} + +void D3D11DebugManager::CreateCustomShaderTex(uint32_t w, uint32_t h) +{ + D3D11_TEXTURE2D_DESC texdesc; + + texdesc.ArraySize = 1; + texdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + texdesc.CPUAccessFlags = 0; + texdesc.MipLevels = 1; + texdesc.MiscFlags = 0; + texdesc.SampleDesc.Count = 1; + texdesc.SampleDesc.Quality = 0; + texdesc.Usage = D3D11_USAGE_DEFAULT; + texdesc.Width = w; + texdesc.Height = h; + texdesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + + if(m_CustomShaderTex) + { + D3D11_TEXTURE2D_DESC customTexDesc; + m_CustomShaderTex->GetDesc(&customTexDesc); + + if(customTexDesc.Width == w && customTexDesc.Height == h) + return; + + SAFE_RELEASE(m_CustomShaderRTV); + SAFE_RELEASE(m_CustomShaderTex); + } + + HRESULT hr = m_WrappedDevice->CreateTexture2D(&texdesc, NULL, &m_CustomShaderTex); + + if(FAILED(hr)) + { + RDCERR("Failed to create custom shader tex %08x", hr); + } + else + { + WrappedID3D11Texture2D *wrapped = (WrappedID3D11Texture2D *)m_CustomShaderTex; + hr = m_pDevice->CreateRenderTargetView(wrapped->GetReal(), NULL, &m_CustomShaderRTV); + + if(FAILED(hr)) + RDCERR("Failed to create custom shader rtv %08x", hr); + + m_CustomShaderResourceId = GetIDForResource(m_CustomShaderTex); + } +} + +ResourceId D3D11DebugManager::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID) +{ + TextureShaderDetails details = GetShaderDetails(texid, false); + + ResourceId id = texid; + + D3D11_TEXTURE2D_DESC realTexDesc; + realTexDesc.BindFlags = D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE; + realTexDesc.Usage = D3D11_USAGE_DEFAULT; + realTexDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + realTexDesc.ArraySize = 1; + realTexDesc.MipLevels = 1; + realTexDesc.CPUAccessFlags = 0; + realTexDesc.MiscFlags = 0; + realTexDesc.SampleDesc.Count = 1; + realTexDesc.SampleDesc.Quality = 0; + realTexDesc.Width = details.texWidth; + realTexDesc.Height = details.texHeight; + + if(details.texType == eTexType_2D) + { + realTexDesc.SampleDesc.Count = details.sampleCount; + realTexDesc.SampleDesc.Quality = details.sampleQuality; + } + + D3D11RenderState old = *m_WrappedContext->GetCurrentPipelineState(); + + D3D11_TEXTURE2D_DESC customTexDesc; + RDCEraseEl(customTexDesc); + if(m_OverlayRenderTex) + m_OverlayRenderTex->GetDesc(&customTexDesc); + + WrappedID3D11Texture2D *wrappedCustomRenderTex = (WrappedID3D11Texture2D *)m_OverlayRenderTex; + + // need to recreate backing custom render tex + if(realTexDesc.Width != customTexDesc.Width || + realTexDesc.Height != customTexDesc.Height || + realTexDesc.Format != customTexDesc.Format || + realTexDesc.SampleDesc.Count != customTexDesc.SampleDesc.Count || + realTexDesc.SampleDesc.Quality != customTexDesc.SampleDesc.Quality) + { + SAFE_RELEASE(m_OverlayRenderTex); + m_OverlayResourceId = ResourceId(); + + ID3D11Texture2D *customRenderTex = NULL; + HRESULT hr = m_WrappedDevice->CreateTexture2D(&realTexDesc, NULL, &customRenderTex); + if(FAILED(hr)) + { + RDCERR("Failed to create custom render tex %08x", hr); + return ResourceId(); + } + wrappedCustomRenderTex = (WrappedID3D11Texture2D *)customRenderTex; + + m_OverlayRenderTex = wrappedCustomRenderTex; + m_OverlayResourceId = wrappedCustomRenderTex->GetResourceID(); + } + + ID3D11Texture2D *preDrawDepth = NULL; + ID3D11Texture2D *renderDepth = NULL; + + ID3D11DepthStencilView *dsView = NULL; + + m_pImmediateContext->OMGetRenderTargets(0, NULL, &dsView); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsViewDesc; + RDCEraseEl(dsViewDesc); + if(dsView) + { + ID3D11Texture2D *realDepth = NULL; + + dsView->GetResource((ID3D11Resource **)&realDepth); + + dsView->GetDesc(&dsViewDesc); + + SAFE_RELEASE(dsView); + + D3D11_TEXTURE2D_DESC desc; + + realDepth->GetDesc(&desc); + + HRESULT hr = S_OK; + + hr = m_pDevice->CreateTexture2D(&desc, NULL, &preDrawDepth); + if(FAILED(hr)) + { + RDCERR("Failed to create preDrawDepth %08x", hr); + SAFE_RELEASE(realDepth); + return m_OverlayResourceId; + } + hr = m_pDevice->CreateTexture2D(&desc, NULL, &renderDepth); + if(FAILED(hr)) + { + RDCERR("Failed to create renderDepth %08x", hr); + SAFE_RELEASE(realDepth); + return m_OverlayResourceId; + } + + m_pImmediateContext->CopyResource(preDrawDepth, realDepth); + + SAFE_RELEASE(realDepth); + } + + D3D11_RENDER_TARGET_VIEW_DESC rtDesc; + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + rtDesc.Texture2D.MipSlice = 0; + + if(realTexDesc.SampleDesc.Count > 1 || + realTexDesc.SampleDesc.Quality > 0) + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } + + ID3D11RenderTargetView *rtv = NULL; + HRESULT hr = m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex->GetReal(), &rtDesc, &rtv); + if(FAILED(hr)) + { + RDCERR("Failed to create custom render tex RTV %08x", hr); + return m_OverlayResourceId; + } + + FLOAT black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + m_pImmediateContext->ClearRenderTargetView(rtv, black); + + if(renderDepth) + { + m_pImmediateContext->CopyResource(renderDepth, preDrawDepth); + + hr = m_pDevice->CreateDepthStencilView(renderDepth, &dsViewDesc, &dsView); + if(FAILED(hr)) + { + RDCERR("Failed to create renderDepth DSV %08x", hr); + return m_OverlayResourceId; + } + } + + m_pImmediateContext->OMSetRenderTargets(1, &rtv, dsView); + + SAFE_RELEASE(dsView); + + D3D11_DEPTH_STENCIL_DESC desc; + + desc.BackFace.StencilFailOp = desc.BackFace.StencilPassOp = desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.FrontFace.StencilFailOp = desc.FrontFace.StencilPassOp = desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.DepthEnable = TRUE; + desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + desc.StencilEnable = FALSE; + desc.StencilReadMask = desc.StencilWriteMask = 0xff; + + if(overlay == eTexOverlay_NaN || + overlay == eTexOverlay_Clipping) + { + // just need the basic texture + } + else if(overlay == eTexOverlay_Drawcall) + { + m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0); + + desc.DepthEnable = FALSE; + desc.StencilEnable = FALSE; + + ID3D11DepthStencilState *os = NULL; + hr = m_pDevice->CreateDepthStencilState(&desc, &os); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall depth stencil state %08x", hr); + return m_OverlayResourceId; + } + + m_pImmediateContext->OMSetDepthStencilState(os, 0); + + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + + ID3D11RasterizerState *rs = NULL; + { + D3D11_RASTERIZER_DESC desc; + + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_NONE; + desc.FrontCounterClockwise = FALSE; + desc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS; + desc.DepthBiasClamp = D3D11_DEFAULT_DEPTH_BIAS_CLAMP; + desc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + desc.DepthClipEnable = FALSE; + desc.ScissorEnable = FALSE; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + + hr = m_pDevice->CreateRasterizerState(&desc, &rs); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall rast state %08x", hr); + return m_OverlayResourceId; + } + } + + float clearColour[] = { 0.0f, 0.0f, 0.0f, 0.5f }; + m_pImmediateContext->ClearRenderTargetView(rtv, clearColour); + + float overlayConsts[] = { 0.8f, 0.1f, 0.8f, 1.0f }; + ID3D11Buffer *buf = MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &buf); + + m_pImmediateContext->RSSetState(rs); + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + SAFE_RELEASE(os); + SAFE_RELEASE(rs); + } + else if(overlay == eTexOverlay_ViewportScissor) + { + m_pImmediateContext->VSSetShader(m_DebugRender.FullscreenVS, NULL, 0); + m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0); + + desc.DepthEnable = FALSE; + desc.StencilEnable = FALSE; + + ID3D11DepthStencilState *os = NULL; + hr = m_pDevice->CreateDepthStencilState(&desc, &os); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall depth stencil state %08x", hr); + return m_OverlayResourceId; + } + + m_pImmediateContext->OMSetDepthStencilState(os, 0); + + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + + ID3D11RasterizerState *rs = NULL; + ID3D11RasterizerState *rs2 = NULL; + { + D3D11_RASTERIZER_DESC desc; + + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_NONE; + desc.FrontCounterClockwise = FALSE; + desc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS; + desc.DepthBiasClamp = D3D11_DEFAULT_DEPTH_BIAS_CLAMP; + desc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + desc.DepthClipEnable = FALSE; + desc.ScissorEnable = FALSE; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + + hr = m_pDevice->CreateRasterizerState(&desc, &rs); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall rast state %08x", hr); + return m_OverlayResourceId; + } + + desc.ScissorEnable = TRUE; + + hr = m_pDevice->CreateRasterizerState(&desc, &rs2); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall rast state %08x", hr); + return m_OverlayResourceId; + } + } + + float clearColour[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + m_pImmediateContext->ClearRenderTargetView(rtv, clearColour); + + float overlayConsts[] = { 0.15f, 0.3f, 0.6f, 0.3f }; + ID3D11Buffer *buf = MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &buf); + + m_pImmediateContext->RSSetState(rs); + + m_pImmediateContext->Draw(3, 0); + + float overlayConsts2[] = { 0.5f, 0.6f, 0.8f, 0.3f }; + buf = MakeCBuffer(overlayConsts2, sizeof(overlayConsts2)); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &buf); + + m_pImmediateContext->RSSetState(rs2); + + m_pImmediateContext->Draw(3, 0); + + SAFE_RELEASE(os); + SAFE_RELEASE(rs); + SAFE_RELEASE(rs2); + } + else if(overlay == eTexOverlay_Wireframe) + { + m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0); + + desc.DepthEnable = FALSE; + + ID3D11DepthStencilState *os = NULL; + hr = m_pDevice->CreateDepthStencilState(&desc, &os); + if(FAILED(hr)) + { + RDCERR("Failed to create wireframe depth state %08x", hr); + return m_OverlayResourceId; + } + + m_pImmediateContext->OMSetDepthStencilState(os, 0); + + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + + ID3D11RasterizerState *rs = NULL; + { + D3D11_RASTERIZER_DESC desc; + + m_pImmediateContext->RSGetState(&rs); + + if(rs) + { + rs->GetDesc(&desc); + } + else + { + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_BACK; + desc.FrontCounterClockwise = FALSE; + desc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS; + desc.DepthBiasClamp = D3D11_DEFAULT_DEPTH_BIAS_CLAMP; + desc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + desc.DepthClipEnable = TRUE; + desc.ScissorEnable = FALSE; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + } + + SAFE_RELEASE(rs); + + desc.FillMode = D3D11_FILL_WIREFRAME; + desc.CullMode = D3D11_CULL_NONE; + + hr = m_pDevice->CreateRasterizerState(&desc, &rs); + if(FAILED(hr)) + { + RDCERR("Failed to create wireframe rast state %08x", hr); + return m_OverlayResourceId; + } + } + + float overlayConsts[] = { 200.0f/255.0f, 255.0f/255.0f, 0.0f/255.0f, 0.0f }; + m_pImmediateContext->ClearRenderTargetView(rtv, overlayConsts); + + overlayConsts[3] = 1.0f; + ID3D11Buffer *buf = MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &buf); + + m_pImmediateContext->RSSetState(rs); + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + SAFE_RELEASE(os); + SAFE_RELEASE(rs); + } + else if(preDrawDepth) + { + D3D11_DEPTH_STENCIL_DESC cur = {0}; + + UINT stencilRef = 0; + + { + ID3D11DepthStencilState *os = NULL; + m_pImmediateContext->OMGetDepthStencilState(&os, &stencilRef); + + if(os) + { + os->GetDesc(&cur); + SAFE_RELEASE(os); + } + else + { + cur.DepthFunc = D3D11_COMPARISON_LESS; // default depth func + cur.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + cur.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + cur.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + cur.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + cur.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + cur.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + cur.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + cur.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + } + } + + if(overlay == eTexOverlay_DepthBoth || + overlay == eTexOverlay_StencilBoth) + { + ID3D11DepthStencilState *os = NULL; + + D3D11_DEPTH_STENCIL_DESC d = desc; + + if(overlay == eTexOverlay_DepthBoth) + { + desc.DepthEnable = d.DepthEnable = TRUE; + desc.StencilEnable = d.StencilEnable = FALSE; + + switch(cur.DepthFunc) + { + case D3D11_COMPARISON_ALWAYS: + d.DepthFunc = D3D11_COMPARISON_NEVER; + break; + case D3D11_COMPARISON_NEVER: + d.DepthFunc = D3D11_COMPARISON_ALWAYS; + break; + + case D3D11_COMPARISON_EQUAL: + d.DepthFunc = D3D11_COMPARISON_NOT_EQUAL; + break; + case D3D11_COMPARISON_NOT_EQUAL: + d.DepthFunc = D3D11_COMPARISON_EQUAL; + break; + + case D3D11_COMPARISON_LESS: + d.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; + break; + case D3D11_COMPARISON_GREATER_EQUAL: + d.DepthFunc = D3D11_COMPARISON_LESS; + break; + + case D3D11_COMPARISON_GREATER: + d.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + break; + case D3D11_COMPARISON_LESS_EQUAL: + d.DepthFunc = D3D11_COMPARISON_GREATER; + break; + } + } + else if(overlay == eTexOverlay_StencilBoth) + { + desc.DepthEnable = d.DepthEnable = FALSE; + desc.StencilEnable = d.StencilEnable = TRUE; + + d.FrontFace = cur.FrontFace; + d.BackFace = cur.BackFace; + desc.StencilReadMask = d.StencilReadMask = cur.StencilReadMask; + desc.StencilWriteMask = d.StencilWriteMask = cur.StencilWriteMask; + + switch(cur.FrontFace.StencilFunc) + { + case D3D11_COMPARISON_ALWAYS: + d.FrontFace.StencilFunc = D3D11_COMPARISON_NEVER; + break; + case D3D11_COMPARISON_NEVER: + d.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + break; + + case D3D11_COMPARISON_EQUAL: + d.FrontFace.StencilFunc = D3D11_COMPARISON_NOT_EQUAL; + break; + case D3D11_COMPARISON_NOT_EQUAL: + d.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL; + break; + + case D3D11_COMPARISON_LESS: + d.FrontFace.StencilFunc = D3D11_COMPARISON_GREATER_EQUAL; + break; + case D3D11_COMPARISON_GREATER_EQUAL: + d.FrontFace.StencilFunc = D3D11_COMPARISON_LESS; + break; + + case D3D11_COMPARISON_GREATER: + d.FrontFace.StencilFunc = D3D11_COMPARISON_LESS_EQUAL; + break; + case D3D11_COMPARISON_LESS_EQUAL: + d.FrontFace.StencilFunc = D3D11_COMPARISON_GREATER; + break; + } + + switch(cur.BackFace.StencilFunc) + { + case D3D11_COMPARISON_ALWAYS: + d.BackFace.StencilFunc = D3D11_COMPARISON_NEVER; + break; + case D3D11_COMPARISON_NEVER: + d.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + break; + + case D3D11_COMPARISON_EQUAL: + d.BackFace.StencilFunc = D3D11_COMPARISON_NOT_EQUAL; + break; + case D3D11_COMPARISON_NOT_EQUAL: + d.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL; + break; + + case D3D11_COMPARISON_LESS: + d.BackFace.StencilFunc = D3D11_COMPARISON_GREATER_EQUAL; + break; + case D3D11_COMPARISON_GREATER_EQUAL: + d.BackFace.StencilFunc = D3D11_COMPARISON_LESS; + break; + + case D3D11_COMPARISON_GREATER: + d.BackFace.StencilFunc = D3D11_COMPARISON_LESS_EQUAL; + break; + case D3D11_COMPARISON_LESS_EQUAL: + d.BackFace.StencilFunc = D3D11_COMPARISON_GREATER; + break; + } + } + + SAFE_RELEASE(os); + hr = m_pDevice->CreateDepthStencilState(&d, &os); + if(FAILED(hr)) + { + RDCERR("Failed to create depth/stencil overlay depth state %08x", hr); + return m_OverlayResourceId; + } + + m_pImmediateContext->OMSetDepthStencilState(os, stencilRef); + + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + + float redConsts[] = { 255.0f/255.0f, 0.0f/255.0f, 0.0f/255.0f, 255.0f/255.0f }; + + ID3D11Buffer *buf = MakeCBuffer(redConsts, sizeof(redConsts)); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &buf); + + m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0); + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + SAFE_RELEASE(os); + + m_pImmediateContext->CopyResource(renderDepth, preDrawDepth); + + d = desc; + + if(overlay == eTexOverlay_DepthBoth) + { + d.DepthFunc = cur.DepthFunc; + } + else if(overlay == eTexOverlay_StencilBoth) + { + d.FrontFace = cur.FrontFace; + d.BackFace = cur.BackFace; + } + + hr = m_pDevice->CreateDepthStencilState(&d, &os); + if(FAILED(hr)) + { + RDCERR("Failed to create depth/stencil overlay depth state 2 %08x", hr); + return m_OverlayResourceId; + } + + m_pImmediateContext->OMSetDepthStencilState(os, stencilRef); + + float greenConsts[] = { 0.0f/255.0f, 255.0f/255.0f, 0.0f/255.0f, 255.0f/255.0f }; + + buf = MakeCBuffer(greenConsts, sizeof(greenConsts)); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &buf); + + m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0); + + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + SAFE_RELEASE(os); + } + } + + SAFE_RELEASE(rtv); + + SAFE_RELEASE(renderDepth); + SAFE_RELEASE(preDrawDepth); + + old.ApplyState(m_WrappedContext); + + return m_OverlayResourceId; +} diff --git a/renderdoc/driver/d3d11/d3d11_common.cpp b/renderdoc/driver/d3d11/d3d11_common.cpp new file mode 100644 index 0000000000..ed034e8846 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_common.cpp @@ -0,0 +1,2064 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "core/core.h" + +#include "common/string_utils.h" + +#include "serialise/serialiser.h" + +#include "d3d11_common.h" +#include "driver/d3d11/d3d11_resources.h" +#include "driver/d3d11/d3d11_renderstate.h" + +HMODULE GetD3DCompiler() +{ + static HMODULE ret = NULL; + if(ret != NULL) return ret; + + // dlls to try in priority order + const char *dlls[] = { + "d3dcompiler_47.dll", + "d3dcompiler_46.dll", + "d3dcompiler_45.dll", + "d3dcompiler_44.dll", + "d3dcompiler_43.dll", + }; + + for(int i=0; i < 2; i++) + { + for(int d=0; d < ARRAY_COUNT(dlls); d++) + { + if(i == 0) + ret = GetModuleHandleA(dlls[d]); + else + ret = LoadLibraryA(dlls[d]); + + if(ret != NULL) return ret; + } + } + + return ret; +} + +DXGI_FORMAT MakeDXGIFormat(ResourceFormat fmt) +{ + DXGI_FORMAT ret = DXGI_FORMAT_UNKNOWN; + + if(fmt.special) + { + switch(fmt.specialFormat) + { + case eSpecial_BC1: + ret = DXGI_FORMAT_BC1_UNORM; + break; + case eSpecial_BC2: + ret = DXGI_FORMAT_BC2_UNORM; + break; + case eSpecial_BC3: + ret = DXGI_FORMAT_BC3_UNORM; + break; + case eSpecial_BC4: + ret = DXGI_FORMAT_BC4_UNORM; + break; + case eSpecial_BC5: + ret = DXGI_FORMAT_BC5_UNORM; + break; + case eSpecial_BC6: + ret = DXGI_FORMAT_BC6H_UF16; + break; + case eSpecial_BC7: + ret = DXGI_FORMAT_BC7_UNORM; + break; + case eSpecial_R10G10B10A2: + if(fmt.compType == eCompType_UNorm) + ret = DXGI_FORMAT_R10G10B10A2_UNORM; + else + ret = DXGI_FORMAT_R10G10B10A2_UINT; + break; + case eSpecial_R11G11B10: + ret = DXGI_FORMAT_R11G11B10_FLOAT; + break; + case eSpecial_B5G6R5: + ret = DXGI_FORMAT_B5G6R5_UNORM; + break; + case eSpecial_B5G5R5A1: + ret = DXGI_FORMAT_B5G5R5A1_UNORM; + break; + case eSpecial_R9G9B9E5: + ret = DXGI_FORMAT_R9G9B9E5_SHAREDEXP; + break; + case eSpecial_B8G8R8A8: + ret = DXGI_FORMAT_B8G8R8A8_UNORM; + break; + case eSpecial_B4G4R4A4: + ret = DXGI_FORMAT_B4G4R4A4_UNORM; + break; + case eSpecial_D24S8: + ret = DXGI_FORMAT_R24G8_TYPELESS; + break; + case eSpecial_D32S8: + ret = DXGI_FORMAT_R32G8X24_TYPELESS; + break; + case eSpecial_YUV: + RDCERR("Video format not unambiguously encoded"); + ret = DXGI_FORMAT_AYUV; + break; + default: + RDCERR("Unrecognised special format"); + break; + } + } + else if(fmt.compCount == 4) + { + if(fmt.compByteWidth == 4) ret = DXGI_FORMAT_R32G32B32A32_TYPELESS; + else if(fmt.compByteWidth == 2) ret = DXGI_FORMAT_R16G16B16A16_TYPELESS; + else if(fmt.compByteWidth == 1) ret = DXGI_FORMAT_R8G8B8A8_TYPELESS; + else RDCERR("Unrecognised 4-component byte width: %d", fmt.compByteWidth); + } + else if(fmt.compCount == 3) + { + if(fmt.compByteWidth == 4) ret = DXGI_FORMAT_R32G32B32_TYPELESS; + //else if(fmt.compByteWidth == 2) ret = DXGI_FORMAT_R16G16B16_TYPELESS; // format doesn't exist + //else if(fmt.compByteWidth == 1) ret = DXGI_FORMAT_R8G8B8_TYPELESS; // format doesn't exist + else RDCERR("Unrecognised 3-component byte width: %d", fmt.compByteWidth); + } + else if(fmt.compCount == 2) + { + if(fmt.compByteWidth == 4) ret = DXGI_FORMAT_R32G32_TYPELESS; + else if(fmt.compByteWidth == 2) ret = DXGI_FORMAT_R16G16_TYPELESS; + else if(fmt.compByteWidth == 1) ret = DXGI_FORMAT_R8G8_TYPELESS; + else RDCERR("Unrecognised 2-component byte width: %d", fmt.compByteWidth); + } + else if(fmt.compCount == 1) + { + if(fmt.compByteWidth == 4) ret = DXGI_FORMAT_R32_TYPELESS; + else if(fmt.compByteWidth == 2) ret = DXGI_FORMAT_R16_TYPELESS; + else if(fmt.compByteWidth == 1) ret = DXGI_FORMAT_R8_TYPELESS; + else RDCERR("Unrecognised 1-component byte width: %d", fmt.compByteWidth); + } + else + { + RDCERR("Unrecognised component count: %d", fmt.compCount); + } + + if(fmt.compType == eCompType_None) + ret = GetTypelessFormat(ret); + else if(fmt.compType == eCompType_Float) + ret = GetFloatTypedFormat(ret); + else if(fmt.compType == eCompType_Depth) + ret = GetDepthTypedFormat(ret); + else if(fmt.compType == eCompType_UNorm || fmt.compType == eCompType_UNorm_SRGB) + ret = GetUnormTypedFormat(ret); + else if(fmt.compType == eCompType_SNorm) + ret = GetSnormTypedFormat(ret); + else if(fmt.compType == eCompType_UInt) + ret = GetUIntTypedFormat(ret); + else if(fmt.compType == eCompType_SInt) + ret = GetSIntTypedFormat(ret); + else + RDCERR("Unrecognised component type"); + + if(fmt.srgbCorrected) + ret = GetSRGBFormat(ret); + + if(ret == DXGI_FORMAT_UNKNOWN) + RDCERR("No known DXGI_FORMAT corresponding to resource format!"); + + return ret; +} + +ResourceFormat MakeResourceFormat(DXGI_FORMAT fmt) +{ + ResourceFormat ret; + + ret.rawType = fmt; + ret.special = false; + ret.strname = widen(ToStr::Get(fmt)).substr(12); // 12 == strlen("DXGI_FORMAT_") + + ret.compCount = ret.compByteWidth = 0; + ret.compType = eCompType_Float; + + ret.srgbCorrected = IsSRGBFormat(fmt); + + switch(fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + ret.compCount = 4; + break; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + ret.compCount = 3; + break; + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + ret.compCount = 2; + break; + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + ret.compCount = 1; + break; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + ret.compCount = 2; + break; + + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B5G6R5_UNORM: + + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + ret.compCount = 3; + break; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + ret.compCount = 4; + break; + + case DXGI_FORMAT_R1_UNORM: + + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + ret.compCount = 1; + break; + + case DXGI_FORMAT_UNKNOWN: + ret.compCount = 0; + + default: + ret.special = true; + } + + switch(fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + ret.compByteWidth = 4; + break; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + ret.compByteWidth = 2; + break; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + ret.compByteWidth = 1; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + ret.compByteWidth = 1; + break; + + case DXGI_FORMAT_UNKNOWN: + ret.compByteWidth = 0; + + default: + ret.special = true; + } + + switch(fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8_TYPELESS: + ret.compType = eCompType_None; + break; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R16_FLOAT: + ret.compType = eCompType_Float; + break; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + ret.compType = eCompType_UNorm_SRGB; + break; + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_A8_UNORM: + ret.compType = eCompType_UNorm; + break; + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R8_SNORM: + ret.compType = eCompType_SNorm; + break; + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R8_UINT: + ret.compType = eCompType_UInt; + break; + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R32G32B32_SINT: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_R8_SINT: + ret.compType = eCompType_SInt; + break; + + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + ret.compType = eCompType_UInt; + break; + + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R11G11B10_FLOAT: + ret.compType = eCompType_Float; + break; + + case DXGI_FORMAT_BC4_SNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC6H_TYPELESS: + ret.compType = eCompType_SNorm; + break; + + case DXGI_FORMAT_R24G8_TYPELESS: + ret.compType = eCompType_None; + break; + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_D16_UNORM: + ret.compType = eCompType_Depth; + break; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC7_TYPELESS: + ret.compType = eCompType_None; + break; + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R1_UNORM: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC7_UNORM: + ret.compType = eCompType_UNorm; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + ret.compType = eCompType_UNorm_SRGB; + break; + + case DXGI_FORMAT_UNKNOWN: + ret.compType = eCompType_None; + + default: + ret.special = true; + } + + ret.specialFormat = eSpecial_Unknown; + + switch(fmt) + { + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + ret.specialFormat = eSpecial_D24S8; + break; + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + ret.specialFormat = eSpecial_D32S8; + break; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC1_UNORM: + ret.specialFormat = eSpecial_BC1; + break; + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM: + ret.specialFormat = eSpecial_BC2; + break; + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM: + ret.specialFormat = eSpecial_BC3; + break; + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + ret.specialFormat = eSpecial_BC4; + break; + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + ret.specialFormat = eSpecial_BC5; + break; + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC6H_TYPELESS: + ret.specialFormat = eSpecial_BC6; + break; + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM: + ret.specialFormat = eSpecial_BC7; + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + ret.specialFormat = eSpecial_R10G10B10A2; + break; + case DXGI_FORMAT_R11G11B10_FLOAT: + ret.specialFormat = eSpecial_R11G11B10; + break; + case DXGI_FORMAT_B5G6R5_UNORM: + ret.specialFormat = eSpecial_B5G6R5; + break; + case DXGI_FORMAT_B5G5R5A1_UNORM: + ret.specialFormat = eSpecial_B5G5R5A1; + break; + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + ret.specialFormat = eSpecial_R9G9B9E5; + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + ret.specialFormat = eSpecial_B8G8R8A8; + break; + + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + ret.specialFormat = eSpecial_YUV; + break; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + ret.specialFormat = eSpecial_B4G4R4A4; + break; + + default: + break; + } + + if(ret.specialFormat != eSpecial_Unknown) + { + ret.special = true; + } + + return ret; +} + +ShaderConstant MakeConstantBufferVariable(DXBC::CBufferVariable var, uint32_t &offset); + +ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, uint32_t &offset) +{ + ShaderVariableType ret; + + ret.descriptor.rows = type.descriptor.rows; + ret.descriptor.cols = type.descriptor.cols; + ret.descriptor.elements = type.descriptor.elements; + ret.descriptor.name = type.descriptor.name; + + uint32_t o = offset; + + create_array_uninit(ret.members, type.members.size()); + for(size_t i=0; i < type.members.size(); i++) + { + offset = o; + ret.members[i] = MakeConstantBufferVariable(type.members[i], offset); + } + + if(ret.members.count > 0) + { + ret.descriptor.rows = 0; + ret.descriptor.cols = 0; + ret.descriptor.elements = 0; + } + + return ret; +} + +ShaderConstant MakeConstantBufferVariable(DXBC::CBufferVariable var, uint32_t &offset) +{ + ShaderConstant ret; + + ret.name = var.name; + ret.reg.vec = offset + var.descriptor.offset/16; + ret.reg.comp = (var.descriptor.offset - (var.descriptor.offset&~0xf))/4; + + offset = ret.reg.vec; + + ret.type = MakeShaderVariableType(var.type, offset); + + offset = ret.reg.vec + RDCMAX(1U, var.type.descriptor.bytesize/16); + + return ret; +} + +ShaderReflection *MakeShaderReflection(DXBC::DXBCFile *dxbc) +{ + if(dxbc == NULL || !RenderDoc::Inst().IsReplayApp()) + return NULL; + + ShaderReflection *ret = new ShaderReflection(); + + if(dxbc->m_DebugInfo) + { + ret->DebugInfo.entryFunc = dxbc->m_DebugInfo->GetEntryFunction(); + ret->DebugInfo.compileFlags = dxbc->m_DebugInfo->GetShaderCompileFlags(); + + create_array_uninit(ret->DebugInfo.files, dxbc->m_DebugInfo->Files.size()); + for(size_t i=0; i < dxbc->m_DebugInfo->Files.size(); i++) + { + ret->DebugInfo.files[i].first = dxbc->m_DebugInfo->Files[i].first; + ret->DebugInfo.files[i].second = dxbc->m_DebugInfo->Files[i].second; + } + } + + ret->Disassembly = dxbc->m_Disassembly; + + ret->InputSig = dxbc->m_InputSig; + ret->OutputSig = dxbc->m_OutputSig; + + create_array_uninit(ret->ConstantBlocks, dxbc->m_CBuffers.size()); + for(size_t i=0; i < dxbc->m_CBuffers.size(); i++) + { + ConstantBlock &cb = ret->ConstantBlocks[i]; + cb.name = dxbc->m_CBuffers[i].name; + cb.bufferAddress = (int32_t)i; + + create_array_uninit(cb.variables, dxbc->m_CBuffers[i].variables.size()); + for(size_t v=0; v < dxbc->m_CBuffers[i].variables.size(); v++) + { + uint32_t vecOffset = 0; + cb.variables[v] = MakeConstantBufferVariable(dxbc->m_CBuffers[i].variables[v], vecOffset); + } + } + + int numResources = 0; + for(size_t i=0; i < dxbc->m_Resources.size(); i++) + if(dxbc->m_Resources[i].type != DXBC::ShaderInputBind::TYPE_CBUFFER) + numResources++; + + create_array_uninit(ret->Resources, numResources); + int32_t idx=0; + for(size_t i=0; i < dxbc->m_Resources.size(); i++) + { + const auto &r = dxbc->m_Resources[i]; + + if(r.type == DXBC::ShaderInputBind::TYPE_CBUFFER) + continue; + + ShaderResource res; + res.variableAddress = r.bindPoint; // N/A for D3D, bindPoint is address + res.bindPoint = r.bindPoint; + res.name = r.name; + + res.IsSampler = (r.type == DXBC::ShaderInputBind::TYPE_SAMPLER); + res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE && + r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN && + r.dimension != DXBC::ShaderInputBind::DIM_BUFFER && + r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX); + res.IsSRV = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER || + r.type == DXBC::ShaderInputBind::TYPE_TEXTURE || + r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED || + r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS); + res.IsUAV = (r.type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED || + r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED || + r.type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS || + r.type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED || + r.type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED || + r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER); + + switch(r.dimension) + { + default: + case DXBC::ShaderInputBind::DIM_UNKNOWN: + res.resType = eResType_None; + break; + case DXBC::ShaderInputBind::DIM_BUFFER: + case DXBC::ShaderInputBind::DIM_BUFFEREX: + res.resType = eResType_Buffer; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE1D: + res.resType = eResType_Texture1D; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY: + res.resType = eResType_Texture1DArray; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE2D: + res.resType = eResType_Texture2D; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY: + res.resType = eResType_Texture2DArray; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: + res.resType = eResType_Texture2DMS; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY: + res.resType = eResType_Texture2DMSArray; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE3D: + res.resType = eResType_Texture3D; + break; + case DXBC::ShaderInputBind::DIM_TEXTURECUBE: + res.resType = eResType_TextureCube; + break; + case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY: + res.resType = eResType_TextureCubeArray; + break; + } + + if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN && + r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED && + r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED) + { + res.variableType.descriptor.rows = 1; + res.variableType.descriptor.cols = r.numSamples; + res.variableType.descriptor.elements = 1; + + string name; + + switch(r.retType) + { + case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break; + case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break; + case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break; + case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break; + case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break; + case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break; + default: name = "unknown"; break; + } + + name += ToStr::Get(r.numSamples); + + res.variableType.descriptor.name = name; + } + else + { + if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end()) + { + uint32_t vecOffset = 0; + res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset); + } + else + { + res.variableType.descriptor.rows = 0; + res.variableType.descriptor.cols = 0; + res.variableType.descriptor.elements = 0; + res.variableType.descriptor.name = ""; + } + } + + ret->Resources[idx++] = res; + } + + uint32_t numInterfaces = 0; + for(size_t i=0; i < dxbc->m_Interfaces.variables.size(); i++) + numInterfaces = RDCMAX(dxbc->m_Interfaces.variables[i].descriptor.offset+1, numInterfaces); + + create_array(ret->Interfaces, numInterfaces); + for(size_t i=0; i < dxbc->m_Interfaces.variables.size(); i++) + ret->Interfaces[dxbc->m_Interfaces.variables[i].descriptor.offset] = dxbc->m_Interfaces.variables[i].name; + + return ret; +} + +///////////////////////////////////////////////////////////// +// Structures/descriptors. Serialise members separately +// instead of ToStrInternal separately. Mostly for convenience of +// debugging the output + +template<> +void Serialiser::Serialise(const char *name, D3D11_BUFFER_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_BUFFER_DESC", 0, true); + Serialise("ByteWidth", el.ByteWidth); + Serialise("Usage", el.Usage); + Serialise("BindFlags", (D3D11_BIND_FLAG&)el.BindFlags); + Serialise("CPUAccessFlags", (D3D11_CPU_ACCESS_FLAG&)el.CPUAccessFlags); + Serialise("MiscFlags", (D3D11_RESOURCE_MISC_FLAG&)el.MiscFlags); + Serialise("StructureByteStride", el.StructureByteStride); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_TEXTURE1D_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_TEXTURE1D_DESC", 0, true); + Serialise("Width", el.Width); + Serialise("MipLevels", el.MipLevels); + Serialise("ArraySize", el.ArraySize); + Serialise("Format", el.Format); + Serialise("Usage", el.Usage); + Serialise("BindFlags", (D3D11_BIND_FLAG&)el.BindFlags); + Serialise("CPUAccessFlags", (D3D11_CPU_ACCESS_FLAG&)el.CPUAccessFlags); + Serialise("MiscFlags", (D3D11_RESOURCE_MISC_FLAG&)el.MiscFlags); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_TEXTURE2D_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_TEXTURE2D_DESC", 0, true); + Serialise("Width", el.Width); + Serialise("Height", el.Height); + Serialise("MipLevels", el.MipLevels); + Serialise("ArraySize", el.ArraySize); + Serialise("Format", el.Format); + Serialise("SampleDesc", el.SampleDesc); + Serialise("Usage", el.Usage); + Serialise("BindFlags", (D3D11_BIND_FLAG&)el.BindFlags); + Serialise("CPUAccessFlags", (D3D11_CPU_ACCESS_FLAG&)el.CPUAccessFlags); + Serialise("MiscFlags", (D3D11_RESOURCE_MISC_FLAG&)el.MiscFlags); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_TEXTURE3D_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_TEXTURE3D_DESC", 0, true); + Serialise("Width", el.Width); + Serialise("Height", el.Height); + Serialise("Depth", el.Depth); + Serialise("MipLevels", el.MipLevels); + Serialise("Format", el.Format); + Serialise("Usage", el.Usage); + Serialise("BindFlags", (D3D11_BIND_FLAG&)el.BindFlags); + Serialise("CPUAccessFlags", (D3D11_CPU_ACCESS_FLAG&)el.CPUAccessFlags); + Serialise("MiscFlags", (D3D11_RESOURCE_MISC_FLAG&)el.MiscFlags); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_SHADER_RESOURCE_VIEW_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_SHADER_RESOURCE_VIEW_DESC", 0, true); + Serialise("Format", el.Format); + Serialise("ViewDimension", el.ViewDimension); + + switch(el.ViewDimension) + { + case D3D11_SRV_DIMENSION_BUFFER: + Serialise("Buffer.FirstElement", el.Buffer.FirstElement); + Serialise("Buffer.NumElements", el.Buffer.NumElements); + break; + case D3D11_SRV_DIMENSION_TEXTURE1D: + Serialise("Texture1D.MipLevels", el.Texture1D.MipLevels); + Serialise("Texture1D.MostDetailedMip", el.Texture1D.MostDetailedMip); + break; + case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: + Serialise("Texture1DArray.MipLevels", el.Texture1DArray.MipLevels); + Serialise("Texture1DArray.MostDetailedMip", el.Texture1DArray.MostDetailedMip); + Serialise("Texture1DArray.ArraySize", el.Texture1DArray.ArraySize); + Serialise("Texture1DArray.FirstArraySlice", el.Texture1DArray.FirstArraySlice); + break; + case D3D11_SRV_DIMENSION_TEXTURE2D: + Serialise("Texture2D.MipLevels", el.Texture2D.MipLevels); + Serialise("Texture2D.MostDetailedMip", el.Texture2D.MostDetailedMip); + break; + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + Serialise("Texture2DArray.MipLevels", el.Texture2DArray.MipLevels); + Serialise("Texture2DArray.MostDetailedMip", el.Texture2DArray.MostDetailedMip); + Serialise("Texture2DArray.ArraySize", el.Texture2DArray.ArraySize); + Serialise("Texture2DArray.FirstArraySlice", el.Texture2DArray.FirstArraySlice); + break; + case D3D11_SRV_DIMENSION_TEXTURE2DMS: + // el.Texture2DMS.UnusedField_NothingToDefine + break; + case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: + Serialise("Texture2DMSArray.ArraySize", el.Texture2DMSArray.ArraySize); + Serialise("Texture2DMSArray.FirstArraySlice", el.Texture2DMSArray.FirstArraySlice); + break; + case D3D11_SRV_DIMENSION_TEXTURE3D: + Serialise("Texture3D.MipLevels", el.Texture3D.MipLevels); + Serialise("Texture3D.MostDetailedMip", el.Texture3D.MostDetailedMip); + break; + case D3D11_SRV_DIMENSION_TEXTURECUBE: + Serialise("TextureCube.MipLevels", el.TextureCube.MipLevels); + Serialise("TextureCube.MostDetailedMip", el.TextureCube.MostDetailedMip); + break; + case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: + Serialise("TextureCubeArray.MipLevels", el.TextureCubeArray.MipLevels); + Serialise("TextureCubeArray.MostDetailedMip", el.TextureCubeArray.MostDetailedMip); + Serialise("TextureCubeArray.NumCubes", el.TextureCubeArray.NumCubes); + Serialise("TextureCubeArray.First2DArrayFace", el.TextureCubeArray.First2DArrayFace); + break; + case D3D11_SRV_DIMENSION_BUFFEREX: + Serialise("Buffer.FirstElement", el.BufferEx.FirstElement); + Serialise("Buffer.NumElements", el.BufferEx.NumElements); + Serialise("Buffer.Flags", el.BufferEx.Flags); + break; + default: + RDCERR("Unrecognised SRV Dimension %d", el.ViewDimension); + break; + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_RENDER_TARGET_VIEW_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_RENDER_TARGET_VIEW_DESC", 0, true); + Serialise("Format", el.Format); + Serialise("ViewDimension", el.ViewDimension); + + switch(el.ViewDimension) + { + case D3D11_RTV_DIMENSION_BUFFER: + Serialise("Buffer.FirstElement", el.Buffer.FirstElement); + Serialise("Buffer.NumElements", el.Buffer.NumElements); + break; + case D3D11_RTV_DIMENSION_TEXTURE1D: + Serialise("Texture1D.MipSlice", el.Texture1D.MipSlice); + break; + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + Serialise("Texture1DArray.MipSlice", el.Texture1DArray.MipSlice); + Serialise("Texture1DArray.ArraySize", el.Texture1DArray.ArraySize); + Serialise("Texture1DArray.FirstArraySlice", el.Texture1DArray.FirstArraySlice); + break; + case D3D11_RTV_DIMENSION_TEXTURE2D: + Serialise("Texture2D.MipSlice", el.Texture2D.MipSlice); + break; + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + Serialise("Texture2DArray.MipSlice", el.Texture2DArray.MipSlice); + Serialise("Texture2DArray.ArraySize", el.Texture2DArray.ArraySize); + Serialise("Texture2DArray.FirstArraySlice", el.Texture2DArray.FirstArraySlice); + break; + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + // el.Texture2DMS.UnusedField_NothingToDefine + break; + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + Serialise("Texture2DMSArray.ArraySize", el.Texture2DMSArray.ArraySize); + Serialise("Texture2DMSArray.FirstArraySlice", el.Texture2DMSArray.FirstArraySlice); + break; + case D3D11_RTV_DIMENSION_TEXTURE3D: + Serialise("Texture3D.MipSlice", el.Texture3D.MipSlice); + Serialise("Texture3D.FirstWSlice", el.Texture3D.FirstWSlice); + Serialise("Texture3D.WSize", el.Texture3D.WSize); + break; + default: + RDCERR("Unrecognised RTV Dimension %d", el.ViewDimension); + break; + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_UNORDERED_ACCESS_VIEW_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_UNORDERED_ACCESS_VIEW_DESC", 0, true); + Serialise("Format", el.Format); + Serialise("ViewDimension", el.ViewDimension); + + switch(el.ViewDimension) + { + case D3D11_UAV_DIMENSION_BUFFER: + Serialise("Buffer.FirstElement", el.Buffer.FirstElement); + Serialise("Buffer.NumElements", el.Buffer.NumElements); + Serialise("Buffer.Flags", el.Buffer.Flags); + break; + case D3D11_UAV_DIMENSION_TEXTURE1D: + Serialise("Texture1D.MipSlice", el.Texture1D.MipSlice); + break; + case D3D11_UAV_DIMENSION_TEXTURE1DARRAY: + Serialise("Texture1DArray.MipSlice", el.Texture1DArray.MipSlice); + Serialise("Texture1DArray.ArraySize", el.Texture1DArray.ArraySize); + Serialise("Texture1DArray.FirstArraySlice", el.Texture1DArray.FirstArraySlice); + break; + case D3D11_UAV_DIMENSION_TEXTURE2D: + Serialise("Texture2D.MipSlice", el.Texture2D.MipSlice); + break; + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + Serialise("Texture2DArray.MipSlice", el.Texture2DArray.MipSlice); + Serialise("Texture2DArray.ArraySize", el.Texture2DArray.ArraySize); + Serialise("Texture2DArray.FirstArraySlice", el.Texture2DArray.FirstArraySlice); + break; + case D3D11_UAV_DIMENSION_TEXTURE3D: + Serialise("Texture3D.MipSlice", el.Texture3D.MipSlice); + Serialise("Texture3D.FirstWSlice", el.Texture3D.FirstWSlice); + Serialise("Texture3D.WSize", el.Texture3D.WSize); + break; + default: + RDCERR("Unrecognised RTV Dimension %d", el.ViewDimension); + break; + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_DEPTH_STENCIL_VIEW_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_DEPTH_STENCIL_VIEW_DESC", 0, true); + Serialise("Format", el.Format); + Serialise("Flags", el.Flags); + Serialise("ViewDimension", el.ViewDimension); + + switch(el.ViewDimension) + { + case D3D11_DSV_DIMENSION_TEXTURE1D: + Serialise("Texture1D.MipSlice", el.Texture1D.MipSlice); + break; + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + Serialise("Texture1DArray.MipSlice", el.Texture1DArray.MipSlice); + Serialise("Texture1DArray.ArraySize", el.Texture1DArray.ArraySize); + Serialise("Texture1DArray.FirstArraySlice", el.Texture1DArray.FirstArraySlice); + break; + case D3D11_DSV_DIMENSION_TEXTURE2D: + Serialise("Texture2D.MipSlice", el.Texture2D.MipSlice); + break; + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + Serialise("Texture2DArray.MipSlice", el.Texture2DArray.MipSlice); + Serialise("Texture2DArray.ArraySize", el.Texture2DArray.ArraySize); + Serialise("Texture2DArray.FirstArraySlice", el.Texture2DArray.FirstArraySlice); + break; + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + // el.Texture2DMS.UnusedField_NothingToDefine + break; + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + Serialise("Texture2DMSArray.ArraySize", el.Texture2DMSArray.ArraySize); + Serialise("Texture2DMSArray.FirstArraySlice", el.Texture2DMSArray.FirstArraySlice); + break; + default: + RDCERR("Unrecognised DSV Dimension %d", el.ViewDimension); + break; + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_BLEND_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_BLEND_DESC", 0, true); + + Serialise("AlphaToCoverageEnable", el.AlphaToCoverageEnable); + Serialise("IndependentBlendEnable", el.IndependentBlendEnable); + for(int i=0; i < 8; i++) + { + ScopedContext scope(this, this, name, "D3D11_RENDER_TARGET_BLEND_DESC", 0, true); + + bool enable = el.RenderTarget[i].BlendEnable == TRUE; + Serialise("BlendEnable", enable); + el.RenderTarget[i].BlendEnable = enable; + + { + Serialise("SrcBlend", el.RenderTarget[i].SrcBlend); + Serialise("DestBlend", el.RenderTarget[i].DestBlend); + Serialise("BlendOp", el.RenderTarget[i].BlendOp); + Serialise("SrcBlendAlpha", el.RenderTarget[i].SrcBlendAlpha); + Serialise("DestBlendAlpha", el.RenderTarget[i].DestBlendAlpha); + Serialise("BlendOpAlpha", el.RenderTarget[i].BlendOpAlpha); + } + + Serialise("RenderTargetWriteMask", el.RenderTarget[i].RenderTargetWriteMask); + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_BLEND_DESC1 &el) +{ + ScopedContext scope(this, this, name, "D3D11_BLEND_DESC1", 0, true); + + Serialise("AlphaToCoverageEnable", el.AlphaToCoverageEnable); + Serialise("IndependentBlendEnable", el.IndependentBlendEnable); + for(int i=0; i < 8; i++) + { + ScopedContext scope(this, this, name, "D3D11_RENDER_TARGET_BLEND_DESC1", 0, true); + + bool enable = el.RenderTarget[i].BlendEnable == TRUE; + Serialise("BlendEnable", enable); + el.RenderTarget[i].BlendEnable = enable; + + enable = el.RenderTarget[i].LogicOpEnable == TRUE; + Serialise("LogicOpEnable", enable); + el.RenderTarget[i].LogicOpEnable = enable; + + { + Serialise("SrcBlend", el.RenderTarget[i].SrcBlend); + Serialise("DestBlend", el.RenderTarget[i].DestBlend); + Serialise("BlendOp", el.RenderTarget[i].BlendOp); + Serialise("SrcBlendAlpha", el.RenderTarget[i].SrcBlendAlpha); + Serialise("DestBlendAlpha", el.RenderTarget[i].DestBlendAlpha); + Serialise("BlendOpAlpha", el.RenderTarget[i].BlendOpAlpha); + Serialise("LogicOp", el.RenderTarget[i].LogicOp); + } + + Serialise("RenderTargetWriteMask", el.RenderTarget[i].RenderTargetWriteMask); + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_DEPTH_STENCIL_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_DEPTH_STENCIL_DESC", 0, true); + + Serialise("DepthEnable", el.DepthEnable); + Serialise("DepthWriteMask", el.DepthWriteMask); + Serialise("DepthFunc", el.DepthFunc); + Serialise("StencilEnable", el.StencilEnable); + Serialise("StencilReadMask", el.StencilReadMask); + Serialise("StencilWriteMask", el.StencilWriteMask); + + { + ScopedContext scope(this, this, name, "D3D11_DEPTH_STENCILOP_DESC", 0, true); + Serialise("FrontFace.StencilFailOp", el.FrontFace.StencilFailOp); + Serialise("FrontFace.StencilDepthFailOp", el.FrontFace.StencilDepthFailOp); + Serialise("FrontFace.StencilPassOp", el.FrontFace.StencilPassOp); + Serialise("FrontFace.StencilFunc", el.FrontFace.StencilFunc); + } + { + ScopedContext scope(this, this, name, "D3D11_DEPTH_STENCILOP_DESC", 0, true); + Serialise("BackFace.StencilFailOp", el.BackFace.StencilFailOp); + Serialise("BackFace.StencilDepthFailOp", el.BackFace.StencilDepthFailOp); + Serialise("BackFace.StencilPassOp", el.BackFace.StencilPassOp); + Serialise("BackFace.StencilFunc", el.BackFace.StencilFunc); + } +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_RASTERIZER_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_RASTERIZER_DESC", 0, true); + + Serialise("FillMode", el.FillMode); + Serialise("CullMode", el.CullMode); + Serialise("FrontCounterClockwise", el.FrontCounterClockwise); + Serialise("DepthBias", el.DepthBias); + Serialise("DepthBiasClamp", el.DepthBiasClamp); + Serialise("SlopeScaledDepthBias", el.SlopeScaledDepthBias); + Serialise("DepthClipEnable", el.DepthClipEnable); + Serialise("ScissorEnable", el.ScissorEnable); + Serialise("MultisampleEnable", el.MultisampleEnable); + Serialise("AntialiasedLineEnable", el.AntialiasedLineEnable); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_RASTERIZER_DESC1 &el) +{ + ScopedContext scope(this, this, name, "D3D11_RASTERIZER_DESC1", 0, true); + + Serialise("FillMode", el.FillMode); + Serialise("CullMode", el.CullMode); + Serialise("FrontCounterClockwise", el.FrontCounterClockwise); + Serialise("DepthBias", el.DepthBias); + Serialise("DepthBiasClamp", el.DepthBiasClamp); + Serialise("SlopeScaledDepthBias", el.SlopeScaledDepthBias); + Serialise("DepthClipEnable", el.DepthClipEnable); + Serialise("ScissorEnable", el.ScissorEnable); + Serialise("MultisampleEnable", el.MultisampleEnable); + Serialise("AntialiasedLineEnable", el.AntialiasedLineEnable); + Serialise("ForcedSampleCount", el.ForcedSampleCount); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_QUERY_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_QUERY_DESC", 0, true); + + Serialise("MiscFlags", el.MiscFlags); + Serialise("Query", el.Query); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_COUNTER_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_COUNTER_DESC", 0, true); + + Serialise("MiscFlags", el.MiscFlags); + Serialise("Counter", el.Counter); +} + +template<> +void Serialiser::Serialise(const char *name, D3D11_SAMPLER_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_SAMPLER_DESC", 0, true); + + Serialise("Filter", el.Filter); + Serialise("AddressU", el.AddressU); + Serialise("AddressV", el.AddressV); + Serialise("AddressW", el.AddressW); + Serialise("MipLODBias", el.MipLODBias); + Serialise("MaxAnisotropy", el.MaxAnisotropy); + Serialise("ComparisonFunc", el.ComparisonFunc); + Serialise<4>("BorderColor", el.BorderColor); + Serialise("MinLOD", el.MinLOD); + Serialise("MaxLOD", el.MaxLOD); +} + +template<> void Serialiser::Serialise(const char *name, D3D11_SO_DECLARATION_ENTRY &el) +{ + ScopedContext scope(this, this, name, "D3D11_SO_DECLARATION_ENTRY", 0, true); + + string s; + if(m_Mode >= WRITING) + s = el.SemanticName; + + Serialise("SemanticName", s); + + if(m_Mode == READING) + { + string str = (char *)m_BufferHead-s.length(); + m_StringDB.insert(str); + el.SemanticName = m_StringDB.find(str)->c_str(); + } + + // so we can just take a char* into the buffer above for the semantic name, + // ensure we serialise a null terminator (slightly redundant because the above + // serialise of the string wrote out the length, but not the end of the world). + char nullterminator = 0; + Serialise(NULL, nullterminator); + + Serialise("SemanticIndex", el.SemanticIndex); + Serialise("Stream", el.Stream); + Serialise("StartComponent", el.StartComponent); + Serialise("ComponentCount", el.ComponentCount); + Serialise("OutputSlot", el.OutputSlot); +} + +template<> void Serialiser::Serialise(const char *name, D3D11_INPUT_ELEMENT_DESC &el) +{ + ScopedContext scope(this, this, name, "D3D11_INPUT_ELEMENT_DESC", 0, true); + + string s; + if(m_Mode >= WRITING) + s = el.SemanticName; + + Serialise("SemanticName", s); + + if(m_Mode == READING) + { + string str = (char *)m_BufferHead-s.length(); + m_StringDB.insert(str); + el.SemanticName = m_StringDB.find(str)->c_str(); + } + + // so we can just take a char* into the buffer above for the semantic name, + // ensure we serialise a null terminator (slightly redundant because the above + // serialise of the string wrote out the length, but not the end of the world). + char nullterminator = 0; + Serialise(NULL, nullterminator); + + Serialise("SemanticIndex", el.SemanticIndex); + Serialise("Format", el.Format); + Serialise("InputSlot", el.InputSlot); + Serialise("AlignedByteOffset", el.AlignedByteOffset); + Serialise("InputSlotClass", el.InputSlotClass); + Serialise("InstanceDataStepRate", el.InstanceDataStepRate); +} + +template<> void Serialiser::Serialise(const char *name, D3D11_SUBRESOURCE_DATA &el) +{ + ScopedContext scope(this, this, name, "D3D11_SUBRESOURCE_DATA", 0, true); + + // el.pSysMem + Serialise("SysMemPitch", el.SysMemPitch); + Serialise("SysMemSlicePitch", el.SysMemSlicePitch); +} + + +///////////////////////////////////////////////////////////// +// Trivial structures + +string ToStrHelper::Get(const IID &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "GUID {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + el.Data1, (unsigned int)el.Data2, (unsigned int)el.Data3, + el.Data4[0], el.Data4[1], el.Data4[2], el.Data4[3], + el.Data4[4], el.Data4[5], el.Data4[6], el.Data4[7]); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_VIEWPORT &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "Viewport<%.0fx%.0f+%.0f+%.0f>", el.Width, el.Height, el.TopLeftX, el.TopLeftY); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_RECT &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "RECT<%d,%d,%d,%d>", el.left, el.right, el.top, el.bottom); + + return tostrBuf; +} + + +string ToStrHelper::Get(const D3D11_BOX &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "BOX<%d,%d,%d,%d,%d,%d>", el.left, el.right, el.top, el.bottom, el.front, el.back); + + return tostrBuf; +} + +string ToStrHelper::Get(const DXGI_SAMPLE_DESC &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "DXGI_SAMPLE_DESC<%d,%d>", el.Count, el.Quality); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_BIND_FLAG &el) +{ + string ret; + + if(el & D3D11_BIND_VERTEX_BUFFER) ret += " | D3D11_BIND_VERTEX_BUFFER"; + if(el & D3D11_BIND_INDEX_BUFFER) ret += " | D3D11_BIND_INDEX_BUFFER"; + if(el & D3D11_BIND_CONSTANT_BUFFER) ret += " | D3D11_BIND_CONSTANT_BUFFER"; + if(el & D3D11_BIND_SHADER_RESOURCE) ret += " | D3D11_BIND_SHADER_RESOURCE"; + if(el & D3D11_BIND_STREAM_OUTPUT) ret += " | D3D11_BIND_STREAM_OUTPUT"; + if(el & D3D11_BIND_RENDER_TARGET) ret += " | D3D11_BIND_RENDER_TARGET"; + if(el & D3D11_BIND_DEPTH_STENCIL) ret += " | D3D11_BIND_DEPTH_STENCIL"; + if(el & D3D11_BIND_UNORDERED_ACCESS) ret += " | D3D11_BIND_UNORDERED_ACCESS"; + + if(!ret.empty()) + ret = ret.substr(3); + + return ret; +} + +string ToStrHelper::Get(const D3D11_CPU_ACCESS_FLAG &el) +{ + string ret; + + if(el & D3D11_CPU_ACCESS_READ) ret += " | D3D11_CPU_ACCESS_READ"; + if(el & D3D11_CPU_ACCESS_WRITE) ret += " | D3D11_CPU_ACCESS_WRITE"; + + if(!ret.empty()) + ret = ret.substr(3); + + return ret; +} + +string ToStrHelper::Get(const D3D11_RESOURCE_MISC_FLAG &el) +{ + string ret; + + if(el & D3D11_RESOURCE_MISC_GENERATE_MIPS) ret + " | D3D11_RESOURCE_MISC_GENERATE_MIPS"; + if(el & D3D11_RESOURCE_MISC_SHARED) ret + " | D3D11_RESOURCE_MISC_SHARED"; + if(el & D3D11_RESOURCE_MISC_TEXTURECUBE) ret + " | D3D11_RESOURCE_MISC_TEXTURECUBE"; + if(el & D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS) ret + " | D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS"; + if(el & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) ret + " | D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS"; + if(el & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) ret + " | D3D11_RESOURCE_MISC_BUFFER_STRUCTURED"; + if(el & D3D11_RESOURCE_MISC_RESOURCE_CLAMP) ret + " | D3D11_RESOURCE_MISC_RESOURCE_CLAMP"; + if(el & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) ret + " | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX"; + if(el & D3D11_RESOURCE_MISC_GDI_COMPATIBLE) ret + " | D3D11_RESOURCE_MISC_GDI_COMPATIBLE"; + + if(!ret.empty()) + ret = ret.substr(3); + + return ret; +} + +///////////////////////////////////////////////////////////// +// Enums and lists + +string ToStrHelper::Get(const D3D11_DEPTH_WRITE_MASK &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_DEPTH_WRITE_MASK_ZERO) + TOSTR_CASE_STRINGIZE(D3D11_DEPTH_WRITE_MASK_ALL) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_DEPTH_WRITE_MASK<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_COMPARISON_FUNC &el) +{ + switch(el) + { + case D3D11_COMPARISON_NEVER: return "NEVER"; + case D3D11_COMPARISON_LESS: return "LESS"; + case D3D11_COMPARISON_EQUAL: return "EQUAL"; + case D3D11_COMPARISON_LESS_EQUAL: return "LESS_EQUAL"; + case D3D11_COMPARISON_GREATER: return "GREATER"; + case D3D11_COMPARISON_NOT_EQUAL: return "NOT_EQUAL"; + case D3D11_COMPARISON_GREATER_EQUAL: return "GREATER_EQUAL"; + case D3D11_COMPARISON_ALWAYS: return "ALWAYS"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_COMPARISON_FUNC<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_STENCIL_OP &el) +{ + switch(el) + { + case D3D11_STENCIL_OP_KEEP: return "KEEP"; + case D3D11_STENCIL_OP_ZERO: return "ZERO"; + case D3D11_STENCIL_OP_REPLACE: return "REPLACE"; + case D3D11_STENCIL_OP_INCR_SAT: return "INCR_SAT"; + case D3D11_STENCIL_OP_DECR_SAT: return "DECR_SAT"; + case D3D11_STENCIL_OP_INVERT: return "INVERT"; + case D3D11_STENCIL_OP_INCR: return "INCR"; + case D3D11_STENCIL_OP_DECR: return "DECR"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_STENCIL_OP<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_BLEND &el) +{ + switch(el) + { + case D3D11_BLEND_ZERO: return "ZERO"; + case D3D11_BLEND_ONE: return "ONE"; + case D3D11_BLEND_SRC_COLOR: return "SRC_COLOR"; + case D3D11_BLEND_INV_SRC_COLOR: return "INV_SRC_COLOR"; + case D3D11_BLEND_SRC_ALPHA: return "SRC_ALPHA"; + case D3D11_BLEND_INV_SRC_ALPHA: return "INV_SRC_ALPHA"; + case D3D11_BLEND_DEST_ALPHA: return "DEST_ALPHA"; + case D3D11_BLEND_INV_DEST_ALPHA: return "INV_DEST_ALPHA"; + case D3D11_BLEND_DEST_COLOR: return "DEST_COLOR"; + case D3D11_BLEND_INV_DEST_COLOR: return "INV_DEST_COLOR"; + case D3D11_BLEND_SRC_ALPHA_SAT: return "SRC_ALPHA_SAT"; + case D3D11_BLEND_BLEND_FACTOR: return "BLEND_FACTOR"; + case D3D11_BLEND_INV_BLEND_FACTOR: return "INV_BLEND_FACTOR"; + case D3D11_BLEND_SRC1_COLOR: return "SRC1_COLOR"; + case D3D11_BLEND_INV_SRC1_COLOR: return "INV_SRC1_COLOR"; + case D3D11_BLEND_SRC1_ALPHA: return "SRC1_ALPHA"; + case D3D11_BLEND_INV_SRC1_ALPHA: return "INV_SRC1_ALPHA"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_BLEND<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_BLEND_OP &el) +{ + switch(el) + { + case D3D11_BLEND_OP_ADD: return "ADD"; + case D3D11_BLEND_OP_SUBTRACT: return "SUBTRACT"; + case D3D11_BLEND_OP_REV_SUBTRACT: return "REV_SUBTRACT"; + case D3D11_BLEND_OP_MIN: return "MIN"; + case D3D11_BLEND_OP_MAX: return "MAX"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_BLEND_OP<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_LOGIC_OP &el) +{ + switch(el) + { + case D3D11_LOGIC_OP_CLEAR: return "CLEAR"; + case D3D11_LOGIC_OP_SET: return "SET"; + case D3D11_LOGIC_OP_COPY: return "COPY"; + case D3D11_LOGIC_OP_COPY_INVERTED: return "COPY_INVERTED"; + case D3D11_LOGIC_OP_NOOP: return "NOOP"; + case D3D11_LOGIC_OP_INVERT: return "INVERT"; + case D3D11_LOGIC_OP_AND: return "AND"; + case D3D11_LOGIC_OP_NAND: return "NAND"; + case D3D11_LOGIC_OP_OR: return "OR"; + case D3D11_LOGIC_OP_NOR: return "NOR"; + case D3D11_LOGIC_OP_XOR: return "XOR"; + case D3D11_LOGIC_OP_EQUIV: return "EQUIV"; + case D3D11_LOGIC_OP_AND_REVERSE: return "AND_REVERSE"; + case D3D11_LOGIC_OP_AND_INVERTED: return "AND_INVERTED"; + case D3D11_LOGIC_OP_OR_REVERSE: return "OR_REVERSE"; + case D3D11_LOGIC_OP_OR_INVERTED: return "OR_INVERTED"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_LOGIC_OP<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_CULL_MODE &el) +{ + switch(el) + { + case D3D11_CULL_NONE: return "NONE"; + case D3D11_CULL_FRONT: return "FRONT"; + case D3D11_CULL_BACK: return "BACK"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_CULL_MODE<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_FILL_MODE &el) +{ + switch(el) + { + case D3D11_FILL_WIREFRAME: return "WIREFRAME"; + case D3D11_FILL_SOLID: return "SOLID"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_FILL_MODE<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_TEXTURE_ADDRESS_MODE &el) +{ + switch(el) + { + case D3D11_TEXTURE_ADDRESS_WRAP: return "WRAP"; + case D3D11_TEXTURE_ADDRESS_MIRROR: return "MIRROR"; + case D3D11_TEXTURE_ADDRESS_CLAMP: return "CLAMP"; + case D3D11_TEXTURE_ADDRESS_BORDER: return "BORDER"; + case D3D11_TEXTURE_ADDRESS_MIRROR_ONCE: return "MIRROR_ONCE"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_TEXTURE_ADDRESS_MODE<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_FILTER &el) +{ + switch(el) + { + case D3D11_FILTER_MIN_MAG_MIP_POINT: return "MIN_MAG_MIP_POINT"; + case D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR: return "MIN_MAG_POINT_MIP_LINEAR"; + case D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT: return "MIN_POINT_MAG_LINEAR_MIP_POINT"; + case D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR: return "MIN_POINT_MAG_MIP_LINEAR"; + case D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT: return "MIN_LINEAR_MAG_MIP_POINT"; + case D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR: return "MIN_LINEAR_MAG_POINT_MIP_LINEAR"; + case D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT: return "MIN_MAG_LINEAR_MIP_POINT"; + case D3D11_FILTER_MIN_MAG_MIP_LINEAR: return "MIN_MAG_MIP_LINEAR"; + case D3D11_FILTER_ANISOTROPIC: return "ANISOTROPIC"; + case D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT: return "CMP_MIN_MAG_MIP_POINT"; + case D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR: return "CMP_MIN_MAG_POINT_MIP_LINEAR"; + case D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT: return "CMP_MIN_POINT_MAG_LINEAR_MIP_POINT"; + case D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR: return "CMP_MIN_POINT_MAG_MIP_LINEAR"; + case D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT: return "CMP_MIN_LINEAR_MAG_MIP_POINT"; + case D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR: return "CMP_MIN_LINEAR_MAG_POINT_MIP_LINEAR"; + case D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT: return "CMP_MIN_MAG_LINEAR_MIP_POINT"; + case D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR: return "CMP_MIN_MAG_MIP_LINEAR"; + case D3D11_FILTER_COMPARISON_ANISOTROPIC: return "CMP_ANISOTROPIC"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_FILTER<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_SRV_DIMENSION &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_BUFFER) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE1D) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE1DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE2D) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE2DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE2DMS) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURE3D) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURECUBE) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) + TOSTR_CASE_STRINGIZE(D3D11_SRV_DIMENSION_BUFFEREX) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_SRV_DIMENSION<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_RTV_DIMENSION &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_BUFFER) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE1D) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE1DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE2D) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE2DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE2DMS) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY) + TOSTR_CASE_STRINGIZE(D3D11_RTV_DIMENSION_TEXTURE3D) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_RTV_DIMENSION<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_UAV_DIMENSION &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_UAV_DIMENSION_BUFFER) + TOSTR_CASE_STRINGIZE(D3D11_UAV_DIMENSION_TEXTURE1D) + TOSTR_CASE_STRINGIZE(D3D11_UAV_DIMENSION_TEXTURE1DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_UAV_DIMENSION_TEXTURE2D) + TOSTR_CASE_STRINGIZE(D3D11_UAV_DIMENSION_TEXTURE2DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_UAV_DIMENSION_TEXTURE3D) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_UAV_DIMENSION<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_DSV_DIMENSION &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_DSV_DIMENSION_TEXTURE1D) + TOSTR_CASE_STRINGIZE(D3D11_DSV_DIMENSION_TEXTURE1DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_DSV_DIMENSION_TEXTURE2D) + TOSTR_CASE_STRINGIZE(D3D11_DSV_DIMENSION_TEXTURE2DARRAY) + TOSTR_CASE_STRINGIZE(D3D11_DSV_DIMENSION_TEXTURE2DMS) + TOSTR_CASE_STRINGIZE(D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_DSV_DIMENSION<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D_FEATURE_LEVEL &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_9_1) + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_9_2) + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_9_3) + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_10_0) + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_10_1) + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_11_0) + TOSTR_CASE_STRINGIZE(D3D_FEATURE_LEVEL_11_1) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D_FEATURE_LEVEL<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D_DRIVER_TYPE &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D_DRIVER_TYPE_HARDWARE) + TOSTR_CASE_STRINGIZE(D3D_DRIVER_TYPE_REFERENCE) + TOSTR_CASE_STRINGIZE(D3D_DRIVER_TYPE_NULL) + TOSTR_CASE_STRINGIZE(D3D_DRIVER_TYPE_SOFTWARE) + TOSTR_CASE_STRINGIZE(D3D_DRIVER_TYPE_WARP) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D_DRIVER_TYPE<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_QUERY &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_QUERY_EVENT) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_OCCLUSION) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_TIMESTAMP) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_TIMESTAMP_DISJOINT) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_PIPELINE_STATISTICS) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_OCCLUSION_PREDICATE) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_STATISTICS) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_OVERFLOW_PREDICATE) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_STATISTICS_STREAM0) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_STATISTICS_STREAM1) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_STATISTICS_STREAM2) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_STATISTICS_STREAM3) + TOSTR_CASE_STRINGIZE(D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_QUERY<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_COUNTER &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_COUNTER_DEVICE_DEPENDENT_0) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_COUNTER<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_MAP &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_MAP_READ) + TOSTR_CASE_STRINGIZE(D3D11_MAP_WRITE) + TOSTR_CASE_STRINGIZE(D3D11_MAP_READ_WRITE) + TOSTR_CASE_STRINGIZE(D3D11_MAP_WRITE_DISCARD) + TOSTR_CASE_STRINGIZE(D3D11_MAP_WRITE_NO_OVERWRITE) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_MAP<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_PRIMITIVE_TOPOLOGY &el) +{ + switch(el) + { + case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST: return "PointList"; + case D3D11_PRIMITIVE_TOPOLOGY_LINELIST: return "LineList"; + case D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP: return "LineStrip"; + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST: return "TriangleList"; + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: return "TriangleStrip"; + case D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: return "LineListAdj"; + case D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: return "LineStripAdj"; + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: return "TriangleListAdj"; + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: return "TriangleStripAdj"; + default: break; + } + + char tostrBuf[256] = {0}; + + if(el >= D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST && + el <= D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) + { + StringFormat::snprintf(tostrBuf, 255, "Patchlist_%dCPs", el-D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST+1); + } + else + { + StringFormat::snprintf(tostrBuf, 255, "D3D11_PRIMITIVE_TOPOLOGY<%d>", el); + } + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_USAGE &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_USAGE_DEFAULT) + TOSTR_CASE_STRINGIZE(D3D11_USAGE_IMMUTABLE) + TOSTR_CASE_STRINGIZE(D3D11_USAGE_DYNAMIC) + TOSTR_CASE_STRINGIZE(D3D11_USAGE_STAGING) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_USAGE<%d>", el); + + return tostrBuf; +} + +string ToStrHelper::Get(const D3D11_INPUT_CLASSIFICATION &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D11_INPUT_PER_VERTEX_DATA) + TOSTR_CASE_STRINGIZE(D3D11_INPUT_PER_INSTANCE_DATA) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "D3D11_INPUT_CLASSIFICATION<%d>", el); + + return tostrBuf; +} + + +string ToStrHelper::Get(const DXGI_FORMAT &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32A32_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32A32_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32A32_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32A32_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32B32_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16B16A16_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16B16A16_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16B16A16_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16B16A16_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16B16A16_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16B16A16_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G32_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32G8X24_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_D32_FLOAT_S8X24_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R10G10B10A2_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R10G10B10A2_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R10G10B10A2_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R11G11B10_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8B8A8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8B8A8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8B8A8_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8B8A8_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8B8A8_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16G16_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_D32_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R32_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R24G8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_D24_UNORM_S8_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R24_UNORM_X8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_X24_TYPELESS_G8_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16_FLOAT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_D16_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R16_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8_UINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8_SINT) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_A8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R1_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R9G9B9E5_SHAREDEXP) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R8G8_B8G8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_G8R8_G8B8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC1_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC1_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC1_UNORM_SRGB) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC2_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC2_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC2_UNORM_SRGB) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC3_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC3_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC3_UNORM_SRGB) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC4_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC4_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC4_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC5_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC5_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC5_SNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B5G6R5_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B5G5R5A1_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B8G8R8A8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B8G8R8X8_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B8G8R8A8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B8G8R8X8_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC6H_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC6H_UF16) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC6H_SF16) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC7_TYPELESS) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC7_UNORM) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_BC7_UNORM_SRGB) + + // D3D11.1 formats + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_AYUV) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_Y410) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_Y416) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_NV12) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_P010) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_P016) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_420_OPAQUE) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_YUY2) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_Y210) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_Y216) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_NV11) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_AI44) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_IA44) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_P8) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_A8P8) + TOSTR_CASE_STRINGIZE(DXGI_FORMAT_B4G4R4A4_UNORM) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "DXGI_FORMAT<%d>", el); + + return tostrBuf; +} diff --git a/renderdoc/driver/d3d11/d3d11_common.h b/renderdoc/driver/d3d11/d3d11_common.h new file mode 100644 index 0000000000..98471badae --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_common.h @@ -0,0 +1,300 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#define INITGUID + +#include +#include + +#include "replay/renderdoc.h" +#include "core/core.h" + +class WrappedID3D11Device; +struct D3D11RenderState; + +HMODULE GetD3DCompiler(); + +ResourceFormat MakeResourceFormat(DXGI_FORMAT fmt); +DXGI_FORMAT MakeDXGIFormat(ResourceFormat fmt); + +ShaderReflection *MakeShaderReflection(DXBC::DXBCFile *dxbc); + +template +inline void SetDebugName( T* pObj, const char* name ) +{ + if(pObj) pObj->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)strlen(name), name); +} + +template +inline const char* GetDebugName( T* pObj ) +{ + static char tmpBuf[1024] = {0}; + UINT size = 1023; + if(pObj) + { + HRESULT hr = pObj->GetPrivateData(WKPDID_D3DDebugObjectName, &size, tmpBuf); + if(FAILED(hr)) return ""; + + tmpBuf[size] = 0; + return tmpBuf; + } + return ""; +} + +class RefCounter +{ +private: + IUnknown *m_pReal; + unsigned int m_iRefcount; + bool m_SelfDeleting; +protected: + void SetSelfDeleting(bool selfDelete) { m_SelfDeleting = selfDelete; } + + // used for derived classes that need to soft ref but are handling their + // own self-deletion + static void AddDeviceSoftref(WrappedID3D11Device *device); + static void ReleaseDeviceSoftref(WrappedID3D11Device *device); + +public: + RefCounter(IUnknown *real, bool selfDelete = true) : m_pReal(real), m_iRefcount(1), m_SelfDeleting(selfDelete) {} + virtual ~RefCounter() {} + + unsigned int GetRefCount() { return m_iRefcount; } + + ////////////////////////////// + // implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface( + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG STDMETHODCALLTYPE AddRef() + { + InterlockedIncrement(&m_iRefcount); + return m_iRefcount; + } + ULONG STDMETHODCALLTYPE Release() + { + unsigned int ret = InterlockedDecrement(&m_iRefcount); + if(ret == 0 && m_SelfDeleting) + delete this; + return ret; + } + + unsigned int SoftRef(WrappedID3D11Device *device); + unsigned int SoftRelease(WrappedID3D11Device *device); +}; + +#define IMPLEMENT_IUNKNOWN_WITH_REFCOUNTER \ + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter::AddRef(); } \ + ULONG STDMETHODCALLTYPE Release() { return RefCounter::Release(); } \ + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { return RefCounter::QueryInterface(riid, ppvObject); } + +#define IMPLEMENT_IUNKNOWN_WITH_REFCOUNTER_CUSTOMQUERY \ + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter::AddRef(); } \ + ULONG STDMETHODCALLTYPE Release() { return RefCounter::Release(); } + +#define IMPLEMENT_FUNCTION_SERIALISED(ret, func) ret func; bool CONCAT(Serialise_, func); + +#include "serialise/serialiser.h" + +#include + +// I don't really like this but it's not the end of the world - declare d3d specialisations to enforce +// that this specialisation gets used. +template<> void Serialiser::Serialise(const char *name, D3D11_BUFFER_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_TEXTURE1D_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_TEXTURE2D_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_TEXTURE3D_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_SHADER_RESOURCE_VIEW_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_RENDER_TARGET_VIEW_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_DEPTH_STENCIL_VIEW_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_UNORDERED_ACCESS_VIEW_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_BLEND_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_BLEND_DESC1 &el); +template<> void Serialiser::Serialise(const char *name, D3D11_DEPTH_STENCIL_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_RASTERIZER_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_RASTERIZER_DESC1 &el); +template<> void Serialiser::Serialise(const char *name, D3D11_SAMPLER_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_QUERY_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_COUNTER_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_INPUT_ELEMENT_DESC &el); +template<> void Serialiser::Serialise(const char *name, D3D11_SO_DECLARATION_ENTRY &el); +template<> void Serialiser::Serialise(const char *name, D3D11_SUBRESOURCE_DATA &el); + +#pragma region Chunks + +enum D3D11ChunkType +{ + DEVICE_INIT = FIRST_CHUNK_ID, + SET_RESOURCE_NAME, + RELEASE_RESOURCE, + CREATE_SWAP_BUFFER, + + CREATE_TEXTURE_1D, + CREATE_TEXTURE_2D, + CREATE_TEXTURE_3D, + CREATE_BUFFER, + CREATE_VERTEX_SHADER, + CREATE_HULL_SHADER, + CREATE_DOMAIN_SHADER, + CREATE_GEOMETRY_SHADER, + CREATE_GEOMETRY_SHADER_WITH_SO, + CREATE_PIXEL_SHADER, + CREATE_COMPUTE_SHADER, + GET_CLASS_INSTANCE, + CREATE_CLASS_INSTANCE, + CREATE_CLASS_LINKAGE, + CREATE_SRV, + CREATE_RTV, + CREATE_DSV, + CREATE_UAV, + CREATE_INPUT_LAYOUT, + CREATE_BLEND_STATE, + CREATE_DEPTHSTENCIL_STATE, + CREATE_RASTER_STATE, + CREATE_SAMPLER_STATE, + CREATE_QUERY, + CREATE_PREDICATE, + CREATE_COUNTER, + CREATE_DEFERRED_CONTEXT, + SET_EXCEPTION_MODE, + OPEN_SHARED_RESOURCE, + + CAPTURE_SCOPE, + + SET_INPUT_LAYOUT, + FIRST_CONTEXT_CHUNK = SET_INPUT_LAYOUT, + SET_VBUFFER, + SET_IBUFFER, + SET_TOPOLOGY, + + SET_VS_CBUFFERS, + SET_VS_RESOURCES, + SET_VS_SAMPLERS, + SET_VS, + + SET_HS_CBUFFERS, + SET_HS_RESOURCES, + SET_HS_SAMPLERS, + SET_HS, + + SET_DS_CBUFFERS, + SET_DS_RESOURCES, + SET_DS_SAMPLERS, + SET_DS, + + SET_GS_CBUFFERS, + SET_GS_RESOURCES, + SET_GS_SAMPLERS, + SET_GS, + + SET_SO_TARGETS, + + SET_PS_CBUFFERS, + SET_PS_RESOURCES, + SET_PS_SAMPLERS, + SET_PS, + + SET_CS_CBUFFERS, + SET_CS_RESOURCES, + SET_CS_UAVS, + SET_CS_SAMPLERS, + SET_CS, + + SET_VIEWPORTS, + SET_SCISSORS, + SET_RASTER, + + SET_RTARGET, + SET_RTARGET_AND_UAVS, + SET_BLEND, + SET_DEPTHSTENCIL, + + DRAW_INDEXED_INST, + DRAW_INST, + DRAW_INDEXED, + DRAW, + DRAW_AUTO, + DRAW_INDEXED_INST_INDIRECT, + DRAW_INST_INDIRECT, + + MAP, + UNMAP, + + COPY_SUBRESOURCE_REGION, + COPY_RESOURCE, + UPDATE_SUBRESOURCE, + COPY_STRUCTURE_COUNT, + RESOLVE_SUBRESOURCE, + GENERATE_MIPS, + + CLEAR_DSV, + CLEAR_RTV, + CLEAR_UAV_INT, + CLEAR_UAV_FLOAT, + CLEAR_STATE, + + EXECUTE_CMD_LIST, + DISPATCH, + DISPATCH_INDIRECT, + FINISH_CMD_LIST, + FLUSH, + + SET_PREDICATION, + SET_RESOURCE_MINLOD, + + BEGIN, + END, + + CREATE_RASTER_STATE1, + CREATE_BLEND_STATE1, + + COPY_SUBRESOURCE_REGION1, + UPDATE_SUBRESOURCE1, + CLEAR_VIEW, + + SET_VS_CBUFFERS1, + SET_HS_CBUFFERS1, + SET_DS_CBUFFERS1, + SET_GS_CBUFFERS1, + SET_PS_CBUFFERS1, + SET_CS_CBUFFERS1, + + BEGIN_EVENT, + SET_MARKER, + END_EVENT, + + DEBUG_MESSAGES, + + CONTEXT_CAPTURE_HEADER, // chunk at beginning of context's chunk stream + CONTEXT_CAPTURE_FOOTER, // chunk at end of context's chunk stream + + NUM_D3D11_CHUNKS, +}; + +#pragma endregion Chunks diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp new file mode 100644 index 0000000000..3fba835909 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -0,0 +1,1193 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/d3d11/d3d11_device.h" +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_renderstate.h" +#include "driver/d3d11/d3d11_manager.h" +#include "driver/d3d11/d3d11_resources.h" + +#include "common/string_utils.h" + +#include "replay/type_helpers.h" + +WRAPPED_POOL_INST(WrappedID3D11DeviceContext); +WRAPPED_POOL_INST(WrappedID3D11CommandList); + + +INT STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::BeginEvent(LPCWSTR Name) +{ + if(m_Context) + return m_Context->BeginEvent(0, Name); + + return -1; +} + +INT STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::EndEvent() +{ + if(m_Context) + return m_Context->EndEvent(); + + return -1; +} + +void STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::SetMarker(LPCWSTR Name) +{ + if(m_Context) + return m_Context->SetMarker(0, Name); +} + +HRESULT STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::QueryInterface(REFIID riid, void **ppvObject) +{ + //DEFINE_GUID(IID_ID3DUserDefinedAnnotation,0xb2daad8b,0x03d4,0x4dbf,0x95,0xeb,0x32,0xab,0x4b,0x63,0xd0,0xab); + static const GUID ID3D11UserDefinedAnnotation_uuid = { 0xb2daad8b, 0x03d4, 0x4dbf, { 0x95, 0xeb, 0x32, 0xab, 0x4b, 0x63, 0xd0, 0xab } }; + + if(riid == ID3D11UserDefinedAnnotation_uuid) + { + *ppvObject = (void *)this; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +extern uint32_t NullCBOffsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; +extern uint32_t NullCBCounts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + +WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device* realDevice, ID3D11DeviceContext* context, + Serialiser *ser, Serialiser *debugser) + : RefCounter(context), m_pDevice(realDevice), m_pRealContext(context) +{ + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D11DeviceContext)); + + for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + { + NullCBOffsets[i] = 0; + NullCBCounts[i] = 4096; + } + + D3D11_FEATURE_DATA_D3D11_OPTIONS features; + RDCEraseEl(features); + HRESULT hr = m_pDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)); + + m_SetCBuffer1 = false; + if(SUCCEEDED(hr)) + m_SetCBuffer1 = features.ConstantBufferOffsetting == TRUE; + + m_pRealContext1 = NULL; + m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&m_pRealContext1); + +#if defined(RELEASE) + const bool debugSerialiser = false; +#else + const bool debugSerialiser = true; +#endif + + if(RenderDoc::Inst().IsReplayApp()) + { + m_State = READING; + m_pSerialiser = ser; + } + else + { + m_pSerialiser = new Serialiser(NULL, Serialiser::WRITING, debugSerialiser); + m_pDebugSerialiser = debugser; + m_State = WRITING_IDLE; + } + + // create a temporary and grab its resource ID + m_ResourceID = TrackedResource().GetResourceID(); + + m_ContextRecord = NULL; + + if(!RenderDoc::Inst().IsReplayApp()) + { + m_ContextRecord = m_pDevice->GetResourceManager()->AddResourceRecord(m_ResourceID); + m_ContextRecord->DataInSerialiser = false; + m_ContextRecord->SpecialResource = true; + m_ContextRecord->Length = 0; + m_ContextRecord->NumSubResources = 0; + m_ContextRecord->SubResources = NULL; + m_ContextRecord->ignoreSerialise = true; + } + + m_SuccessfulCapture = true; + m_FailureReason = CaptureSucceeded; + m_EmptyCommandList = true; + + m_DrawcallStack.push_back(&m_ParentDrawcall); + + m_CurEventID = 1; + m_CurDrawcallID = 1; + + m_MarkerIndentLevel = 0; + m_UserAnnotation.SetContext(this); + + m_CurrentPipelineState = new D3D11RenderState((Serialiser *)NULL); + m_DoStateVerify = m_State >= WRITING; + + if(context->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) + { + m_CurrentPipelineState->SetImmediatePipeline(m_pDevice); + } + else + { + m_pDevice->SoftRef(); + + if(m_State >= WRITING && RenderDoc::Inst().GetCaptureOptions().CaptureAllCmdLists) + m_State = WRITING_CAPFRAME; + } + + ReplayFakeContext(ResourceId()); +} + +WrappedID3D11DeviceContext::~WrappedID3D11DeviceContext() +{ + if(m_ContextRecord) + m_ContextRecord->Delete(m_pDevice->GetResourceManager()); + + if(m_pRealContext->GetType() != D3D11_DEVICE_CONTEXT_IMMEDIATE) + m_pDevice->RemoveDeferredContext(this); + + if(m_State >= WRITING) + { + SAFE_DELETE(m_pSerialiser); + } + + SAFE_RELEASE(m_pRealContext1); + + SAFE_DELETE(m_CurrentPipelineState); + SAFE_RELEASE(m_pRealContext); + + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); +} + +const char *WrappedID3D11DeviceContext::GetChunkName(D3D11ChunkType idx) +{ + return m_pDevice->GetChunkName(idx); +} + +bool WrappedID3D11DeviceContext::Serialise_BeginCaptureFrame(bool applyInitialState) +{ + D3D11RenderState state(m_pSerialiser); + + if(m_State >= WRITING) + { + state = *m_CurrentPipelineState; + + state.SetSerialiser(m_pSerialiser); + + state.MarkReferenced(this, true); + } + + state.Serialise(m_State, m_pDevice); + + if(m_State <= EXECUTING && applyInitialState) + { + m_DoStateVerify = false; + { + *m_CurrentPipelineState = state; + state.ApplyState(this); + } + m_DoStateVerify = true; + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::MarkResourceReferenced(ResourceId id, FrameRefType refType) +{ + if(m_pRealContext->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) + { + m_pDevice->GetResourceManager()->MarkResourceFrameReferenced(id, refType); + } + else + { + m_ContextRecord->MarkResourceFrameReferenced(id, refType); + } +} + +void WrappedID3D11DeviceContext::VerifyState() +{ +#if 0 + if(m_DoStateVerify) + { + D3D11RenderState state(this); + } +#endif +} + +void WrappedID3D11DeviceContext::BeginCaptureFrame() +{ + SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_HEADER); + m_pSerialiser->Serialise("context", m_ResourceID); + + Serialise_BeginCaptureFrame(false); + + { + SCOPED_LOCK(m_AnnotLock); + + m_AnnotationQueue.clear(); + } + + m_ContextRecord->AddChunk(scope.Get(), 1); +} + +void WrappedID3D11DeviceContext::AttemptCapture() +{ + m_State = WRITING_CAPFRAME; + + m_FailureReason = CaptureSucceeded; + + // deferred contexts are initially NOT successful unless empty. That's because we don't have the serialised + // contents of whatever is in them up until now (could be anything). + // Only after they have been through a Finish() and then in CAPFRAME mode are they considered + // successful. + if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + RDCDEBUG("Deferred Context %llu Attempting capture - initially %hs, %hs", GetResourceID(), m_SuccessfulCapture ? "successful" : "unsuccessful", m_EmptyCommandList ? "empty" : "non-empty"); + + m_SuccessfulCapture |= m_EmptyCommandList; + + if(m_SuccessfulCapture) + m_FailureReason = CaptureSucceeded; + else + m_FailureReason = CaptureFailed_UncappedCmdlist; + + RDCDEBUG("Deferred Context %llu Attempting capture - now %hs", GetResourceID(), m_SuccessfulCapture ? "successful" : "unsuccessful"); + } + else + { + RDCDEBUG("Immediate Context %llu Attempting capture", GetResourceID()); + + m_SuccessfulCapture = true; + m_FailureReason = CaptureSucceeded; + + for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it) + (*it)->Delete(m_pDevice->GetResourceManager()); + m_DeferredRecords.clear(); + + m_ContextRecord->LockChunks(); + while(m_ContextRecord->HasChunks()) + { + Chunk *chunk = m_ContextRecord->GetLastChunk(); + + SAFE_DELETE(chunk); + m_ContextRecord->PopChunk(); + } + m_ContextRecord->UnlockChunks(); + + m_ContextRecord->FreeParents(m_pDevice->GetResourceManager()); + } +} + +void WrappedID3D11DeviceContext::FinishCapture() +{ + if(GetType() != D3D11_DEVICE_CONTEXT_DEFERRED || !RenderDoc::Inst().GetCaptureOptions().CaptureAllCmdLists) + { + m_State = WRITING_IDLE; + + m_SuccessfulCapture = false; + m_FailureReason = CaptureSucceeded; + } + + for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it) + { + m_ContextRecord->AddParent(*it); + (*it)->Delete(m_pDevice->GetResourceManager()); + } + m_DeferredRecords.clear(); +} + +void WrappedID3D11DeviceContext::EndCaptureFrame() +{ + SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER); + m_pSerialiser->Serialise("context", m_ResourceID); + + bool HasCallstack = RenderDoc::Inst().GetCaptureOptions().CaptureCallstacks != 0; + m_pSerialiser->Serialise("HasCallstack", HasCallstack); + + if(HasCallstack) + { + Callstack::Stackwalk *call = Callstack::Collect(); + + RDCASSERT(call->NumLevels() < 0xff); + + size_t numLevels = call->NumLevels(); + uint64_t *stack = call->GetAddrs(); + + m_pSerialiser->Serialise("callstack", stack, numLevels); + + delete call; + } + + m_ContextRecord->AddChunk(scope.Get()); +} + +void WrappedID3D11DeviceContext::FreeCaptureData() +{ + for(auto it = WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it) + { + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(it->first); + + if(record == NULL) continue; + + bool inuse = false; + for(auto mapit=m_OpenMaps.begin(); mapit != m_OpenMaps.end(); ++mapit) + { + if(mapit->first.resource == it->first) + { + inuse = true; + break; + } + } + + if(inuse) continue; + + record->FreeShadowStorage(); + } +} + +void WrappedID3D11DeviceContext::CleanupCapture() +{ + if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + m_SuccessfulCapture |= m_EmptyCommandList; + + if(m_SuccessfulCapture) + m_FailureReason = CaptureSucceeded; + else + m_FailureReason = CaptureFailed_UncappedCmdlist; + + for(auto it=m_MapResourceRecordAllocs.begin(); it != m_MapResourceRecordAllocs.end(); ++it) + { + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(it->first); + if(record) record->FreeContextID(it->second); + } + + if(RenderDoc::Inst().GetCaptureOptions().CaptureAllCmdLists) + return; + } + else + { + m_SuccessfulCapture = true; + m_FailureReason = CaptureSucceeded; + } + + for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it) + (*it)->Delete(m_pDevice->GetResourceManager()); + m_DeferredRecords.clear(); + + m_ContextRecord->LockChunks(); + while(m_ContextRecord->HasChunks()) + { + Chunk *chunk = m_ContextRecord->GetLastChunk(); + + SAFE_DELETE(chunk); + m_ContextRecord->PopChunk(); + } + m_ContextRecord->UnlockChunks(); + + m_ContextRecord->FreeParents(m_pDevice->GetResourceManager()); + + for(auto it=m_MissingTracks.begin(); it != m_MissingTracks.end(); ++it) + { + if(m_pDevice->GetResourceManager()->HasResourceRecord(*it)) + m_pDevice->GetResourceManager()->MarkDirtyResource(*it); + } + + m_MissingTracks.clear(); +} + +void WrappedID3D11DeviceContext::BeginFrame() +{ + { + SCOPED_LOCK(m_AnnotLock); + m_AnnotationQueue.clear(); + } +} + +void WrappedID3D11DeviceContext::EndFrame() +{ + m_pDevice->GetResourceManager()->FlushPendingDirty(); +} + +void WrappedID3D11DeviceContext::ProcessChunk(uint64_t offset, D3D11ChunkType chunk, bool forceExecute) +{ + if(chunk < FIRST_CONTEXT_CHUNK && !forceExecute) + { + if(m_State == READING) + { + m_pDevice->GetResourceManager()->MarkInFrame(false); + + m_pDevice->ProcessChunk(offset, chunk); + m_pSerialiser->PopContext(NULL, chunk); + + m_pDevice->GetResourceManager()->MarkInFrame(true); + } + else if(m_State == EXECUTING) + { + m_pSerialiser->SkipCurrentChunk(); + m_pSerialiser->PopContext(NULL, chunk); + } + return; + } + + m_CurChunkOffset = offset; + + RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE); + + uint64_t cOffs = m_pSerialiser->GetOffset(); + + ResourceId ctxId; + m_pSerialiser->Serialise("context", ctxId); + + WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(ctxId); + + if(m_FakeContext != ResourceId()) + { + if(m_FakeContext == ctxId) + context = this; + else + { + m_pSerialiser->SetOffset(cOffs); + m_pSerialiser->SkipCurrentChunk(); + m_pSerialiser->PopContext(NULL, chunk); + return; + } + } + + RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context)); + + LogState state = context->m_State; + + if(forceExecute) + context->m_State = EXECUTING; + else + context->m_State = m_State; + + m_AddedDrawcall = false; + + switch(chunk) + { + case SET_INPUT_LAYOUT: + context->Serialise_IASetInputLayout(0x0); + break; + case SET_VBUFFER: + context->Serialise_IASetVertexBuffers(0, 0, 0x0, 0x0, 0x0); + break; + case SET_IBUFFER: + context->Serialise_IASetIndexBuffer(0, DXGI_FORMAT_UNKNOWN, 0); + break; + case SET_TOPOLOGY: + context->Serialise_IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED); + break; + + case SET_VS_CBUFFERS: + context->Serialise_VSSetConstantBuffers(0, 0, 0x0); + break; + case SET_VS_RESOURCES: + context->Serialise_VSSetShaderResources(0, 0, 0x0); + break; + case SET_VS_SAMPLERS: + context->Serialise_VSSetSamplers(0, 0, 0x0); + break; + case SET_VS: + context->Serialise_VSSetShader(0x0, 0x0, 0); + break; + + case SET_HS_CBUFFERS: + context->Serialise_HSSetConstantBuffers(0, 0, 0x0); + break; + case SET_HS_RESOURCES: + context->Serialise_HSSetShaderResources(0, 0, 0x0); + break; + case SET_HS_SAMPLERS: + context->Serialise_HSSetSamplers(0, 0, 0x0); + break; + case SET_HS: + context->Serialise_HSSetShader(0x0, 0x0, 0); + break; + + case SET_DS_CBUFFERS: + context->Serialise_DSSetConstantBuffers(0, 0, 0x0); + break; + case SET_DS_RESOURCES: + context->Serialise_DSSetShaderResources(0, 0, 0x0); + break; + case SET_DS_SAMPLERS: + context->Serialise_DSSetSamplers(0, 0, 0x0); + break; + case SET_DS: + context->Serialise_DSSetShader(0x0, 0x0, 0); + break; + + case SET_GS_CBUFFERS: + context->Serialise_GSSetConstantBuffers(0, 0, 0x0); + break; + case SET_GS_RESOURCES: + context->Serialise_GSSetShaderResources(0, 0, 0x0); + break; + case SET_GS_SAMPLERS: + context->Serialise_GSSetSamplers(0, 0, 0x0); + break; + case SET_GS: + context->Serialise_GSSetShader(0x0, 0x0, 0); + break; + + case SET_SO_TARGETS: + context->Serialise_SOSetTargets(0, 0x0, 0x0); + break; + + case SET_PS_CBUFFERS: + context->Serialise_PSSetConstantBuffers(0, 0, 0x0); + break; + case SET_PS_RESOURCES: + context->Serialise_PSSetShaderResources(0, 0, 0x0); + break; + case SET_PS_SAMPLERS: + context->Serialise_PSSetSamplers(0, 0, 0x0); + break; + case SET_PS: + context->Serialise_PSSetShader(0x0, 0x0, 0); + break; + + case SET_CS_CBUFFERS: + context->Serialise_CSSetConstantBuffers(0, 0, 0x0); + break; + case SET_CS_RESOURCES: + context->Serialise_CSSetShaderResources(0, 0, 0x0); + break; + case SET_CS_UAVS: + context->Serialise_CSSetUnorderedAccessViews(0, 0, 0x0, 0x0); + break; + case SET_CS_SAMPLERS: + context->Serialise_CSSetSamplers(0, 0, 0x0); + break; + case SET_CS: + context->Serialise_CSSetShader(0x0, 0x0, 0); + break; + + case SET_VIEWPORTS: + context->Serialise_RSSetViewports(0, 0x0); + break; + case SET_SCISSORS: + context->Serialise_RSSetScissorRects(0, 0x0); + break; + case SET_RASTER: + context->Serialise_RSSetState(0x0); + break; + + case SET_RTARGET: + context->Serialise_OMSetRenderTargets(0, 0x0, 0x0); + break; + case SET_RTARGET_AND_UAVS: + context->Serialise_OMSetRenderTargetsAndUnorderedAccessViews(0, 0x0, 0x0, 0, 0, 0x0, 0x0); + break; + case SET_BLEND: + context->Serialise_OMSetBlendState(0x0, (FLOAT*)0x0, 0); + break; + case SET_DEPTHSTENCIL: + context->Serialise_OMSetDepthStencilState(0x0, 0); + break; + + case DRAW_INDEXED_INST: + context->Serialise_DrawIndexedInstanced(0, 0, 0, 0, 0); + break; + case DRAW_INST: + context->Serialise_DrawInstanced(0, 0, 0, 0); + break; + case DRAW_INDEXED: + context->Serialise_DrawIndexed(0, 0, 0); + break; + case DRAW: + context->Serialise_Draw(0, 0); + break; + case DRAW_AUTO: + context->Serialise_DrawAuto(); + break; + case DRAW_INDEXED_INST_INDIRECT: + context->Serialise_DrawIndexedInstancedIndirect(0x0, 0); + break; + case DRAW_INST_INDIRECT: + context->Serialise_DrawInstancedIndirect(0x0, 0); + break; + + case MAP: + context->Serialise_Map(0, 0, (D3D11_MAP)0, 0, 0); + break; + case UNMAP: + context->Serialise_Unmap(0, 0); + break; + + case COPY_SUBRESOURCE_REGION: + context->Serialise_CopySubresourceRegion(0x0, 0, 0, 0, 0, 0x0, 0, 0x0); + break; + case COPY_RESOURCE: + context->Serialise_CopyResource(0x0, 0x0); + break; + case UPDATE_SUBRESOURCE: + context->Serialise_UpdateSubresource(0x0, 0, 0x0, 0x0, 0, 0); + break; + case COPY_STRUCTURE_COUNT: + context->Serialise_CopyStructureCount(0x0, 0, 0x0); + break; + case RESOLVE_SUBRESOURCE: + context->Serialise_ResolveSubresource(0x0, 0, 0x0, 0, DXGI_FORMAT_UNKNOWN); + break; + case GENERATE_MIPS: + context->Serialise_GenerateMips(0x0); + break; + + case CLEAR_DSV: + context->Serialise_ClearDepthStencilView(0x0, 0, 0.0f, 0); + break; + case CLEAR_RTV: + context->Serialise_ClearRenderTargetView(0x0, (FLOAT*)0x0); + break; + case CLEAR_UAV_INT: + context->Serialise_ClearUnorderedAccessViewUint(0x0, (UINT*)0x0); + break; + case CLEAR_UAV_FLOAT: + context->Serialise_ClearUnorderedAccessViewFloat(0x0, (FLOAT*)0x0); + break; + case CLEAR_STATE: + context->Serialise_ClearState(); + break; + + case EXECUTE_CMD_LIST: + context->Serialise_ExecuteCommandList(0x0, 0); + break; + case DISPATCH: + context->Serialise_Dispatch(0, 0, 0); + break; + case DISPATCH_INDIRECT: + context->Serialise_DispatchIndirect(0x0, 0); + break; + case FINISH_CMD_LIST: + context->Serialise_FinishCommandList(0, 0x0); + break; + case FLUSH: + context->Serialise_Flush(); + break; + + case SET_PREDICATION: + context->Serialise_SetPredication(0x0, 0x0); + break; + case SET_RESOURCE_MINLOD: + context->Serialise_SetResourceMinLOD(0x0, 0); + break; + + case BEGIN: + context->Serialise_Begin(0x0); + break; + case END: + context->Serialise_End(0x0); + break; + + case COPY_SUBRESOURCE_REGION1: + context->Serialise_CopySubresourceRegion1(0x0, 0, 0, 0, 0, 0x0, 0, 0x0, 0); + break; + case UPDATE_SUBRESOURCE1: + context->Serialise_UpdateSubresource1(0x0, 0, 0x0, 0x0, 0, 0, 0); + break; + case CLEAR_VIEW: + context->Serialise_ClearView(0x0, 0x0, 0x0, 0); + break; + + case SET_VS_CBUFFERS1: + context->Serialise_VSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0); + break; + case SET_HS_CBUFFERS1: + context->Serialise_HSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0); + break; + case SET_DS_CBUFFERS1: + context->Serialise_DSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0); + break; + case SET_GS_CBUFFERS1: + context->Serialise_GSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0); + break; + case SET_PS_CBUFFERS1: + context->Serialise_PSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0); + break; + case SET_CS_CBUFFERS1: + context->Serialise_CSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0); + break; + + case BEGIN_EVENT: + context->Serialise_BeginEvent(0, L""); + break; + case SET_MARKER: + context->Serialise_SetMarker(0, L""); + break; + case END_EVENT: + context->Serialise_EndEvent(); + break; + + case CONTEXT_CAPTURE_FOOTER: + { + bool HasCallstack = false; + m_pSerialiser->Serialise("HasCallstack", HasCallstack); + + if(HasCallstack) + { + size_t numLevels = 0; + uint64_t *stack = NULL; + + m_pSerialiser->Serialise("callstack", stack, numLevels); + + m_pSerialiser->SetCallstack(stack, numLevels); + + SAFE_DELETE_ARRAY(stack); + } + + if(m_State == READING) + { + AddEvent(CONTEXT_CAPTURE_FOOTER, "IDXGISwapChain::Present()"); + + FetchDrawcall draw; + draw.name = L"Present()"; + draw.flags |= eDraw_Present; + + AddDrawcall(draw, true); + } + } + break; + default: + RDCERR("Unrecognised Chunk type %d", chunk); + break; + } + + m_pSerialiser->PopContext(NULL, chunk); + + if(context->m_State == READING && chunk == SET_MARKER) + { + // no push/pop necessary + } + else if(context->m_State == READING && chunk == BEGIN_EVENT) + { + // push down the drawcallstack to the latest drawcall + context->m_DrawcallStack.push_back(&context->m_DrawcallStack.back()->children.back()); + } + else if(context->m_State == READING && chunk == END_EVENT) + { + // refuse to pop off further than the root drawcall (mismatched begin/end events e.g.) + RDCASSERT(context->m_DrawcallStack.size() > 1); + if(context->m_DrawcallStack.size() > 1) + context->m_DrawcallStack.pop_back(); + } + else if(context->m_State == READING) + { + if(!m_AddedDrawcall) + context->AddEvent(chunk, m_pSerialiser->GetDebugStr()); + } + + m_AddedDrawcall = false; + + if(forceExecute) + context->m_State = state; +} + +void WrappedID3D11DeviceContext::AddUsage(FetchDrawcall d) +{ + const D3D11RenderState *pipe = m_CurrentPipelineState; + uint32_t e = d.eventID; + + if((d.flags & (eDraw_Drawcall|eDraw_Dispatch|eDraw_CmdList)) == 0) + return; + + ////////////////////////////// + // IA + + if(d.flags & eDraw_UseIBuffer && pipe->IA.IndexBuffer != NULL) + m_ResourceUses[GetIDForResource(pipe->IA.IndexBuffer)].push_back(EventUsage(e, eUsage_IA_IB)); + + for(int i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + if(pipe->IA.Used_VB(m_pDevice, i)) + m_ResourceUses[GetIDForResource(pipe->IA.VBs[i])].push_back(EventUsage(e, eUsage_IA_VB)); + + ////////////////////////////// + // Shaders + + const D3D11RenderState::shader *shArr = &pipe->VS; + for(int s=0; s < 6; s++) + { + const D3D11RenderState::shader &sh = shArr[s]; + + for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + if(sh.Used_CB(i)) + m_ResourceUses[GetIDForResource(sh.ConstantBuffers[i])].push_back(EventUsage(e, (ResourceUsage)(eUsage_VS_CB+s))); + + for(int i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + if(sh.Used_SRV(i)) + m_ResourceUses[((WrappedID3D11ShaderResourceView *)sh.SRVs[i])->GetResourceResID()].push_back(EventUsage(e, (ResourceUsage)(eUsage_VS_SRV+s))); + + if(s == 5) + { + for(int i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + if(pipe->CS.Used_UAV(i) && pipe->CS.UAVs[i]) + m_ResourceUses[((WrappedID3D11UnorderedAccessView *)pipe->CS.UAVs[i])->GetResourceResID()].push_back(EventUsage(e, eUsage_CS_UAV)); + } + } + + ////////////////////////////// + // SO + + for(int i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + if(pipe->SO.Buffers[i]) // assuming for now that any SO target bound is used. + m_ResourceUses[GetIDForResource(pipe->SO.Buffers[i])].push_back(EventUsage(e, eUsage_SO)); + + ////////////////////////////// + // OM + + for(int i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + if(pipe->PS.Used_UAV(i) && pipe->OM.UAVs[i]) + m_ResourceUses[((WrappedID3D11UnorderedAccessView *)pipe->OM.UAVs[i])->GetResourceResID()].push_back(EventUsage(e, eUsage_PS_UAV)); + + if(pipe->OM.DepthView) // assuming for now that any DSV bound is used. + m_ResourceUses[((WrappedID3D11DepthStencilView *)pipe->OM.DepthView)->GetResourceResID()].push_back(EventUsage(e, eUsage_OM_DSV)); + + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + if(pipe->OM.RenderTargets[i]) // assuming for now that any RTV bound is used. + m_ResourceUses[((WrappedID3D11RenderTargetView *)pipe->OM.RenderTargets[i])->GetResourceResID()].push_back(EventUsage(e, eUsage_OM_RTV)); +} + +void WrappedID3D11DeviceContext::AddDrawcall(FetchDrawcall d, bool hasEvents) +{ + if(d.context == ResourceId()) d.context = m_pDevice->GetResourceManager()->GetOriginalID(m_ResourceID); + + if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + m_pDevice->GetImmediateContext()->AddDrawcall(d, hasEvents); + return; + } + + m_AddedDrawcall = true; + + WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(d.context); + + RDCASSERT(context); + + FetchDrawcall draw = d; + draw.eventID = m_CurEventID; + draw.drawcallID = m_CurDrawcallID; + + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + draw.outputs[i] = ResourceId(); + if(m_CurrentPipelineState->OM.RenderTargets[i]) + draw.outputs[i] = ((WrappedID3D11RenderTargetView *)m_CurrentPipelineState->OM.RenderTargets[i])->GetResourceResID(); + } + + { + draw.depthOut = ResourceId(); + if(m_CurrentPipelineState->OM.DepthView) + draw.depthOut = ((WrappedID3D11DepthStencilView *)m_CurrentPipelineState->OM.DepthView)->GetResourceResID(); + } + + m_CurDrawcallID++; + if(hasEvents) + { + vector evs; + evs.reserve(m_CurEvents.size()); + for(size_t i=0; i < m_CurEvents.size(); ) + { + if(m_CurEvents[i].context == draw.context) + { + evs.push_back(m_CurEvents[i]); + m_CurEvents.erase(m_CurEvents.begin()+i); + } + else + { + i++; + } + } + + draw.events = evs; + } + + AddUsage(draw); + + // should have at least the root drawcall here, push this drawcall + // onto the back's children list. + if(!context->m_DrawcallStack.empty()) + { + DrawcallTreeNode node(draw); + node.children.insert(node.children.begin(), draw.children.elems, draw.children.elems+draw.children.count); + context->m_DrawcallStack.back()->children.push_back(node); + } + else + RDCERR("Somehow lost drawcall stack!"); +} + +void WrappedID3D11DeviceContext::AddEvent(D3D11ChunkType type, string description, ResourceId ctx) +{ + if(ctx == ResourceId()) ctx = m_pDevice->GetResourceManager()->GetOriginalID(m_ResourceID); + + if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + m_pDevice->GetImmediateContext()->AddEvent(type, description, ctx); + return; + } + + FetchAPIEvent apievent; + + apievent.context = ctx; + apievent.fileOffset = m_CurChunkOffset; + apievent.eventID = m_CurEventID; + + apievent.eventDesc = widen(description); + + Callstack::Stackwalk *stack = m_pSerialiser->GetLastCallstack(); + if(stack) + { + create_array(apievent.callstack, stack->NumLevels()); + memcpy(apievent.callstack.elems, stack->GetAddrs(), sizeof(uint64_t)*stack->NumLevels()); + } + + m_CurEvents.push_back(apievent); + + if(m_State == READING) + m_Events.push_back(apievent); +} + +FetchAPIEvent WrappedID3D11DeviceContext::GetEvent(uint32_t eventID) +{ + for(size_t i=m_Events.size()-1; i > 0; i--) + { + if(m_Events[i].eventID <= eventID) + return m_Events[i]; + } + + return m_Events[0]; +} + +void WrappedID3D11DeviceContext::ReplayFakeContext(ResourceId id) +{ + m_FakeContext = id; +} + +void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial) +{ + m_State = readType; + + m_DoStateVerify = true; + + D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); + RDCASSERT(header == CONTEXT_CAPTURE_HEADER); + + ResourceId id; + m_pSerialiser->Serialise("context", id); + + WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(id); + + RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context) && context == this); + + Serialise_BeginCaptureFrame(!partial); + + m_pSerialiser->PopContext(NULL, header); + + m_CurEvents.clear(); + + if(m_State == EXECUTING) + { + FetchAPIEvent ev = GetEvent(startEventID); + m_CurEventID = ev.eventID; + m_pSerialiser->SetOffset(ev.fileOffset); + } + else if(m_State == READING) + { + m_CurEventID = 1; + } + + if(m_State == EXECUTING) + { + ClearMaps(); + for(size_t i=0; i < m_pDevice->GetNumDeferredContexts(); i++) + { + WrappedID3D11DeviceContext *context = m_pDevice->GetDeferredContext(i); + context->ClearMaps(); + } + } + + m_pDevice->GetResourceManager()->MarkInFrame(true); + + while(1) + { + if(m_State == EXECUTING && m_CurEventID > endEventID) + { + // we can just break out if we've done all the events desired. + break; + } + + uint64_t offset = m_pSerialiser->GetOffset(); + + D3D11ChunkType context = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); + + ProcessChunk(offset, context, false); + + RenderDoc::Inst().SetProgress(FileInitialRead, float(offset)/float(m_pSerialiser->GetSize())); + + // for now just abort after capture scope. Really we'd need to support multiple frames + // but for now this will do. + if(context == CONTEXT_CAPTURE_FOOTER) + break; + + m_CurEventID++; + } + + if(m_State == READING) + { + m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake(); + + m_ParentDrawcall.children.clear(); + + int initialSkips = 0; + + for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it) + m_ResourceUses[it->first]; + + for(auto it=WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it) + m_ResourceUses[it->first]; + for(auto it=WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it) + m_ResourceUses[it->first]; + for(auto it=WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it) + m_ResourceUses[it->first]; + + for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it) + { + ResourceId id = m_pDevice->GetResourceManager()->GetOriginalID(it->first); + + if(m_pDevice->GetResourceManager()->GetInitialContents(id) == NULL) + continue; + + RDCDEBUG("Resource %llu", id); + if(it->second.empty()) + { + RDCDEBUG("Never used!"); + initialSkips++; + } + else + { + bool written = false; + + for(auto usit = it->second.begin(); usit != it->second.end(); ++usit) + { + ResourceUsage u = usit->usage; + + if(u == eUsage_SO || + u == eUsage_CS_UAV || u == eUsage_PS_UAV || + u == eUsage_OM_DSV || u == eUsage_OM_RTV) + { + written = true; + break; + } + } + + if(written) + { + RDCDEBUG("Written in frame - needs initial state"); + } + else + { + RDCDEBUG("Never written to in the frame"); + initialSkips++; + } + } + } + + RDCDEBUG("Can skip %d initial states.", initialSkips); + } + + m_pDevice->GetResourceManager()->MarkInFrame(false); + + m_State = READING; + + m_DoStateVerify = false; +} + +void WrappedID3D11DeviceContext::ClearMaps() +{ + auto it = m_OpenMaps.begin(); + + for(; it != m_OpenMaps.end(); ++it) + { + RDCASSERT(m_pDevice->GetResourceManager()->HasLiveResource(it->first.resource)); + + ID3D11Resource *res = (ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(it->first.resource); + + m_pRealContext->Unmap(m_pDevice->GetResourceManager()->UnwrapResource(res), it->first.subresource); + } + + m_OpenMaps.clear(); +} + +HRESULT STDMETHODCALLTYPE WrappedID3D11DeviceContext::QueryInterface( REFIID riid, void **ppvObject ) +{ + //DEFINE_GUID(IID_ID3D11DeviceContext2,0x420d5b32,0xb90c,0x4da4,0xbe,0xf0,0x35,0x9f,0x6a,0x24,0xa8,0x3a); + static const GUID ID3D11DeviceContext2_uuid = { 0x420d5b32, 0xb90c, 0x4da4, { 0xbe, 0xf0, 0x35, 0x9f, 0x6a, 0x24, 0xa8, 0x3a } }; + + if(riid == __uuidof(ID3D11DeviceContext)) + { + *ppvObject = (ID3D11DeviceContext *)this; + AddRef(); + return S_OK; + } + else if(riid == __uuidof(ID3D11DeviceChild)) + { + *ppvObject = (ID3D11DeviceChild *)this; + AddRef(); + return S_OK; + } + else if(riid == __uuidof(ID3D11DeviceContext1)) + { + *ppvObject = (ID3D11DeviceContext1 *)this; + AddRef(); + return S_OK; + } + else if(riid == ID3D11DeviceContext2_uuid) + { + RDCWARN("Trying to get ID3D11DeviceContext2. DX11.2 not supported at this time."); + *ppvObject = NULL; + return E_NOINTERFACE; + } + else if(riid == __uuidof(ID3DUserDefinedAnnotation)) + { + *ppvObject = (ID3DUserDefinedAnnotation *)&m_UserAnnotation; + m_UserAnnotation.AddRef(); + return S_OK; + } + else + { + string guid = ToStr::Get(riid); + RDCWARN("Querying ID3D11DeviceContext for interface: %hs", guid.c_str()); + } + + return RefCounter::QueryInterface(riid, ppvObject); +} diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h new file mode 100644 index 0000000000..9413bc4037 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -0,0 +1,1311 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "core/core.h" +#include "replay/renderdoc.h" + +#include + +#include "d3d11_manager.h" + +#include +#include +using std::map; +using std::list; + +struct MapIntercept +{ + MapIntercept() + { + RDCEraseEl(app); RDCEraseEl(d3d); + numRows = numSlices = 1; + } + + void SetAppMemory(void *appMemory); + void SetD3D(D3D11_MAPPED_SUBRESOURCE d3dMap); + void SetD3D(D3D11_SUBRESOURCE_DATA d3dMap); + + void InitWrappedResource(ID3D11Resource *res, UINT sub, void *appMemory); + + void Init(ID3D11Buffer *buf, void *appMemory); + void Init(ID3D11Texture1D *tex, UINT sub, void *appMemory); + void Init(ID3D11Texture2D *tex, UINT sub, void *appMemory); + void Init(ID3D11Texture3D *tex, UINT sub, void *appMemory); + + D3D11_MAPPED_SUBRESOURCE app, d3d; + int numRows, numSlices; + + D3D11_MAP MapType; + UINT MapFlags; + + void CopyFromD3D(); + void CopyToD3D(size_t RangeStart = 0, size_t RangeEnd = 0); +}; + +class WrappedID3D11DeviceContext; + +// ID3DUserDefinedAnnotation +class WrappedID3DUserDefinedAnnotation : public RefCounter, public ID3DUserDefinedAnnotation +{ + public: + WrappedID3DUserDefinedAnnotation() : RefCounter(NULL), m_Context(NULL) {} + + void SetContext(WrappedID3D11DeviceContext *ctx) + { m_Context = ctx; } + + // doesn't need to soft-ref the device, for once! + IMPLEMENT_IUNKNOWN_WITH_REFCOUNTER_CUSTOMQUERY; + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + virtual INT STDMETHODCALLTYPE BeginEvent(LPCWSTR Name); + virtual INT STDMETHODCALLTYPE EndEvent(); + virtual void STDMETHODCALLTYPE SetMarker(LPCWSTR Name); + virtual BOOL STDMETHODCALLTYPE GetStatus() { return TRUE; } + + private: + WrappedID3D11DeviceContext *m_Context; +}; + +enum CaptureFailReason +{ + CaptureSucceeded = 0, + CaptureFailed_UncappedUnmap, + CaptureFailed_UncappedCmdlist, +}; + +struct DrawcallTreeNode +{ + DrawcallTreeNode() {} + explicit DrawcallTreeNode(FetchDrawcall d) : draw(d) {} + FetchDrawcall draw; + vector children; + + rdctype::array Bake() + { + rdctype::array ret; + if(children.empty()) return ret; + + create_array_uninit(ret, children.size()); + for(size_t i=0; i < children.size(); i++) + { + ret.elems[i] = children[i].draw; + ret.elems[i].children = children[i].Bake(); + } + + return ret; + } +}; + +class WrappedID3D11DeviceContext : public RefCounter, public ID3D11DeviceContext1 +{ +private: + friend class WrappedID3D11DeviceContext; + friend class WrappedID3DUserDefinedAnnotation; + friend struct D3D11RenderState; + + struct MappedResource + { + MappedResource(ResourceId res = ResourceId(), UINT sub = 0) : resource(res), subresource(sub) {} + ResourceId resource; + UINT subresource; + + bool operator <(const MappedResource &o) const + { + if(resource != o.resource) + return resource < o.resource; + + return subresource < o.subresource; + } + }; + + set m_HighTrafficResources; + map m_OpenMaps; + + map > m_ResourceUses; + + WrappedID3D11Device* m_pDevice; + ID3D11DeviceContext* m_pRealContext; + ID3D11DeviceContext1* m_pRealContext1; + bool m_SetCBuffer1; + + set m_DeferredRecords; + map m_MapResourceRecordAllocs; + + set m_MissingTracks; + + ResourceId m_ResourceID; + D3D11ResourceRecord *m_ContextRecord; + + Serialiser *m_pSerialiser; + Serialiser *m_pDebugSerialiser; + LogState m_State; + CaptureFailReason m_FailureReason; + bool m_SuccessfulCapture; + bool m_EmptyCommandList; + + ResourceId m_FakeContext; + + bool m_DoStateVerify; + D3D11RenderState *m_CurrentPipelineState; + + vector m_CurEvents, m_Events; + bool m_AddedDrawcall; + + WrappedID3DUserDefinedAnnotation m_UserAnnotation; + int32_t m_MarkerIndentLevel; + + struct Annotation + { + enum { ANNOT_SETMARKER, ANNOT_BEGINEVENT, ANNOT_ENDEVENT } m_Type; + uint32_t m_Col; + wstring m_Name; + }; + vector m_AnnotationQueue; + Threading::CriticalSection m_AnnotLock; + + uint64_t m_CurChunkOffset; + uint32_t m_CurEventID, m_CurDrawcallID; + + DrawcallTreeNode m_ParentDrawcall; + map m_CmdLists; + + list m_DrawcallStack; + + const char *GetChunkName(D3D11ChunkType idx); + + vector Serialise_DebugMessages(); + + void DrainAnnotationQueue(); + + void AddUsage(FetchDrawcall draw); + + void AddEvent(D3D11ChunkType type, string description, ResourceId ctx = ResourceId()); + void AddDrawcall(FetchDrawcall draw, bool hasEvents); + + //////////////////////////////////////////////////////////////// + // implement InterceptorSystem privately, since it is not thread safe (like all other context functions) + IMPLEMENT_FUNCTION_SERIALISED(void, SetMarker(uint32_t col, const wchar_t *name)); + IMPLEMENT_FUNCTION_SERIALISED(int, BeginEvent(uint32_t col, const wchar_t *name)); + IMPLEMENT_FUNCTION_SERIALISED(int, EndEvent()); +public: + static const int AllocPoolCount = 2048; + static const int AllocPoolMaxByteSize = 3*1024*1024; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11DeviceContext, AllocPoolCount, AllocPoolMaxByteSize); + + WrappedID3D11DeviceContext(WrappedID3D11Device* realDevice, ID3D11DeviceContext* context, Serialiser *ser, Serialiser *debugser); + void SetSerialiser(Serialiser *ser) { m_pSerialiser = ser; } + virtual ~WrappedID3D11DeviceContext(); + + void VerifyState(); + + void BeginFrame(); + void EndFrame(); + + bool Serialise_BeginCaptureFrame(bool applyInitialState); + void BeginCaptureFrame(); + void EndCaptureFrame(); + + void CleanupCapture(); + void FreeCaptureData(); + + bool HasSuccessfulCapture(CaptureFailReason &reason) { reason = m_FailureReason; return m_SuccessfulCapture && m_ContextRecord->NumChunks() > 3; } + + void AttemptCapture(); + void FinishCapture(); + + D3D11RenderState *GetCurrentPipelineState() { return m_CurrentPipelineState; } + Serialiser *GetSerialiser() { return m_pSerialiser; } + ResourceId GetResourceID() { return m_ResourceID; } + ID3D11DeviceContext* GetReal() { return m_pRealContext; } + + void ProcessChunk(uint64_t offset, D3D11ChunkType chunk, bool forceExecute); + void ReplayFakeContext(ResourceId id); + void ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial); + + void MarkResourceReferenced(ResourceId id, FrameRefType refType); + + vector GetUsage(ResourceId id) { return m_ResourceUses[id]; } + + void ClearMaps(); + + uint32_t GetEventID() { return m_CurEventID; } + FetchAPIEvent GetEvent(uint32_t eventID); + + void ThreadSafe_SetMarker(uint32_t col, const wchar_t *name); + int ThreadSafe_BeginEvent(uint32_t col, const wchar_t *name); + int ThreadSafe_EndEvent(); + + ////////////////////////////// + // implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter::SoftRef(m_pDevice); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter::SoftRelease(m_pDevice); } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + ////////////////////////////// + // implement IDXGIDeviceChild + + virtual HRESULT STDMETHODCALLTYPE SetPrivateData( + /* [in] */ REFGUID Name, + /* [in] */ UINT DataSize, + /* [in] */ const void *pData) + { return m_pRealContext->SetPrivateData(Name, DataSize, pData); } + + virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + /* [in] */ REFGUID Name, + /* [in] */ const IUnknown *pUnknown) + { return m_pRealContext->SetPrivateDataInterface(Name, pUnknown); } + + virtual HRESULT STDMETHODCALLTYPE GetPrivateData( + /* [in] */ REFGUID Name, + /* [out][in] */ UINT *pDataSize, + /* [out] */ void *pData) + { return m_pRealContext->GetPrivateData(Name, pDataSize, pData); } + + virtual void STDMETHODCALLTYPE GetDevice( + /* [retval][out] */ ID3D11Device **ppDevice) + { *ppDevice = (ID3D11Device *)m_pDevice; (*ppDevice)->AddRef(); } + + ////////////////////////////// + // implement ID3D11DeviceContext + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSSetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSSetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSSetShader( + /* [annotation] */ + __in_opt ID3D11PixelShader *pPixelShader, + /* [annotation] */ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSSetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSSetShader( + /* [annotation] */ + __in_opt ID3D11VertexShader *pVertexShader, + /* [annotation] */ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DrawIndexed( + /* [annotation] */ + __in UINT IndexCount, + /* [annotation] */ + __in UINT StartIndexLocation, + /* [annotation] */ + __in INT BaseVertexLocation)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, Draw( + /* [annotation] */ + __in UINT VertexCount, + /* [annotation] */ + __in UINT StartVertexLocation)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, Map( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in UINT Subresource, + /* [annotation] */ + __in D3D11_MAP MapType, + /* [annotation] */ + __in UINT MapFlags, + /* [annotation] */ + __out D3D11_MAPPED_SUBRESOURCE *pMappedResource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, Unmap( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in UINT Subresource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSSetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IASetInputLayout( + /* [annotation] */ + __in_opt ID3D11InputLayout *pInputLayout)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IASetVertexBuffers( + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppVertexBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) const UINT *pStrides, + /* [annotation] */ + __in_ecount(NumBuffers) const UINT *pOffsets)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IASetIndexBuffer( + /* [annotation] */ + __in_opt ID3D11Buffer *pIndexBuffer, + /* [annotation] */ + __in DXGI_FORMAT Format, + /* [annotation] */ + __in UINT Offset)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DrawIndexedInstanced( + /* [annotation] */ + __in UINT IndexCountPerInstance, + /* [annotation] */ + __in UINT InstanceCount, + /* [annotation] */ + __in UINT StartIndexLocation, + /* [annotation] */ + __in INT BaseVertexLocation, + /* [annotation] */ + __in UINT StartInstanceLocation)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DrawInstanced( + /* [annotation] */ + __in UINT VertexCountPerInstance, + /* [annotation] */ + __in UINT InstanceCount, + /* [annotation] */ + __in UINT StartVertexLocation, + /* [annotation] */ + __in UINT StartInstanceLocation)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSSetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSSetShader( + /* [annotation] */ + __in_opt ID3D11GeometryShader *pShader, + /* [annotation] */ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IASetPrimitiveTopology( + /* [annotation] */ + __in D3D11_PRIMITIVE_TOPOLOGY Topology)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSSetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSSetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, Begin( + /* [annotation] */ + __in ID3D11Asynchronous *pAsync)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, End( + /* [annotation] */ + __in ID3D11Asynchronous *pAsync)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, GetData( + /* [annotation] */ + __in ID3D11Asynchronous *pAsync, + /* [annotation] */ + __out_bcount_opt( DataSize ) void *pData, + /* [annotation] */ + __in UINT DataSize, + /* [annotation] */ + __in UINT GetDataFlags)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SetPredication( + /* [annotation] */ + __in_opt ID3D11Predicate *pPredicate, + /* [annotation] */ + __in BOOL PredicateValue)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSSetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSSetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMSetRenderTargets( + /* [annotation] */ + __in_range( 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT ) UINT NumViews, + /* [annotation] */ + __in_ecount_opt(NumViews) ID3D11RenderTargetView *const *ppRenderTargetViews, + /* [annotation] */ + __in_opt ID3D11DepthStencilView *pDepthStencilView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMSetRenderTargetsAndUnorderedAccessViews( + /* [annotation] */ + __in UINT NumRTVs, + /* [annotation] */ + __in_ecount_opt(NumRTVs) ID3D11RenderTargetView *const *ppRenderTargetViews, + /* [annotation] */ + __in_opt ID3D11DepthStencilView *pDepthStencilView, + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1 ) UINT UAVStartSlot, + /* [annotation] */ + __in UINT NumUAVs, + /* [annotation] */ + __in_ecount_opt(NumUAVs) ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + /* [annotation] */ + __in_ecount_opt(NumUAVs) const UINT *pUAVInitialCounts)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMSetBlendState( + /* [annotation] */ + __in_opt ID3D11BlendState *pBlendState, + /* [annotation] */ + __in_opt const FLOAT BlendFactor[ 4 ], + /* [annotation] */ + __in UINT SampleMask)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMSetDepthStencilState( + /* [annotation] */ + __in_opt ID3D11DepthStencilState *pDepthStencilState, + /* [annotation] */ + __in UINT StencilRef)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SOSetTargets( + /* [annotation] */ + __in_range( 0, D3D11_SO_BUFFER_SLOT_COUNT) UINT NumBuffers, + /* [annotation] */ + __in_ecount_opt(NumBuffers) ID3D11Buffer *const *ppSOTargets, + /* [annotation] */ + __in_ecount_opt(NumBuffers) const UINT *pOffsets)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DrawAuto( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DrawIndexedInstancedIndirect( + /* [annotation] */ + __in ID3D11Buffer *pBufferForArgs, + /* [annotation] */ + __in UINT AlignedByteOffsetForArgs)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DrawInstancedIndirect( + /* [annotation] */ + __in ID3D11Buffer *pBufferForArgs, + /* [annotation] */ + __in UINT AlignedByteOffsetForArgs)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, Dispatch( + /* [annotation] */ + __in UINT ThreadGroupCountX, + /* [annotation] */ + __in UINT ThreadGroupCountY, + /* [annotation] */ + __in UINT ThreadGroupCountZ)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DispatchIndirect( + /* [annotation] */ + __in ID3D11Buffer *pBufferForArgs, + /* [annotation] */ + __in UINT AlignedByteOffsetForArgs)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, RSSetState( + /* [annotation] */ + __in_opt ID3D11RasterizerState *pRasterizerState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, RSSetViewports( + /* [annotation] */ + __in_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT NumViewports, + /* [annotation] */ + __in_ecount_opt(NumViewports) const D3D11_VIEWPORT *pViewports)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, RSSetScissorRects( + /* [annotation] */ + __in_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT NumRects, + /* [annotation] */ + __in_ecount_opt(NumRects) const D3D11_RECT *pRects)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CopySubresourceRegion( + /* [annotation] */ + __in ID3D11Resource *pDstResource, + /* [annotation] */ + __in UINT DstSubresource, + /* [annotation] */ + __in UINT DstX, + /* [annotation] */ + __in UINT DstY, + /* [annotation] */ + __in UINT DstZ, + /* [annotation] */ + __in ID3D11Resource *pSrcResource, + /* [annotation] */ + __in UINT SrcSubresource, + /* [annotation] */ + __in_opt const D3D11_BOX *pSrcBox)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CopyResource( + /* [annotation] */ + __in ID3D11Resource *pDstResource, + /* [annotation] */ + __in ID3D11Resource *pSrcResource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, UpdateSubresource( + /* [annotation] */ + __in ID3D11Resource *pDstResource, + /* [annotation] */ + __in UINT DstSubresource, + /* [annotation] */ + __in_opt const D3D11_BOX *pDstBox, + /* [annotation] */ + __in const void *pSrcData, + /* [annotation] */ + __in UINT SrcRowPitch, + /* [annotation] */ + __in UINT SrcDepthPitch)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CopyStructureCount( + /* [annotation] */ + __in ID3D11Buffer *pDstBuffer, + /* [annotation] */ + __in UINT DstAlignedByteOffset, + /* [annotation] */ + __in ID3D11UnorderedAccessView *pSrcView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ClearRenderTargetView( + /* [annotation] */ + __in ID3D11RenderTargetView *pRenderTargetView, + /* [annotation] */ + __in const FLOAT ColorRGBA[ 4 ])); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ClearUnorderedAccessViewUint( + /* [annotation] */ + __in ID3D11UnorderedAccessView *pUnorderedAccessView, + /* [annotation] */ + __in const UINT Values[ 4 ])); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ClearUnorderedAccessViewFloat( + /* [annotation] */ + __in ID3D11UnorderedAccessView *pUnorderedAccessView, + /* [annotation] */ + __in const FLOAT Values[ 4 ])); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ClearDepthStencilView( + /* [annotation] */ + __in ID3D11DepthStencilView *pDepthStencilView, + /* [annotation] */ + __in UINT ClearFlags, + /* [annotation] */ + __in FLOAT Depth, + /* [annotation] */ + __in UINT8 Stencil)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GenerateMips( + /* [annotation] */ + __in ID3D11ShaderResourceView *pShaderResourceView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SetResourceMinLOD( + /* [annotation] */ + __in ID3D11Resource *pResource, + FLOAT MinLOD)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual FLOAT STDMETHODCALLTYPE, GetResourceMinLOD( + /* [annotation] */ + __in ID3D11Resource *pResource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ResolveSubresource( + /* [annotation] */ + __in ID3D11Resource *pDstResource, + /* [annotation] */ + __in UINT DstSubresource, + /* [annotation] */ + __in ID3D11Resource *pSrcResource, + /* [annotation] */ + __in UINT SrcSubresource, + /* [annotation] */ + __in DXGI_FORMAT Format)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ExecuteCommandList( + /* [annotation] */ + __in ID3D11CommandList *pCommandList, + BOOL RestoreContextState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSSetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSSetShader( + /* [annotation] */ + __in_opt ID3D11HullShader *pHullShader, + /* [annotation] */ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSSetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSSetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSSetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSSetShader( + /* [annotation] */ + __in_opt ID3D11DomainShader *pDomainShader, + /* [annotation] */ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSSetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSSetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSSetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSSetUnorderedAccessViews( + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - StartSlot ) UINT NumUAVs, + /* [annotation] */ + __in_ecount(NumUAVs) ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + /* [annotation] */ + __in_ecount(NumUAVs) const UINT *pUAVInitialCounts)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSSetShader( + /* [annotation] */ + __in_opt ID3D11ComputeShader *pComputeShader, + /* [annotation] */ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSSetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSSetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSGetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSGetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSGetShader( + /* [annotation] */ + __out ID3D11PixelShader **ppPixelShader, + /* [annotation] */ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, + /* [annotation] */ + __inout_opt UINT *pNumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSGetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSGetShader( + /* [annotation] */ + __out ID3D11VertexShader **ppVertexShader, + /* [annotation] */ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, + /* [annotation] */ + __inout_opt UINT *pNumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSGetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IAGetInputLayout( + /* [annotation] */ + __out ID3D11InputLayout **ppInputLayout)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IAGetVertexBuffers( + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount_opt(NumBuffers) ID3D11Buffer **ppVertexBuffers, + /* [annotation] */ + __out_ecount_opt(NumBuffers) UINT *pStrides, + /* [annotation] */ + __out_ecount_opt(NumBuffers) UINT *pOffsets)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IAGetIndexBuffer( + /* [annotation] */ + __out_opt ID3D11Buffer **pIndexBuffer, + /* [annotation] */ + __out_opt DXGI_FORMAT *Format, + /* [annotation] */ + __out_opt UINT *Offset)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSGetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSGetShader( + /* [annotation] */ + __out ID3D11GeometryShader **ppGeometryShader, + /* [annotation] */ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, + /* [annotation] */ + __inout_opt UINT *pNumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, IAGetPrimitiveTopology( + /* [annotation] */ + __out D3D11_PRIMITIVE_TOPOLOGY *pTopology)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSGetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSGetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GetPredication( + /* [annotation] */ + __out_opt ID3D11Predicate **ppPredicate, + /* [annotation] */ + __out_opt BOOL *pPredicateValue)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSGetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSGetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMGetRenderTargets( + /* [annotation] */ + __in_range( 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT ) UINT NumViews, + /* [annotation] */ + __out_ecount_opt(NumViews) ID3D11RenderTargetView **ppRenderTargetViews, + /* [annotation] */ + __out_opt ID3D11DepthStencilView **ppDepthStencilView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMGetRenderTargetsAndUnorderedAccessViews( + /* [annotation] */ + __in_range( 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT ) UINT NumRTVs, + /* [annotation] */ + __out_ecount_opt(NumRTVs) ID3D11RenderTargetView **ppRenderTargetViews, + /* [annotation] */ + __out_opt ID3D11DepthStencilView **ppDepthStencilView, + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1 ) UINT UAVStartSlot, + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - UAVStartSlot ) UINT NumUAVs, + /* [annotation] */ + __out_ecount_opt(NumUAVs) ID3D11UnorderedAccessView **ppUnorderedAccessViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMGetBlendState( + /* [annotation] */ + __out_opt ID3D11BlendState **ppBlendState, + /* [annotation] */ + __out_opt FLOAT BlendFactor[ 4 ], + /* [annotation] */ + __out_opt UINT *pSampleMask)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, OMGetDepthStencilState( + /* [annotation] */ + __out_opt ID3D11DepthStencilState **ppDepthStencilState, + /* [annotation] */ + __out_opt UINT *pStencilRef)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SOGetTargets( + /* [annotation] */ + __in_range( 0, D3D11_SO_BUFFER_SLOT_COUNT ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppSOTargets)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, RSGetState( + /* [annotation] */ + __out ID3D11RasterizerState **ppRasterizerState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, RSGetViewports( + /* [annotation] */ + __inout /*_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE )*/ UINT *pNumViewports, + /* [annotation] */ + __out_ecount_opt(*pNumViewports) D3D11_VIEWPORT *pViewports)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, RSGetScissorRects( + /* [annotation] */ + __inout /*_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE )*/ UINT *pNumRects, + /* [annotation] */ + __out_ecount_opt(*pNumRects) D3D11_RECT *pRects)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSGetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSGetShader( + /* [annotation] */ + __out ID3D11HullShader **ppHullShader, + /* [annotation] */ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, + /* [annotation] */ + __inout_opt UINT *pNumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSGetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSGetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSGetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSGetShader( + /* [annotation] */ + __out ID3D11DomainShader **ppDomainShader, + /* [annotation] */ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, + /* [annotation] */ + __inout_opt UINT *pNumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSGetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSGetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSGetShaderResources( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, + /* [annotation] */ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSGetUnorderedAccessViews( + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_PS_CS_UAV_REGISTER_COUNT - StartSlot ) UINT NumUAVs, + /* [annotation] */ + __out_ecount(NumUAVs) ID3D11UnorderedAccessView **ppUnorderedAccessViews)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSGetShader( + /* [annotation] */ + __out ID3D11ComputeShader **ppComputeShader, + /* [annotation] */ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, + /* [annotation] */ + __inout_opt UINT *pNumClassInstances)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSGetSamplers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot ) UINT NumSamplers, + /* [annotation] */ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSGetConstantBuffers( + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + __in_range( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ClearState( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, Flush( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE, GetType( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual UINT STDMETHODCALLTYPE, GetContextFlags( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, FinishCommandList( + BOOL RestoreDeferredContextState, + /* [annotation] */ + __out_opt ID3D11CommandList **ppCommandList)); + + ////////////////////////////// + // implement ID3D11DeviceContext1 + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CopySubresourceRegion1( + /* [annotation] */ + _In_ ID3D11Resource *pDstResource, + /* [annotation] */ + _In_ UINT DstSubresource, + /* [annotation] */ + _In_ UINT DstX, + /* [annotation] */ + _In_ UINT DstY, + /* [annotation] */ + _In_ UINT DstZ, + /* [annotation] */ + _In_ ID3D11Resource *pSrcResource, + /* [annotation] */ + _In_ UINT SrcSubresource, + /* [annotation] */ + _In_opt_ const D3D11_BOX *pSrcBox, + /* [annotation] */ + _In_ UINT CopyFlags)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, UpdateSubresource1( + /* [annotation] */ + _In_ ID3D11Resource *pDstResource, + /* [annotation] */ + _In_ UINT DstSubresource, + /* [annotation] */ + _In_opt_ const D3D11_BOX *pDstBox, + /* [annotation] */ + _In_ const void *pSrcData, + /* [annotation] */ + _In_ UINT SrcRowPitch, + /* [annotation] */ + _In_ UINT SrcDepthPitch, + /* [annotation] */ + _In_ UINT CopyFlags)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DiscardResource( + /* [annotation] */ + _In_ ID3D11Resource *pResource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DiscardView( + /* [annotation] */ + _In_ ID3D11View *pResourceView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSSetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) ID3D11Buffer *const *ppConstantBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pFirstConstant, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSSetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) ID3D11Buffer *const *ppConstantBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pFirstConstant, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSSetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) ID3D11Buffer *const *ppConstantBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pFirstConstant, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSSetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) ID3D11Buffer *const *ppConstantBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pFirstConstant, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSSetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) ID3D11Buffer *const *ppConstantBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pFirstConstant, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSSetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) ID3D11Buffer *const *ppConstantBuffers, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pFirstConstant, + /* [annotation] */ + _In_reads_opt_(NumBuffers) const UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, VSGetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) ID3D11Buffer **ppConstantBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pFirstConstant, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, HSGetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) ID3D11Buffer **ppConstantBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pFirstConstant, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DSGetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) ID3D11Buffer **ppConstantBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pFirstConstant, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GSGetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) ID3D11Buffer **ppConstantBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pFirstConstant, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, PSGetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) ID3D11Buffer **ppConstantBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pFirstConstant, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CSGetConstantBuffers1( + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1 ) UINT StartSlot, + /* [annotation] */ + _In_range_( 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot ) UINT NumBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) ID3D11Buffer **ppConstantBuffers, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pFirstConstant, + /* [annotation] */ + _Out_writes_opt_(NumBuffers) UINT *pNumConstants)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SwapDeviceContextState( + /* [annotation] */ + _In_ ID3DDeviceContextState *pState, + /* [annotation] */ + _Out_opt_ ID3DDeviceContextState **ppPreviousState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ClearView( + /* [annotation] */ + _In_ ID3D11View *pView, + /* [annotation] */ + _In_ const FLOAT Color[ 4 ], + /* [annotation] */ + _In_reads_opt_(NumRects) const D3D11_RECT *pRect, + UINT NumRects)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, DiscardView1( + /* [annotation] */ + _In_ ID3D11View *pResourceView, + /* [annotation] */ + _In_reads_opt_(NumRects) const D3D11_RECT *pRects, + UINT NumRects)); + +}; diff --git a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp new file mode 100644 index 0000000000..08b02440f6 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp @@ -0,0 +1,1314 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "d3d11_context.h" +#include "d3d11_resources.h" +#include "d3d11_renderstate.h" + +#include "common/string_utils.h" + +bool WrappedID3D11DeviceContext::Serialise_CopySubresourceRegion1(ID3D11Resource *pDstResource, UINT DstSubresource, + UINT DstX, UINT DstY, UINT DstZ, + ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox, UINT CopyFlags) +{ + SERIALISE_ELEMENT(ResourceId, Destination, GetIDForResource(pDstResource)); + SERIALISE_ELEMENT(uint32_t, DestSubresource, DstSubresource); + SERIALISE_ELEMENT(uint32_t, DestX, DstX); + SERIALISE_ELEMENT(uint32_t, DestY, DstY); + SERIALISE_ELEMENT(uint32_t, DestZ, DstZ); + SERIALISE_ELEMENT(ResourceId, Source, GetIDForResource(pSrcResource)); + SERIALISE_ELEMENT(uint32_t, SourceSubresource, SrcSubresource); + SERIALISE_ELEMENT(uint8_t, HasSourceBox, pSrcBox != NULL); + SERIALISE_ELEMENT_OPT(D3D11_BOX, SourceBox, *pSrcBox, HasSourceBox); + SERIALISE_ELEMENT(UINT, flags, CopyFlags); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(Destination)) + { + D3D11_BOX *box = &SourceBox; + if(!HasSourceBox) + box = NULL; + + if(m_pRealContext1) + { + m_pRealContext1->CopySubresourceRegion1(m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(Destination)), + DestSubresource, DestX, DestY, DestZ, + m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(Source)), + SourceSubresource, box, flags); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + } + + return true; +} + +void WrappedID3D11DeviceContext::CopySubresourceRegion1(ID3D11Resource *pDstResource, UINT DstSubresource, + UINT DstX, UINT DstY, UINT DstZ, + ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox, UINT CopyFlags) +{ + if(m_pRealContext1 == NULL) return; + + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(COPY_SUBRESOURCE_REGION1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CopySubresourceRegion1(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, pSrcBox, CopyFlags); + + m_MissingTracks.insert(GetIDForResource(pDstResource)); + + m_ContextRecord->AddChunk(scope.Get()); + } + else + { + // just mark dirty + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); + RDCASSERT(record); + + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstResource)); + } + + m_pRealContext1->CopySubresourceRegion1(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), + DstSubresource, DstX, DstY, DstZ, + m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource), + SrcSubresource, pSrcBox, CopyFlags); +} + +bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pDstResource, UINT DstSubresource, const D3D11_BOX *pDstBox, + const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch, UINT CopyFlags) +{ + SERIALISE_ELEMENT(ResourceId, idx, GetIDForResource(pDstResource)); + SERIALISE_ELEMENT(uint32_t, flags, CopyFlags); + SERIALISE_ELEMENT(uint32_t, DestSubresource, DstSubresource); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(idx); + + D3D11ResourceRecord *parent = record; + + if(record && record->NumSubResources > (int)DestSubresource) + record = (D3D11ResourceRecord *)record->SubResources[DestSubresource]; + + SERIALISE_ELEMENT(uint8_t, isUpdate, record->DataInSerialiser); + + ID3D11Resource *DestResource = pDstResource; + if(m_State < WRITING) + DestResource = (ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(idx); + + if(isUpdate) + { + SERIALISE_ELEMENT(uint8_t, HasDestBox, pDstBox != NULL); + SERIALISE_ELEMENT_OPT(D3D11_BOX, box, *pDstBox, HasDestBox); + SERIALISE_ELEMENT(uint32_t, SourceRowPitch, SrcRowPitch); + SERIALISE_ELEMENT(uint32_t, SourceDepthPitch, SrcDepthPitch); + + size_t srcLength = 0; + + if(m_State >= WRITING) + { + RDCASSERT(record); + + if(WrappedID3D11Buffer::IsAlloc(DestResource)) + { + srcLength = record->Length; + + if(HasDestBox) + srcLength = RDCMIN((uint32_t)srcLength, pDstBox->right - pDstBox->left); + } + else + { + WrappedID3D11Texture1D *tex1 = WrappedID3D11Texture1D::IsAlloc(DestResource) ? (WrappedID3D11Texture1D *)DestResource : NULL; + WrappedID3D11Texture2D *tex2 = WrappedID3D11Texture2D::IsAlloc(DestResource) ? (WrappedID3D11Texture2D *)DestResource : NULL; + WrappedID3D11Texture3D *tex3 = WrappedID3D11Texture3D::IsAlloc(DestResource) ? (WrappedID3D11Texture3D *)DestResource : NULL; + + UINT mipLevel = GetMipForSubresource(DestResource, DestSubresource); + + if(tex1) + { + srcLength = record->Length; + + if(HasDestBox) + srcLength = RDCMIN((uint32_t)srcLength, pDstBox->right - pDstBox->left); + } + else if(tex2) + { + D3D11_TEXTURE2D_DESC desc = {0}; + tex2->GetDesc(&desc); + size_t rows = RDCMAX(1U,desc.Height>>mipLevel); + DXGI_FORMAT fmt = desc.Format; + + if(HasDestBox) + rows = (pDstBox->bottom - pDstBox->top); + + if(IsBlockFormat(fmt)) + rows = RDCMAX((size_t)1, rows/4); + + srcLength = SourceRowPitch*rows; + } + else if(tex3) + { + D3D11_TEXTURE3D_DESC desc = {0}; + tex3->GetDesc(&desc); + size_t slices = RDCMAX(1U,desc.Depth>>mipLevel); + + srcLength = SourceDepthPitch*slices; + + if(HasDestBox) + srcLength = SourceDepthPitch*(pDstBox->back - pDstBox->front); + } + else + { + RDCERR("UpdateSubResource on unexpected resource type"); + } + } + + if(m_State == WRITING_CAPFRAME) + { + // partial update + if(srcLength != (size_t)record->Length) + MarkResourceReferenced(idx, eFrameRef_Read); + MarkResourceReferenced(idx, eFrameRef_Write); + } + } + + SERIALISE_ELEMENT(uint32_t, SourceDataLength, (uint32_t)srcLength); + + SERIALISE_ELEMENT_BUF(byte *, SourceData, (byte *)pSrcData, SourceDataLength); + + if(m_State < WRITING) + { + D3D11_BOX *pBox = NULL; + if(HasDestBox) + pBox = &box; + + if(flags == 0) + { + m_pRealContext->UpdateSubresource(m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, pBox, + SourceData, SourceRowPitch, SourceDepthPitch); + } + else + { + if(m_pRealContext1) + { + m_pRealContext1->UpdateSubresource1(m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, pBox, + SourceData, SourceRowPitch, SourceDepthPitch, flags); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + } + + SAFE_DELETE_ARRAY(SourceData); + } + } + else + { + SERIALISE_ELEMENT(uint32_t, ResourceBufLen, record->Length); + + byte *padding = m_State >= WRITING ? new byte[ResourceBufLen] : NULL; + + SERIALISE_ELEMENT_BUF(byte *, bufData, padding, ResourceBufLen); + + if(record) + record->SetDataOffset(m_pSerialiser->GetOffset() - ResourceBufLen); + + SAFE_DELETE_ARRAY(padding); + + if(m_State <= EXECUTING) + { + WrappedID3D11Texture1D *tex1 = WrappedID3D11Texture1D::IsAlloc(DestResource) ? (WrappedID3D11Texture1D *)DestResource : NULL; + WrappedID3D11Texture2D *tex2 = WrappedID3D11Texture2D::IsAlloc(DestResource) ? (WrappedID3D11Texture2D *)DestResource : NULL; + WrappedID3D11Texture3D *tex3 = WrappedID3D11Texture3D::IsAlloc(DestResource) ? (WrappedID3D11Texture3D *)DestResource : NULL; + + DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN; + UINT subWidth = 1; + UINT subHeight = 1; + + UINT mipLevel = GetMipForSubresource(DestResource, DestSubresource); + + if(tex1) + { + D3D11_TEXTURE1D_DESC desc = {0}; + tex1->GetDesc(&desc); + fmt = desc.Format; + subWidth = RDCMAX(1U, desc.Width>>mipLevel); + } + else if(tex2) + { + D3D11_TEXTURE2D_DESC desc = {0}; + tex2->GetDesc(&desc); + fmt = desc.Format; + subWidth = RDCMAX(1U, desc.Width>>mipLevel); + subHeight = RDCMAX(1U, desc.Height>>mipLevel); + } + else if(tex3) + { + D3D11_TEXTURE3D_DESC desc = {0}; + tex3->GetDesc(&desc); + fmt = desc.Format; + subWidth = RDCMAX(1U, desc.Width>>mipLevel); + subHeight = RDCMAX(1U, desc.Height>>mipLevel); + } + + UINT SourceRowPitch = GetByteSize(subWidth, 1, 1, fmt, 0); + UINT SourceDepthPitch = GetByteSize(subWidth, subHeight, 1, fmt, 0); + + if(flags == 0) + { + m_pRealContext->UpdateSubresource(m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, NULL, + bufData, SourceRowPitch, SourceDepthPitch); + } + else + { + if(m_pRealContext1) + { + m_pRealContext1->UpdateSubresource1(m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, NULL, + bufData, SourceRowPitch, SourceDepthPitch, flags); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + } + } + + if(m_State <= EXECUTING) + SAFE_DELETE_ARRAY(bufData); + } + + return true; +} + +void WrappedID3D11DeviceContext::UpdateSubresource1(ID3D11Resource *pDstResource, UINT DstSubresource, const D3D11_BOX *pDstBox, + const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch, UINT CopyFlags) +{ + if(m_pRealContext1 == NULL) return; + + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(UPDATE_SUBRESOURCE1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_UpdateSubresource1(pDstResource, DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch, CopyFlags); + + m_MissingTracks.insert(GetIDForResource(pDstResource)); + + m_ContextRecord->AddChunk(scope.Get()); + } + else + { + // just mark dirty + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstResource)); + } + + m_pRealContext1->UpdateSubresource1(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch, CopyFlags); +} + +bool WrappedID3D11DeviceContext::Serialise_ClearView(ID3D11View *pView, const FLOAT ColorRGBA[4], const D3D11_RECT *pRect, UINT NumRects) +{ + SERIALISE_ELEMENT(ResourceId, View, GetIDForResource(pView)); + + float Color[4] = {0}; + + if(m_State >= WRITING) + memcpy(Color, ColorRGBA, sizeof(float)*4); + + m_pSerialiser->Serialise<4>("ColorRGBA", Color); + + SERIALISE_ELEMENT(uint32_t, numRects, NumRects); + SERIALISE_ELEMENT_ARR(D3D11_RECT, rects, pRect, NumRects); + + if(m_State <= EXECUTING) + { + ID3D11View *wrapped = (ID3D11View *)m_pDevice->GetResourceManager()->GetLiveResource(View); + + ID3D11View *real = NULL; + + if(WrappedID3D11RenderTargetView::IsAlloc(wrapped)) + real = UNWRAP(WrappedID3D11RenderTargetView, wrapped); + else if(WrappedID3D11DepthStencilView::IsAlloc(wrapped)) + real = UNWRAP(WrappedID3D11DepthStencilView, wrapped); + else if(WrappedID3D11ShaderResourceView::IsAlloc(wrapped)) + real = UNWRAP(WrappedID3D11ShaderResourceView, wrapped); + else if(WrappedID3D11UnorderedAccessView::IsAlloc(wrapped)) + real = UNWRAP(WrappedID3D11UnorderedAccessView, wrapped); + + RDCASSERT(real); + + m_pRealContext1->ClearView(real, Color, rects, numRects); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(CLEAR_VIEW, desc); + string name = "ClearView(" + + ToStr::Get(Color[0]) + ", " + + ToStr::Get(Color[1]) + ", " + + ToStr::Get(Color[2]) + ", " + + ToStr::Get(Color[3]) + ", " + + ToStr::Get(numRects) + " rects" + ")"; + + FetchDrawcall draw; + + draw.name = widen(name); + + draw.flags |= eDraw_Clear; + + draw.duration = 0.1f; + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + SAFE_DELETE_ARRAY(rects); + + return true; +} + +void WrappedID3D11DeviceContext::ClearView(ID3D11View *pView, const FLOAT Color[4], const D3D11_RECT *pRect, UINT NumRects) +{ + if(m_pRealContext1 == NULL) return; + + DrainAnnotationQueue(); + + if(pView == NULL) return; + + m_EmptyCommandList = false; + + { + ID3D11View *real = NULL; + + if(WrappedID3D11RenderTargetView::IsAlloc(pView)) + real = UNWRAP(WrappedID3D11RenderTargetView, pView); + else if(WrappedID3D11DepthStencilView::IsAlloc(pView)) + real = UNWRAP(WrappedID3D11DepthStencilView, pView); + else if(WrappedID3D11ShaderResourceView::IsAlloc(pView)) + real = UNWRAP(WrappedID3D11ShaderResourceView, pView); + else if(WrappedID3D11UnorderedAccessView::IsAlloc(pView)) + real = UNWRAP(WrappedID3D11UnorderedAccessView, pView); + + RDCASSERT(real); + + m_pRealContext1->ClearView(real, Color, pRect, NumRects); + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_VIEW); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearView(pView, Color, pRect, NumRects); + + ID3D11Resource *viewRes = NULL; + pView->GetResource(&viewRes); + + m_MissingTracks.insert(GetIDForResource(pView)); + m_MissingTracks.insert(GetIDForResource(viewRes)); + + SAFE_RELEASE(viewRes); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_VIEW); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearView(pView, Color, pRect, NumRects); + + ID3D11Resource *viewRes = NULL; + pView->GetResource(&viewRes); + ResourceId id = GetIDForResource(viewRes); + SAFE_RELEASE(viewRes); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(scope.Get()); + } + + if(pView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pView->GetResource(&res); + + if(m_State == WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Write); + + SAFE_RELEASE(res); + } +} + +bool WrappedID3D11DeviceContext::Serialise_VSSetConstantBuffers1(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Offsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Counts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + SERIALISE_ELEMENT(bool, setCBs, ppConstantBuffers != NULL); + SERIALISE_ELEMENT(bool, setOffs, pFirstConstant != NULL); + SERIALISE_ELEMENT(bool, setCounts, pNumConstants != NULL); + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, ppConstantBuffers ? GetIDForResource(ppConstantBuffers[i]) : ResourceId()); + SERIALISE_ELEMENT(uint32_t, offs, pFirstConstant ? pFirstConstant[i] : 0); + SERIALISE_ELEMENT(uint32_t, count, pNumConstants ? pNumConstants[i] : 4096); + + if(m_State <= EXECUTING) + { + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Offsets[i] = offs; + Counts[i] = count; + } + } + + if(m_State <= EXECUTING) + { + if(setCBs) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + if(setOffs) + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBOffsets, Offsets, StartSlot, NumBuffers); + if(setCounts) + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBCounts, Counts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_pRealContext1 && m_SetCBuffer1) + { + m_pRealContext1->VSSetConstantBuffers1(StartSlot, NumBuffers, setCBs ? Buffers : NULL, setOffs ? Offsets : NULL, setCounts ? Counts : NULL); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::VSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + VSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + return; + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VS_CBUFFERS1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_VSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(ppConstantBuffers) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + + if(pFirstConstant) + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBOffsets, pFirstConstant, StartSlot, NumBuffers); + + if(pNumConstants) + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBCounts, pNumConstants, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext1->VSSetConstantBuffers1(StartSlot, NumBuffers, bufs, pFirstConstant, pNumConstants); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_HSSetConstantBuffers1(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Offsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Counts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + SERIALISE_ELEMENT(bool, setCBs, ppConstantBuffers != NULL); + SERIALISE_ELEMENT(bool, setOffs, pFirstConstant != NULL); + SERIALISE_ELEMENT(bool, setCounts, pNumConstants != NULL); + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, ppConstantBuffers ? GetIDForResource(ppConstantBuffers[i]) : ResourceId()); + SERIALISE_ELEMENT(uint32_t, offs, pFirstConstant ? pFirstConstant[i] : 0); + SERIALISE_ELEMENT(uint32_t, count, pNumConstants ? pNumConstants[i] : 4096); + + if(m_State <= EXECUTING) + { + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Offsets[i] = offs; + Counts[i] = count; + } + } + + if(m_State <= EXECUTING) + { + if(setCBs) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + if(setOffs) + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBOffsets, Offsets, StartSlot, NumBuffers); + if(setCounts) + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBCounts, Counts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_pRealContext1 && m_SetCBuffer1) + { + m_pRealContext1->HSSetConstantBuffers1(StartSlot, NumBuffers, setCBs ? Buffers : NULL, setOffs ? Offsets : NULL, setCounts ? Counts : NULL); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + VerifyState(); + } + + return true; +} + + +void WrappedID3D11DeviceContext::HSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + HSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + return; + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_HS_CBUFFERS1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_HSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(ppConstantBuffers) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + + if(pFirstConstant) + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBOffsets, pFirstConstant, StartSlot, NumBuffers); + + if(pNumConstants) + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBCounts, pNumConstants, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext1->HSSetConstantBuffers1(StartSlot, NumBuffers, bufs, pFirstConstant, pNumConstants); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_DSSetConstantBuffers1(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Offsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Counts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + SERIALISE_ELEMENT(bool, setCBs, ppConstantBuffers != NULL); + SERIALISE_ELEMENT(bool, setOffs, pFirstConstant != NULL); + SERIALISE_ELEMENT(bool, setCounts, pNumConstants != NULL); + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, ppConstantBuffers ? GetIDForResource(ppConstantBuffers[i]) : ResourceId()); + SERIALISE_ELEMENT(uint32_t, offs, pFirstConstant ? pFirstConstant[i] : 0); + SERIALISE_ELEMENT(uint32_t, count, pNumConstants ? pNumConstants[i] : 4096); + + if(m_State <= EXECUTING) + { + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Offsets[i] = offs; + Counts[i] = count; + } + } + + if(m_State <= EXECUTING) + { + if(setCBs) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + if(setOffs) + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBOffsets, Offsets, StartSlot, NumBuffers); + if(setCounts) + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBCounts, Counts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_pRealContext1 && m_SetCBuffer1) + { + m_pRealContext1->DSSetConstantBuffers1(StartSlot, NumBuffers, setCBs ? Buffers : NULL, setOffs ? Offsets : NULL, setCounts ? Counts : NULL); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + VerifyState(); + } + + return true; +} + + +void WrappedID3D11DeviceContext::DSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + DSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + return; + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_DS_CBUFFERS1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(ppConstantBuffers) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + + if(pFirstConstant) + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBOffsets, pFirstConstant, StartSlot, NumBuffers); + + if(pNumConstants) + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBCounts, pNumConstants, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext1->DSSetConstantBuffers1(StartSlot, NumBuffers, bufs, pFirstConstant, pNumConstants); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_GSSetConstantBuffers1(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Offsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Counts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + SERIALISE_ELEMENT(bool, setCBs, ppConstantBuffers != NULL); + SERIALISE_ELEMENT(bool, setOffs, pFirstConstant != NULL); + SERIALISE_ELEMENT(bool, setCounts, pNumConstants != NULL); + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, ppConstantBuffers ? GetIDForResource(ppConstantBuffers[i]) : ResourceId()); + SERIALISE_ELEMENT(uint32_t, offs, pFirstConstant ? pFirstConstant[i] : 0); + SERIALISE_ELEMENT(uint32_t, count, pNumConstants ? pNumConstants[i] : 4096); + + if(m_State <= EXECUTING) + { + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Offsets[i] = offs; + Counts[i] = count; + } + } + + if(m_State <= EXECUTING) + { + if(setCBs) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + if(setOffs) + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBOffsets, Offsets, StartSlot, NumBuffers); + if(setCounts) + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBCounts, Counts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_pRealContext1 && m_SetCBuffer1) + { + m_pRealContext1->GSSetConstantBuffers1(StartSlot, NumBuffers, setCBs ? Buffers : NULL, setOffs ? Offsets : NULL, setCounts ? Counts : NULL); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + VerifyState(); + } + + return true; +} + + +void WrappedID3D11DeviceContext::GSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + GSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + return; + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_GS_CBUFFERS1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_GSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(ppConstantBuffers) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + + if(pFirstConstant) + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBOffsets, pFirstConstant, StartSlot, NumBuffers); + + if(pNumConstants) + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBCounts, pNumConstants, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext1->GSSetConstantBuffers1(StartSlot, NumBuffers, bufs, pFirstConstant, pNumConstants); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_PSSetConstantBuffers1(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Offsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Counts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + SERIALISE_ELEMENT(bool, setCBs, ppConstantBuffers != NULL); + SERIALISE_ELEMENT(bool, setOffs, pFirstConstant != NULL); + SERIALISE_ELEMENT(bool, setCounts, pNumConstants != NULL); + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, ppConstantBuffers ? GetIDForResource(ppConstantBuffers[i]) : ResourceId()); + SERIALISE_ELEMENT(uint32_t, offs, pFirstConstant ? pFirstConstant[i] : 0); + SERIALISE_ELEMENT(uint32_t, count, pNumConstants ? pNumConstants[i] : 4096); + + if(m_State <= EXECUTING) + { + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Offsets[i] = offs; + Counts[i] = count; + } + } + + if(m_State <= EXECUTING) + { + if(setCBs) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + if(setOffs) + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBOffsets, Offsets, StartSlot, NumBuffers); + if(setCounts) + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBCounts, Counts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_pRealContext1 && m_SetCBuffer1) + { + m_pRealContext1->PSSetConstantBuffers1(StartSlot, NumBuffers, setCBs ? Buffers : NULL, setOffs ? Offsets : NULL, setCounts ? Counts : NULL); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + VerifyState(); + } + + return true; +} + + +void WrappedID3D11DeviceContext::PSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + PSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + return; + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_PS_CBUFFERS1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_PSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(ppConstantBuffers) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + + if(pFirstConstant) + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBOffsets, pFirstConstant, StartSlot, NumBuffers); + + if(pNumConstants) + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBCounts, pNumConstants, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext1->PSSetConstantBuffers1(StartSlot, NumBuffers, bufs, pFirstConstant, pNumConstants); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_CSSetConstantBuffers1(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Offsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + uint32_t Counts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + SERIALISE_ELEMENT(bool, setCBs, ppConstantBuffers != NULL); + SERIALISE_ELEMENT(bool, setOffs, pFirstConstant != NULL); + SERIALISE_ELEMENT(bool, setCounts, pNumConstants != NULL); + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, ppConstantBuffers ? GetIDForResource(ppConstantBuffers[i]) : ResourceId()); + SERIALISE_ELEMENT(uint32_t, offs, pFirstConstant ? pFirstConstant[i] : 0); + SERIALISE_ELEMENT(uint32_t, count, pNumConstants ? pNumConstants[i] : 4096); + + if(m_State <= EXECUTING) + { + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Offsets[i] = offs; + Counts[i] = count; + } + } + + if(m_State <= EXECUTING) + { + if(setCBs) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + if(setOffs) + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBOffsets, Offsets, StartSlot, NumBuffers); + if(setCounts) + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBCounts, Counts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_pRealContext1) + { + m_pRealContext1->CSSetConstantBuffers1(StartSlot, NumBuffers, setCBs ? Buffers : NULL, setOffs ? Offsets : NULL, setCounts ? Counts : NULL); + } + else + { + RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + } + VerifyState(); + } + + return true; +} + + +void WrappedID3D11DeviceContext::CSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers, const UINT *pFirstConstant, const UINT *pNumConstants) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + CSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + return; + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_CS_CBUFFERS1); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(ppConstantBuffers) + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + + if(pFirstConstant) + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBOffsets, pFirstConstant, StartSlot, NumBuffers); + + if(pNumConstants) + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBCounts, pNumConstants, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext1->CSSetConstantBuffers1(StartSlot, NumBuffers, bufs, pFirstConstant, pNumConstants); + VerifyState(); +} + +void WrappedID3D11DeviceContext::VSGetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers, UINT *pFirstConstant, UINT *pNumConstants) +{ + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + VSGetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + for(UINT i=0; i < NumBuffers && (pFirstConstant || pNumConstants); i++) + { + if(pFirstConstant) pFirstConstant[i] = 0; + if(pNumConstants) pNumConstants[i] = 4096; + } + + return; + } + + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext1->VSGetConstantBuffers1(StartSlot, NumBuffers, real, pFirstConstant, pNumConstants); + + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->VS.ConstantBuffers[i+StartSlot]); + } + + if(pFirstConstant) + RDCASSERT(pFirstConstant[i] == m_CurrentPipelineState->VS.CBOffsets[i+StartSlot]); + + if(pNumConstants) + RDCASSERT(pNumConstants[i] == m_CurrentPipelineState->VS.CBCounts[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::HSGetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers, UINT *pFirstConstant, UINT *pNumConstants) +{ + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + HSGetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + for(UINT i=0; i < NumBuffers && (pFirstConstant || pNumConstants); i++) + { + if(pFirstConstant) pFirstConstant[i] = 0; + if(pNumConstants) pNumConstants[i] = 4096; + } + + return; + } + + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext1->HSGetConstantBuffers1(StartSlot, NumBuffers, real, pFirstConstant, pNumConstants); + + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->HS.ConstantBuffers[i+StartSlot]); + } + + if(pFirstConstant) + RDCASSERT(pFirstConstant[i] == m_CurrentPipelineState->HS.CBOffsets[i+StartSlot]); + + if(pNumConstants) + RDCASSERT(pNumConstants[i] == m_CurrentPipelineState->HS.CBCounts[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::DSGetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers, UINT *pFirstConstant, UINT *pNumConstants) +{ + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + DSGetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + for(UINT i=0; i < NumBuffers && (pFirstConstant || pNumConstants); i++) + { + if(pFirstConstant) pFirstConstant[i] = 0; + if(pNumConstants) pNumConstants[i] = 4096; + } + + return; + } + + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext1->DSGetConstantBuffers1(StartSlot, NumBuffers, real, pFirstConstant, pNumConstants); + + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->DS.ConstantBuffers[i+StartSlot]); + } + + if(pFirstConstant) + RDCASSERT(pFirstConstant[i] == m_CurrentPipelineState->DS.CBOffsets[i+StartSlot]); + + if(pNumConstants) + RDCASSERT(pNumConstants[i] == m_CurrentPipelineState->DS.CBCounts[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::GSGetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers, UINT *pFirstConstant, UINT *pNumConstants) +{ + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + GSGetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + for(UINT i=0; i < NumBuffers && (pFirstConstant || pNumConstants); i++) + { + if(pFirstConstant) pFirstConstant[i] = 0; + if(pNumConstants) pNumConstants[i] = 4096; + } + + return; + } + + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext1->GSGetConstantBuffers1(StartSlot, NumBuffers, real, pFirstConstant, pNumConstants); + + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->GS.ConstantBuffers[i+StartSlot]); + } + + if(pFirstConstant) + RDCASSERT(pFirstConstant[i] == m_CurrentPipelineState->GS.CBOffsets[i+StartSlot]); + + if(pNumConstants) + RDCASSERT(pNumConstants[i] == m_CurrentPipelineState->GS.CBCounts[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::PSGetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers, UINT *pFirstConstant, UINT *pNumConstants) +{ + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + PSGetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + for(UINT i=0; i < NumBuffers && (pFirstConstant || pNumConstants); i++) + { + if(pFirstConstant) pFirstConstant[i] = 0; + if(pNumConstants) pNumConstants[i] = 4096; + } + + return; + } + + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext1->PSGetConstantBuffers1(StartSlot, NumBuffers, real, pFirstConstant, pNumConstants); + + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->PS.ConstantBuffers[i+StartSlot]); + } + + if(pFirstConstant) + RDCASSERT(pFirstConstant[i] == m_CurrentPipelineState->PS.CBOffsets[i+StartSlot]); + + if(pNumConstants) + RDCASSERT(pNumConstants[i] == m_CurrentPipelineState->PS.CBCounts[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::CSGetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers, UINT *pFirstConstant, UINT *pNumConstants) +{ + if(m_pRealContext1 == NULL || !m_SetCBuffer1) + { + CSGetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + for(UINT i=0; i < NumBuffers && (pFirstConstant || pNumConstants); i++) + { + if(pFirstConstant) pFirstConstant[i] = 0; + if(pNumConstants) pNumConstants[i] = 4096; + } + + return; + } + + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext1->CSGetConstantBuffers1(StartSlot, NumBuffers, real, pFirstConstant, pNumConstants); + + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->CS.ConstantBuffers[i+StartSlot]); + } + + if(pFirstConstant) + RDCASSERT(pFirstConstant[i] == m_CurrentPipelineState->CS.CBOffsets[i+StartSlot]); + + if(pNumConstants) + RDCASSERT(pNumConstants[i] == m_CurrentPipelineState->CS.CBCounts[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::DiscardResource(ID3D11Resource *pResource) +{ + if(m_pRealContext1 == NULL) return; + + // no need to serialise + m_pRealContext1->DiscardResource(pResource); +} + +void WrappedID3D11DeviceContext::DiscardView(ID3D11View *pResourceView) +{ + if(m_pRealContext1 == NULL) return; + + // no need to serialise + m_pRealContext1->DiscardView(pResourceView); +} + +void WrappedID3D11DeviceContext::SwapDeviceContextState(ID3DDeviceContextState *pState, ID3DDeviceContextState **ppPreviousState) +{ + if(m_pRealContext1 == NULL) return; + RDCUNIMPLEMENTED("Not wrapping SwapDeviceContextState"); + m_pRealContext1->SwapDeviceContextState(pState, ppPreviousState); +} + +void WrappedID3D11DeviceContext::DiscardView1(ID3D11View *pResourceView, const D3D11_RECT *pRects, UINT NumRects) +{ + if(m_pRealContext1 == NULL) return; + m_pRealContext1->DiscardView1(pResourceView, pRects, NumRects); +} diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp new file mode 100644 index 0000000000..2a8f7754c4 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -0,0 +1,6703 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_resources.h" +#include "driver/d3d11/d3d11_renderstate.h" + +#include "common/string_utils.h" + +uint32_t NullCBOffsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; +uint32_t NullCBCounts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + +#pragma region D3DPERF + +bool WrappedID3D11DeviceContext::Serialise_SetMarker(uint32_t col, const wchar_t *name_) +{ + SERIALISE_ELEMENT(uint32_t, colour, col); + + wstring name = name_ ? name_ : L""; + + m_pSerialiser->Serialise("Name", name); + + if(m_State == READING) + { + FetchDrawcall draw; + draw.name = name; + draw.flags |= eDraw_SetMarker; + + AddDrawcall(draw, false); + } + + return true; +} + +bool WrappedID3D11DeviceContext::Serialise_BeginEvent(uint32_t col, const wchar_t *name_) +{ + SERIALISE_ELEMENT(uint32_t, colour, col); + + wstring name = name_ ? name_ : L""; + + m_pSerialiser->Serialise("Name", name); + + if(m_State == READING) + { + FetchDrawcall draw; + draw.name = name; + draw.flags |= eDraw_PushMarker; + + AddDrawcall(draw, false); + } + + return true; +} + +bool WrappedID3D11DeviceContext::Serialise_EndEvent() +{ + if(m_State == READING && !m_CurEvents.empty()) + { + FetchDrawcall draw; + draw.name = L"API Calls"; + draw.flags |= eDraw_SetMarker; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::SetMarker(uint32_t col, const wchar_t *name) +{ + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_MARKER); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_SetMarker(col, name); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +int WrappedID3D11DeviceContext::BeginEvent(uint32_t col, const wchar_t *name) +{ + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(BEGIN_EVENT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_BeginEvent(col, name); + + m_ContextRecord->AddChunk(scope.Get()); + } + + return m_MarkerIndentLevel++; +} + +int WrappedID3D11DeviceContext::EndEvent() +{ + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(END_EVENT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_EndEvent(); + + m_ContextRecord->AddChunk(scope.Get()); + } + + return --m_MarkerIndentLevel; +} + +void WrappedID3D11DeviceContext::ThreadSafe_SetMarker(uint32_t col, const wchar_t *name) +{ + Annotation annot; + annot.m_Type = Annotation::ANNOT_SETMARKER; + annot.m_Col = col; + annot.m_Name = name; + + { + SCOPED_LOCK(m_AnnotLock); + m_AnnotationQueue.push_back(annot); + } +} + +int WrappedID3D11DeviceContext::ThreadSafe_BeginEvent(uint32_t col, const wchar_t *name) +{ + Annotation annot; + annot.m_Type = Annotation::ANNOT_BEGINEVENT; + annot.m_Col = col; + annot.m_Name = name; + + { + SCOPED_LOCK(m_AnnotLock); + m_AnnotationQueue.push_back(annot); + } + + // not thread safe but I don't want to lock over access to this - if people use D3DPERF + MT + // they shouldn't rely on this return value anyway :). + return m_MarkerIndentLevel; +} + +int WrappedID3D11DeviceContext::ThreadSafe_EndEvent() +{ + Annotation annot; + annot.m_Type = Annotation::ANNOT_ENDEVENT; + + { + SCOPED_LOCK(m_AnnotLock); + m_AnnotationQueue.push_back(annot); + } + + // not thread safe but I don't want to lock over access to this - if people use D3DPERF + MT + // they shouldn't rely on this return value anyway :). + return m_MarkerIndentLevel-1; +} + +void WrappedID3D11DeviceContext::DrainAnnotationQueue() +{ + if(m_State != WRITING_CAPFRAME) + return; + + m_AnnotLock.Lock(); + + // fastest possible early-out + if(m_AnnotationQueue.empty()) + { + m_AnnotLock.Unlock(); + return; + } + + vector annotations; + annotations.swap(m_AnnotationQueue); + + m_AnnotLock.Unlock(); + + for(size_t i=0; i < annotations.size(); i++) + { + const Annotation &a = annotations[i]; + + switch(a.m_Type) + { + case Annotation::ANNOT_SETMARKER: + SetMarker(a.m_Col, a.m_Name.c_str()); + break; + case Annotation::ANNOT_BEGINEVENT: + BeginEvent(a.m_Col, a.m_Name.c_str()); + break; + case Annotation::ANNOT_ENDEVENT: + EndEvent(); + break; + } + } +} + +#pragma endregion D3DPERF + +#pragma region Input Assembly + +void WrappedID3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout **ppInputLayout) +{ + if(ppInputLayout) + { + ID3D11InputLayout *real = NULL; + m_pRealContext->IAGetInputLayout(&real); + + SAFE_RELEASE_NOCLEAR(real); + *ppInputLayout = (ID3D11InputLayout *)m_pDevice->GetResourceManager()->GetWrapper(real); + SAFE_ADDREF(*ppInputLayout); + + RDCASSERT(*ppInputLayout == m_CurrentPipelineState->IA.Layout); + } +} + +void WrappedID3D11DeviceContext::IAGetVertexBuffers(UINT StartSlot, UINT NumBuffers, + ID3D11Buffer **ppVertexBuffers, UINT *pStrides, UINT *pOffsets) +{ + ID3D11Buffer *real[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->IAGetVertexBuffers(StartSlot, NumBuffers, real, pStrides, pOffsets); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + if(ppVertexBuffers) + { + ppVertexBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppVertexBuffers[i]); + + RDCASSERT(ppVertexBuffers[i] == m_CurrentPipelineState->IA.VBs[i+StartSlot]); + } + + // D3D11 really inconsistently tracks these. + //RDCASSERT(pStrides[i] == m_CurrentPipelineState->IA.Strides[i+StartSlot]); + //RDCASSERT(pOffsets[i] == m_CurrentPipelineState->IA.Offsets[i+StartSlot]); + } +} + +void WrappedID3D11DeviceContext::IAGetIndexBuffer(ID3D11Buffer **pIndexBuffer, DXGI_FORMAT *Format, UINT *Offset) +{ + if(pIndexBuffer) + { + ID3D11Buffer *real = NULL; + m_pRealContext->IAGetIndexBuffer(&real, Format, Offset); + + SAFE_RELEASE_NOCLEAR(real); + *pIndexBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real); + SAFE_ADDREF(*pIndexBuffer); + + RDCASSERT(*pIndexBuffer == m_CurrentPipelineState->IA.IndexBuffer); + } + if(Format) + RDCASSERT(*Format == m_CurrentPipelineState->IA.IndexFormat); + if(Offset) + RDCASSERT(*Offset == m_CurrentPipelineState->IA.IndexOffset); +} + +void WrappedID3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY *pTopology) +{ + m_pRealContext->IAGetPrimitiveTopology(pTopology); + if(pTopology) + RDCASSERT(*pTopology == m_CurrentPipelineState->IA.Topo); +} + +bool WrappedID3D11DeviceContext::Serialise_IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology_) +{ + SERIALISE_ELEMENT(D3D11_PRIMITIVE_TOPOLOGY, Topology, Topology_); + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Topo, Topology); + m_pRealContext->IASetPrimitiveTopology(Topology); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_TOPOLOGY); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_IASetPrimitiveTopology(Topology); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Topo, Topology); + m_pRealContext->IASetPrimitiveTopology(Topology); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_IASetInputLayout(ID3D11InputLayout *pInputLayout) +{ + SERIALISE_ELEMENT(ResourceId, InputLayout, GetIDForResource(pInputLayout)); + + if(m_State <= EXECUTING) + { + pInputLayout = (ID3D11InputLayout *)m_pDevice->GetResourceManager()->GetLiveResource(InputLayout); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.Layout, pInputLayout); + m_pRealContext->IASetInputLayout(UNWRAP(WrappedID3D11InputLayout, pInputLayout)); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::IASetInputLayout(ID3D11InputLayout *pInputLayout) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_INPUT_LAYOUT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_IASetInputLayout(pInputLayout); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.Layout, pInputLayout); + m_pRealContext->IASetInputLayout(UNWRAP(WrappedID3D11InputLayout, pInputLayout)); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_IASetVertexBuffers(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppVertexBuffers, const UINT *pStrides, const UINT *pOffsets) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + SERIALISE_ELEMENT_ARR(uint32_t, Strides, pStrides, NumBuffers); + SERIALISE_ELEMENT_ARR(uint32_t, Offsets, pOffsets, NumBuffers); + + ID3D11Buffer *Buffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppVertexBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.VBs, Buffers, StartSlot, NumBuffers); + } + + for(UINT i=0; i < NumBuffers; i++) + if(m_State <= EXECUTING) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Strides, Strides, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Offsets, Offsets, StartSlot, NumBuffers); + m_pRealContext->IASetVertexBuffers(StartSlot, NumBuffers, Buffers, Strides, Offsets); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Strides); + SAFE_DELETE_ARRAY(Offsets); + + return true; +} + +void WrappedID3D11DeviceContext::IASetVertexBuffers(UINT StartSlot, UINT NumBuffers, + ID3D11Buffer *const *ppVertexBuffers, const UINT *pStrides, const UINT *pOffsets) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VBUFFER); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_IASetVertexBuffers(StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.VBs, ppVertexBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Strides, pStrides, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Offsets, pOffsets, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppVertexBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppVertexBuffers[i]), eFrameRef_Read); + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppVertexBuffers[i]); + } + + m_pRealContext->IASetVertexBuffers(StartSlot, NumBuffers, bufs, pStrides, pOffsets); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_IASetIndexBuffer(ID3D11Buffer *pIndexBuffer, DXGI_FORMAT Format_, UINT Offset_) +{ + SERIALISE_ELEMENT(ResourceId, Buffer, GetIDForResource(pIndexBuffer)); + SERIALISE_ELEMENT(DXGI_FORMAT, Format, Format_); + SERIALISE_ELEMENT(uint32_t, Offset, Offset_); + + if(m_State <= EXECUTING) + { + pIndexBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(Buffer); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.IndexBuffer, pIndexBuffer); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexFormat, Format); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexOffset, Offset); + m_pRealContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, pIndexBuffer), Format, Offset); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::IASetIndexBuffer(ID3D11Buffer *pIndexBuffer, DXGI_FORMAT Format, UINT Offset) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_IBUFFER); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_IASetIndexBuffer(pIndexBuffer, Format, Offset); + + m_ContextRecord->AddChunk(scope.Get()); + } + + if(pIndexBuffer && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(pIndexBuffer), eFrameRef_Read); + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.IndexBuffer, pIndexBuffer); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexFormat, Format); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexOffset, Offset); + m_pRealContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, pIndexBuffer), Format, Offset); + VerifyState(); +} + +#pragma endregion Input Assembly + +#pragma region Vertex Shader + +void WrappedID3D11DeviceContext::VSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) +{ + if(ppConstantBuffers) + { + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext->VSGetConstantBuffers(StartSlot, NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->VS.ConstantBuffers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::VSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) +{ + if(ppShaderResourceViews) + { + ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->VSGetShaderResources(StartSlot, NumViews, real); + + for(UINT i=0; i < NumViews; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppShaderResourceViews[i]); + + RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->VS.SRVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::VSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) +{ + if(ppSamplers) + { + ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; + m_pRealContext->VSGetSamplers(StartSlot, NumSamplers, real); + + for(UINT i=0; i < NumSamplers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSamplers[i]); + + RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->VS.Samplers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::VSGetShader(ID3D11VertexShader **ppVertexShader, ID3D11ClassInstance **ppClassInstances, + UINT *pNumClassInstances) +{ + if(ppVertexShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) + return; + + ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; + UINT numInsts = 0; + ID3D11VertexShader *realShader = NULL; + m_pRealContext->VSGetShader(&realShader, realInsts, &numInsts); + + SAFE_RELEASE_NOCLEAR(realShader); + for(UINT i=0; i < numInsts; i++) + SAFE_RELEASE_NOCLEAR(realInsts[i]); + + if(ppVertexShader) + { + *ppVertexShader = (ID3D11VertexShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); + SAFE_ADDREF(*ppVertexShader); + + RDCASSERT(*ppVertexShader == m_CurrentPipelineState->VS.Shader); + } + + if(ppClassInstances) + { + for(UINT i=0; i < numInsts; i++) + { + ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); + SAFE_ADDREF(ppClassInstances[i]); + + RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->VS.Instances[i]); + } + } + + if(pNumClassInstances) + { + *pNumClassInstances = numInsts; + } +} + +bool WrappedID3D11DeviceContext::Serialise_VSSetConstantBuffers(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppConstantBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + m_pRealContext->VSSetConstantBuffers(StartSlot, NumBuffers, Buffers); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::VSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VS_CBUFFERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_VSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext->VSSetConstantBuffers(StartSlot, NumBuffers, bufs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_VSSetShaderResources(UINT StartSlot_, UINT NumViews_, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + + ID3D11ShaderResourceView **Views = new ID3D11ShaderResourceView *[NumViews]; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppShaderResourceViews[i])); + + if(m_State <= EXECUTING) + Views[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.SRVs, Views, StartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + + m_pRealContext->VSSetShaderResources(StartSlot, NumViews, Views); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Views); + + return true; +} + +void WrappedID3D11DeviceContext::VSSetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VS_RESOURCES); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_VSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.SRVs, ppShaderResourceViews, StartSlot, NumViews); + + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumViews; i++) + { + if(ppShaderResourceViews[i] && m_State >= WRITING_CAPFRAME) + { + ID3D11Resource *res = NULL; + ppShaderResourceViews[i]->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + + SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView, ppShaderResourceViews[i]); + } + + m_pRealContext->VSSetShaderResources(StartSlot, NumViews, SRVs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_VSSetSamplers(UINT StartSlot_, UINT NumSamplers_, ID3D11SamplerState *const *ppSamplers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); + + ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + + for(UINT i=0; i < NumSamplers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); + + if(m_State <= EXECUTING) + Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Samplers, Sampler, StartSlot, NumSamplers); + + for(UINT i=0; i < NumSamplers; i++) + Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + + m_pRealContext->VSSetSamplers(StartSlot, NumSamplers, Sampler); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Sampler); + + return true; +} + +void WrappedID3D11DeviceContext::VSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VS_SAMPLERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_VSSetSamplers(StartSlot, NumSamplers, ppSamplers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Samplers, ppSamplers, StartSlot, NumSamplers); + + ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + for(UINT i=0; i < NumSamplers; i++) + samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); + + m_pRealContext->VSSetSamplers(StartSlot, NumSamplers, samps); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_VSSetShader(ID3D11VertexShader *pShader, ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances_) +{ + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(pShader)); + SERIALISE_ELEMENT(uint32_t, NumClassInstances, NumClassInstances_); + + ID3D11ClassInstance **Instances = new ID3D11ClassInstance *[NumClassInstances]; + + for(UINT i=0; i < NumClassInstances; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppClassInstances[i])); + + if(m_State <= EXECUTING) + Instances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Instances, Instances, 0, NumClassInstances); + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.NumInstances, NumClassInstances); + + for(UINT i=0; i < NumClassInstances; i++) + Instances[i] = UNWRAP(WrappedID3D11ClassInstance, Instances[i]); + + ID3D11DeviceChild *pShader = (ID3D11DeviceChild *)m_pDevice->GetResourceManager()->GetLiveResource(Shader); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Shader, pShader); + m_pRealContext->VSSetShader(UNWRAP(WrappedID3D11Shader, pShader), Instances, NumClassInstances); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::VSSetShader(ID3D11VertexShader *pVertexShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_VSSetShader(pVertexShader, ppClassInstances, NumClassInstances); + + MarkResourceReferenced(GetIDForResource(pVertexShader), eFrameRef_Read); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Shader, (ID3D11DeviceChild *)pVertexShader); + m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.NumInstances, NumClassInstances); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Instances, ppClassInstances, 0, NumClassInstances); + + ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; + if(ppClassInstances && NumClassInstances > 0) + for(UINT i=0; i < NumClassInstances; i++) + insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); + + m_pRealContext->VSSetShader(UNWRAP(WrappedID3D11Shader, pVertexShader), insts, NumClassInstances); + VerifyState(); +} + +#pragma endregion Vertex Shader + +#pragma region Hull Shader + +void WrappedID3D11DeviceContext::HSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) +{ + if(ppConstantBuffers) + { + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext->HSGetConstantBuffers(StartSlot, NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->HS.ConstantBuffers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::HSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) +{ + if(ppShaderResourceViews) + { + ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->HSGetShaderResources(StartSlot, NumViews, real); + + for(UINT i=0; i < NumViews; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppShaderResourceViews[i]); + + RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->HS.SRVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::HSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) +{ + if(ppSamplers) + { + ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; + m_pRealContext->HSGetSamplers(StartSlot, NumSamplers, real); + + for(UINT i=0; i < NumSamplers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSamplers[i]); + + RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->HS.Samplers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::HSGetShader(ID3D11HullShader **ppHullShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) +{ + if(ppHullShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) + return; + + ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; + UINT numInsts = 0; + ID3D11HullShader *realShader = NULL; + m_pRealContext->HSGetShader(&realShader, realInsts, &numInsts); + + SAFE_RELEASE_NOCLEAR(realShader); + for(UINT i=0; i < numInsts; i++) + SAFE_RELEASE_NOCLEAR(realInsts[i]); + + if(ppHullShader) + { + *ppHullShader = (ID3D11HullShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); + SAFE_ADDREF(*ppHullShader); + + RDCASSERT(*ppHullShader == m_CurrentPipelineState->HS.Shader); + } + + if(ppClassInstances) + { + for(UINT i=0; i < numInsts; i++) + { + ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); + SAFE_ADDREF(ppClassInstances[i]); + + RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->HS.Instances[i]); + } + } + + if(pNumClassInstances) + { + *pNumClassInstances = numInsts; + } +} + +bool WrappedID3D11DeviceContext::Serialise_HSSetConstantBuffers(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer **Buffers = new ID3D11Buffer *[NumBuffers]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppConstantBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_State <= EXECUTING) + m_pRealContext->HSSetConstantBuffers(StartSlot, NumBuffers, Buffers); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Buffers); + + return true; +} + +void WrappedID3D11DeviceContext::HSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_HS_CBUFFERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_HSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext->HSSetConstantBuffers(StartSlot, NumBuffers, bufs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_HSSetShaderResources(UINT StartSlot_, UINT NumViews_, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + + ID3D11ShaderResourceView **Views = new ID3D11ShaderResourceView *[NumViews]; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppShaderResourceViews[i])); + + if(m_State <= EXECUTING) + Views[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.SRVs, Views, StartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + + m_pRealContext->HSSetShaderResources(StartSlot, NumViews, Views); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Views); + + return true; +} + +void WrappedID3D11DeviceContext::HSSetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_HS_RESOURCES); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_HSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.SRVs, ppShaderResourceViews, StartSlot, NumViews); + + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumViews; i++) + { + if(ppShaderResourceViews[i] && m_State >= WRITING_CAPFRAME) + { + ID3D11Resource *res = NULL; + ppShaderResourceViews[i]->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + + SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView, ppShaderResourceViews[i]); + } + + m_pRealContext->HSSetShaderResources(StartSlot, NumViews, SRVs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_HSSetSamplers(UINT StartSlot_, UINT NumSamplers_, ID3D11SamplerState *const *ppSamplers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); + + ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + + for(UINT i=0; i < NumSamplers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); + + if(m_State <= EXECUTING) + Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Samplers, Sampler, StartSlot, NumSamplers); + + for(UINT i=0; i < NumSamplers; i++) + Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + + m_pRealContext->HSSetSamplers(StartSlot, NumSamplers, Sampler); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Sampler); + + return true; +} + +void WrappedID3D11DeviceContext::HSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_HS_SAMPLERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_HSSetSamplers(StartSlot, NumSamplers, ppSamplers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Samplers, ppSamplers, StartSlot, NumSamplers); + + ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + for(UINT i=0; i < NumSamplers; i++) + samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); + + m_pRealContext->HSSetSamplers(StartSlot, NumSamplers, samps); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_HSSetShader(ID3D11HullShader *pShader, ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances_) +{ + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(pShader)); + SERIALISE_ELEMENT(uint32_t, NumClassInstances, NumClassInstances_); + + ID3D11ClassInstance **Instances = new ID3D11ClassInstance *[NumClassInstances]; + + for(UINT i=0; i < NumClassInstances; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppClassInstances[i])); + + if(m_State <= EXECUTING) + Instances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Instances, Instances, 0, NumClassInstances); + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.NumInstances, NumClassInstances); + + for(UINT i=0; i < NumClassInstances; i++) + Instances[i] = UNWRAP(WrappedID3D11ClassInstance, Instances[i]); + + ID3D11DeviceChild *pShader = (ID3D11DeviceChild *)m_pDevice->GetResourceManager()->GetLiveResource(Shader); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Shader, pShader); + m_pRealContext->HSSetShader(UNWRAP(WrappedID3D11Shader, pShader), Instances, NumClassInstances); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::HSSetShader(ID3D11HullShader *pHullShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_HS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_HSSetShader(pHullShader, ppClassInstances, NumClassInstances); + + MarkResourceReferenced(GetIDForResource(pHullShader), eFrameRef_Read); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Shader, (ID3D11DeviceChild *)pHullShader); + m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.NumInstances, NumClassInstances); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Instances, ppClassInstances, 0, NumClassInstances); + + ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; + if(ppClassInstances && NumClassInstances > 0) + for(UINT i=0; i < NumClassInstances; i++) + insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); + + m_pRealContext->HSSetShader(UNWRAP(WrappedID3D11Shader, pHullShader), insts, NumClassInstances); + VerifyState(); +} + +#pragma endregion Hull Shader + +#pragma region Domain Shader + +void WrappedID3D11DeviceContext::DSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) +{ + if(ppConstantBuffers) + { + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext->DSGetConstantBuffers(StartSlot, NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->DS.ConstantBuffers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::DSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) +{ + if(ppShaderResourceViews) + { + ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->DSGetShaderResources(StartSlot, NumViews, real); + + for(UINT i=0; i < NumViews; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppShaderResourceViews[i]); + + RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->DS.SRVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::DSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) +{ + if(ppSamplers) + { + ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; + m_pRealContext->DSGetSamplers(StartSlot, NumSamplers, real); + + for(UINT i=0; i < NumSamplers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSamplers[i]); + + RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->DS.Samplers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::DSGetShader(ID3D11DomainShader **ppDomainShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) +{ + if(ppDomainShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) + return; + + ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; + UINT numInsts = 0; + ID3D11DomainShader *realShader = NULL; + m_pRealContext->DSGetShader(&realShader, realInsts, &numInsts); + + SAFE_RELEASE_NOCLEAR(realShader); + for(UINT i=0; i < numInsts; i++) + SAFE_RELEASE_NOCLEAR(realInsts[i]); + + if(ppDomainShader) + { + *ppDomainShader = (ID3D11DomainShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); + SAFE_ADDREF(*ppDomainShader); + + RDCASSERT(*ppDomainShader == m_CurrentPipelineState->DS.Shader); + } + + if(ppClassInstances) + { + for(UINT i=0; i < numInsts; i++) + { + ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); + SAFE_ADDREF(ppClassInstances[i]); + + RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->DS.Instances[i]); + } + } + + if(pNumClassInstances) + { + *pNumClassInstances = numInsts; + } +} + +bool WrappedID3D11DeviceContext::Serialise_DSSetConstantBuffers(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer **Buffers = new ID3D11Buffer *[NumBuffers]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppConstantBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + m_pRealContext->DSSetConstantBuffers(StartSlot, NumBuffers, Buffers); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Buffers); + + return true; +} + +void WrappedID3D11DeviceContext::DSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_DS_CBUFFERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext->DSSetConstantBuffers(StartSlot, NumBuffers, bufs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_DSSetShaderResources(UINT StartSlot_, UINT NumViews_, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + + ID3D11ShaderResourceView **Views = new ID3D11ShaderResourceView *[NumViews]; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppShaderResourceViews[i])); + + if(m_State <= EXECUTING) + Views[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.SRVs, Views, StartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + + m_pRealContext->DSSetShaderResources(StartSlot, NumViews, Views); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Views); + + return true; +} + +void WrappedID3D11DeviceContext::DSSetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_DS_RESOURCES); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.SRVs, ppShaderResourceViews, StartSlot, NumViews); + + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumViews; i++) + { + if(ppShaderResourceViews[i] && m_State >= WRITING_CAPFRAME) + { + ID3D11Resource *res = NULL; + ppShaderResourceViews[i]->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + + SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView, ppShaderResourceViews[i]); + } + + m_pRealContext->DSSetShaderResources(StartSlot, NumViews, SRVs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_DSSetSamplers(UINT StartSlot_, UINT NumSamplers_, ID3D11SamplerState *const *ppSamplers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); + + ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + + for(UINT i=0; i < NumSamplers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); + + if(m_State <= EXECUTING) + Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Samplers, Sampler, StartSlot, NumSamplers); + + for(UINT i=0; i < NumSamplers; i++) + Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + + m_pRealContext->DSSetSamplers(StartSlot, NumSamplers, Sampler); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Sampler); + + return true; +} + +void WrappedID3D11DeviceContext::DSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_DS_SAMPLERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DSSetSamplers(StartSlot, NumSamplers, ppSamplers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Samplers, ppSamplers, StartSlot, NumSamplers); + + ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + for(UINT i=0; i < NumSamplers; i++) + samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); + + m_pRealContext->DSSetSamplers(StartSlot, NumSamplers, samps); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_DSSetShader(ID3D11DomainShader *pShader, ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances_) +{ + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(pShader)); + SERIALISE_ELEMENT(uint32_t, NumClassInstances, NumClassInstances_); + + ID3D11ClassInstance **Instances = new ID3D11ClassInstance *[NumClassInstances]; + + for(UINT i=0; i < NumClassInstances; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppClassInstances[i])); + + if(m_State <= EXECUTING) + Instances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Instances, Instances, 0, NumClassInstances); + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.NumInstances, NumClassInstances); + + for(UINT i=0; i < NumClassInstances; i++) + Instances[i] = UNWRAP(WrappedID3D11ClassInstance, Instances[i]); + + ID3D11DeviceChild *pShader = (ID3D11DeviceChild *)m_pDevice->GetResourceManager()->GetLiveResource(Shader); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Shader, pShader); + m_pRealContext->DSSetShader(UNWRAP(WrappedID3D11Shader, pShader), Instances, NumClassInstances); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::DSSetShader(ID3D11DomainShader *pDomainShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_DS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DSSetShader(pDomainShader, ppClassInstances, NumClassInstances); + + MarkResourceReferenced(GetIDForResource(pDomainShader), eFrameRef_Read); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Shader, (ID3D11DeviceChild *)pDomainShader); + m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.NumInstances, NumClassInstances); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Instances, ppClassInstances, 0, NumClassInstances); + + ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; + if(ppClassInstances && NumClassInstances > 0) + for(UINT i=0; i < NumClassInstances; i++) + insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); + + m_pRealContext->DSSetShader(UNWRAP(WrappedID3D11Shader, pDomainShader), insts, NumClassInstances); + VerifyState(); +} + +#pragma endregion Domain Shader + +#pragma region Geometry Shader + +void WrappedID3D11DeviceContext::GSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) +{ + if(ppConstantBuffers) + { + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext->GSGetConstantBuffers(StartSlot, NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->GS.ConstantBuffers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::GSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) +{ + if(ppShaderResourceViews) + { + ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->GSGetShaderResources(StartSlot, NumViews, real); + + for(UINT i=0; i < NumViews; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppShaderResourceViews[i]); + + RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->GS.SRVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::GSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) +{ + if(ppSamplers) + { + ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; + m_pRealContext->GSGetSamplers(StartSlot, NumSamplers, real); + + for(UINT i=0; i < NumSamplers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSamplers[i]); + + RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->GS.Samplers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::GSGetShader(ID3D11GeometryShader **ppGeometryShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) +{ + if(ppGeometryShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) + return; + + ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; + UINT numInsts = 0; + ID3D11GeometryShader *realShader = NULL; + m_pRealContext->GSGetShader(&realShader, realInsts, &numInsts); + + SAFE_RELEASE_NOCLEAR(realShader); + for(UINT i=0; i < numInsts; i++) + SAFE_RELEASE_NOCLEAR(realInsts[i]); + + if(ppGeometryShader) + { + *ppGeometryShader = (ID3D11GeometryShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); + SAFE_ADDREF(*ppGeometryShader); + + RDCASSERT(*ppGeometryShader == m_CurrentPipelineState->GS.Shader); + } + + if(ppClassInstances) + { + for(UINT i=0; i < numInsts; i++) + { + ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); + SAFE_ADDREF(ppClassInstances[i]); + + RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->GS.Instances[i]); + } + } + + if(pNumClassInstances) + { + *pNumClassInstances = numInsts; + } +} + +bool WrappedID3D11DeviceContext::Serialise_GSSetConstantBuffers(UINT StartSlot_, UINT NumBuffers_, + ID3D11Buffer *const *ppConstantBuffers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer **Buffers = new ID3D11Buffer *[NumBuffers]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppConstantBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + m_pRealContext->GSSetConstantBuffers(StartSlot, NumBuffers, Buffers); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Buffers); + + return true; +} + +void WrappedID3D11DeviceContext::GSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_GS_CBUFFERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_GSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext->GSSetConstantBuffers(StartSlot, NumBuffers, bufs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_GSSetShaderResources(UINT StartSlot_, UINT NumViews_, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + + ID3D11ShaderResourceView **Views = new ID3D11ShaderResourceView *[NumViews]; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppShaderResourceViews[i])); + + if(m_State <= EXECUTING) + Views[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.SRVs, Views, StartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + + m_pRealContext->GSSetShaderResources(StartSlot, NumViews, Views); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Views); + + return true; +} + +void WrappedID3D11DeviceContext::GSSetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_GS_RESOURCES); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_GSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.SRVs, ppShaderResourceViews, StartSlot, NumViews); + + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumViews; i++) + { + if(ppShaderResourceViews[i] && m_State >= WRITING_CAPFRAME) + { + ID3D11Resource *res = NULL; + ppShaderResourceViews[i]->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + + SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView, ppShaderResourceViews[i]); + } + + m_pRealContext->GSSetShaderResources(StartSlot, NumViews, SRVs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_GSSetSamplers(UINT StartSlot_, UINT NumSamplers_, ID3D11SamplerState *const *ppSamplers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); + + ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + + for(UINT i=0; i < NumSamplers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); + + if(m_State <= EXECUTING) + Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Samplers, Sampler, StartSlot, NumSamplers); + + for(UINT i=0; i < NumSamplers; i++) + Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + + m_pRealContext->GSSetSamplers(StartSlot, NumSamplers, Sampler); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Sampler); + + return true; +} + +void WrappedID3D11DeviceContext::GSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_GS_SAMPLERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_GSSetSamplers(StartSlot, NumSamplers, ppSamplers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Samplers, ppSamplers, StartSlot, NumSamplers); + + ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + for(UINT i=0; i < NumSamplers; i++) + samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); + + m_pRealContext->GSSetSamplers(StartSlot, NumSamplers, samps); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_GSSetShader(ID3D11GeometryShader *pShader, ID3D11ClassInstance *const *ppClassInstances, + UINT NumClassInstances_) +{ + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(pShader)); + SERIALISE_ELEMENT(uint32_t, NumClassInstances, NumClassInstances_); + + ID3D11ClassInstance **Instances = new ID3D11ClassInstance *[NumClassInstances]; + + for(UINT i=0; i < NumClassInstances; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppClassInstances[i])); + + if(m_State <= EXECUTING) + Instances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Instances, Instances, 0, NumClassInstances); + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.NumInstances, NumClassInstances); + + for(UINT i=0; i < NumClassInstances; i++) + Instances[i] = UNWRAP(WrappedID3D11ClassInstance, Instances[i]); + + ID3D11DeviceChild *pShader = (ID3D11DeviceChild *)m_pDevice->GetResourceManager()->GetLiveResource(Shader); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Shader, pShader); + m_pRealContext->GSSetShader(UNWRAP(WrappedID3D11Shader, pShader), Instances, NumClassInstances); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::GSSetShader( ID3D11GeometryShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_GS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_GSSetShader(pShader, ppClassInstances, NumClassInstances); + + MarkResourceReferenced(GetIDForResource(pShader), eFrameRef_Read); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Shader, (ID3D11DeviceChild *)pShader); + m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.NumInstances, NumClassInstances); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Instances, ppClassInstances, 0, NumClassInstances); + + ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; + if(ppClassInstances && NumClassInstances > 0) + for(UINT i=0; i < NumClassInstances; i++) + insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); + + m_pRealContext->GSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); + VerifyState(); +} + +#pragma endregion Geometry Shader + +#pragma region Stream Out + +void WrappedID3D11DeviceContext::SOGetTargets(UINT NumBuffers, ID3D11Buffer **ppSOTargets) +{ + if(ppSOTargets) + { + ID3D11Buffer *real[D3D11_SO_BUFFER_SLOT_COUNT] = {0}; + m_pRealContext->SOGetTargets(NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSOTargets[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSOTargets[i]); + + RDCASSERT(ppSOTargets[i] == m_CurrentPipelineState->SO.Buffers[i]); + } + } +} + +bool WrappedID3D11DeviceContext::Serialise_SOSetTargets(UINT NumBuffers_, ID3D11Buffer *const *ppSOTargets, const UINT *pOffsets) +{ + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + SERIALISE_ELEMENT_ARR(uint32_t, Offsets, pOffsets, NumBuffers); + + ID3D11Buffer **Buffers = new ID3D11Buffer *[NumBuffers]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSOTargets[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->SO.Buffers, Buffers, 0, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->SO.Offsets, Offsets, 0, NumBuffers); + } + + for(UINT i=0; i < NumBuffers; i++) + if(m_State <= EXECUTING) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + if(m_State <= EXECUTING) + { + m_pRealContext->SOSetTargets(NumBuffers, Buffers, Offsets); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Buffers); + SAFE_DELETE_ARRAY(Offsets); + + return true; +} + +void WrappedID3D11DeviceContext::SOSetTargets(UINT NumBuffers, ID3D11Buffer *const *ppSOTargets, const UINT *pOffsets) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_SO_TARGETS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_SOSetTargets(NumBuffers, ppSOTargets, pOffsets); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->SO.Buffers, ppSOTargets, 0, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->SO.Offsets, pOffsets, 0, NumBuffers); + + ID3D11Buffer *bufs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + // technically this isn't dirty until the draw call, but let's be conservative + // to avoid having to track "possibly" dirty resources. + // Besides, it's unlikely an application will set an output then not draw to it + if(ppSOTargets[i] && m_State >= WRITING_CAPFRAME) + { + MarkResourceReferenced(GetIDForResource(ppSOTargets[i]), eFrameRef_Write); + + if(m_State == WRITING_CAPFRAME) + m_MissingTracks.insert(GetIDForResource(ppSOTargets[i])); + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(ppSOTargets[i])); + } + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppSOTargets[i]); + } + + m_pRealContext->SOSetTargets(NumBuffers, bufs, pOffsets); + VerifyState(); +} + +#pragma endregion Stream Out + +#pragma region Rasterizer + +void WrappedID3D11DeviceContext::RSGetViewports(UINT *pNumViewports, D3D11_VIEWPORT *pViewports) +{ + m_pRealContext->RSGetViewports(pNumViewports, pViewports); + + if(pViewports) + RDCASSERT(memcmp(pViewports, m_CurrentPipelineState->RS.Viewports, sizeof(D3D11_VIEWPORT)* (*pNumViewports)) == 0); +} + +void WrappedID3D11DeviceContext::RSGetScissorRects(UINT *pNumRects, D3D11_RECT *pRects) +{ + m_pRealContext->RSGetScissorRects(pNumRects, pRects); + + if(pRects) + RDCASSERT(memcmp(pRects, m_CurrentPipelineState->RS.Scissors, sizeof(D3D11_RECT)* (*pNumRects)) == 0); +} + +void WrappedID3D11DeviceContext::RSGetState(ID3D11RasterizerState **ppRasterizerState) +{ + if(ppRasterizerState) + { + ID3D11RasterizerState *real = NULL; + m_pRealContext->RSGetState(&real); + + if(real != NULL) + { + real->Release(); + ID3D11DeviceChild *state = m_pDevice->GetResourceManager()->GetWrapper(real); + if(WrappedID3D11RasterizerState1::IsAlloc(state)) + { + *ppRasterizerState = (ID3D11RasterizerState *)(ID3D11RasterizerState1 *)state; + (*ppRasterizerState)->AddRef(); + } + else + { + *ppRasterizerState = (ID3D11RasterizerState *)state; + (*ppRasterizerState)->AddRef(); + } + } + else + { + *ppRasterizerState = NULL; + } + + RDCASSERT(*ppRasterizerState == m_CurrentPipelineState->RS.State); + } +} + +bool WrappedID3D11DeviceContext::Serialise_RSSetViewports(UINT NumViewports_, const D3D11_VIEWPORT *pViewports) +{ + SERIALISE_ELEMENT(uint32_t, NumViewports, NumViewports_); + + D3D11_VIEWPORT views[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + + for(UINT i=0; i < NumViewports; i++) + { + D3D11_VIEWPORT view; + + if(pViewports) + view = pViewports[i]; + + m_pSerialiser->Serialise<6>((string("Viewport[") + ToStr::Get(i) + "]").c_str(), (FLOAT *)&view); + + views[i] = view; + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Viewports, views, 0, NumViewports); + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumViews, NumViewports); + m_pRealContext->RSSetViewports(NumViewports, views); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::RSSetViewports(UINT NumViewports, const D3D11_VIEWPORT *pViewports) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_VIEWPORTS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_RSSetViewports(NumViewports, pViewports); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Viewports, pViewports, 0, NumViewports); + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumViews, NumViewports); + m_pRealContext->RSSetViewports(NumViewports, pViewports); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_RSSetScissorRects(UINT NumRects_, const D3D11_RECT *pRects_) +{ + SERIALISE_ELEMENT(uint32_t, NumRects, NumRects_); + SERIALISE_ELEMENT_ARR(D3D11_RECT, Rects, pRects_, NumRects); + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Scissors, Rects, 0, NumRects); + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumScissors, NumRects); + RSSetScissorRects(NumRects, Rects); + VerifyState(); + } + + SAFE_DELETE(Rects); + + return true; +} + +void WrappedID3D11DeviceContext::RSSetScissorRects(UINT NumRects, const D3D11_RECT *pRects) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_SCISSORS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_RSSetScissorRects(NumRects, pRects); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Scissors, pRects, 0, NumRects); + m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumScissors, NumRects); + m_pRealContext->RSSetScissorRects(NumRects, pRects); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_RSSetState(ID3D11RasterizerState *pRasterizerState) +{ + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(pRasterizerState)); + + if(m_State <= EXECUTING) + { + ID3D11DeviceChild *live = m_pDevice->GetResourceManager()->GetLiveResource(id); + if(WrappedID3D11RasterizerState1::IsAlloc(live)) + { + ID3D11RasterizerState1 *state = (ID3D11RasterizerState1 *)live; + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->RS.State, (ID3D11RasterizerState *)state); + m_pRealContext->RSSetState((ID3D11RasterizerState *)UNWRAP(WrappedID3D11RasterizerState1, state)); + } + else + { + ID3D11RasterizerState *state = (ID3D11RasterizerState *)live; + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->RS.State, state); + m_pRealContext->RSSetState(UNWRAP(WrappedID3D11RasterizerState, state)); + } + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::RSSetState(ID3D11RasterizerState *pRasterizerState) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_RASTER); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_RSSetState(pRasterizerState); + + m_ContextRecord->AddChunk(scope.Get()); + } + + RDCASSERT(!pRasterizerState || WrappedID3D11RasterizerState::IsAlloc(pRasterizerState) || WrappedID3D11RasterizerState1::IsAlloc(pRasterizerState)); + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->RS.State, pRasterizerState); + if(!pRasterizerState || WrappedID3D11RasterizerState::IsAlloc(pRasterizerState)) + m_pRealContext->RSSetState(UNWRAP(WrappedID3D11RasterizerState, pRasterizerState)); + else + m_pRealContext->RSSetState((ID3D11RasterizerState *)UNWRAP(WrappedID3D11RasterizerState1, pRasterizerState)); + VerifyState(); +} + +#pragma endregion Rasterizer + +#pragma region Pixel Shader + +void WrappedID3D11DeviceContext::PSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) +{ + if(ppConstantBuffers) + { + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext->PSGetConstantBuffers(StartSlot, NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->PS.ConstantBuffers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::PSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) +{ + if(ppShaderResourceViews) + { + ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->PSGetShaderResources(StartSlot, NumViews, real); + + for(UINT i=0; i < NumViews; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppShaderResourceViews[i]); + + RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->PS.SRVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::PSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) +{ + if(ppSamplers) + { + ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; + m_pRealContext->PSGetSamplers(StartSlot, NumSamplers, real); + + for(UINT i=0; i < NumSamplers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSamplers[i]); + + RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->PS.Samplers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::PSGetShader(ID3D11PixelShader **ppPixelShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) +{ + if(ppPixelShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) + return; + + ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; + UINT numInsts = 0; + ID3D11PixelShader *realShader = NULL; + m_pRealContext->PSGetShader(&realShader, realInsts, &numInsts); + + SAFE_RELEASE_NOCLEAR(realShader); + for(UINT i=0; i < numInsts; i++) + SAFE_RELEASE_NOCLEAR(realInsts[i]); + + if(ppPixelShader) + { + *ppPixelShader = (ID3D11PixelShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); + SAFE_ADDREF(*ppPixelShader); + + RDCASSERT(*ppPixelShader == m_CurrentPipelineState->PS.Shader); + } + + if(ppClassInstances) + { + for(UINT i=0; i < numInsts; i++) + { + ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); + SAFE_ADDREF(ppClassInstances[i]); + + RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->PS.Instances[i]); + } + } + + if(pNumClassInstances) + { + *pNumClassInstances = numInsts; + } +} + +bool WrappedID3D11DeviceContext::Serialise_PSSetConstantBuffers(UINT StartSlot_, UINT NumBuffers_, ID3D11Buffer *const *ppConstantBuffers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer *Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppConstantBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + m_pRealContext->PSSetConstantBuffers(StartSlot, NumBuffers, Buffers); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::PSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_PS_CBUFFERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_PSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext->PSSetConstantBuffers(StartSlot, NumBuffers, bufs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_PSSetShaderResources(UINT StartSlot_, UINT NumViews_, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + + ID3D11ShaderResourceView *Views[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppShaderResourceViews[i])); + + if(m_State <= EXECUTING) + Views[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.SRVs, Views, StartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + + m_pRealContext->PSSetShaderResources(StartSlot, NumViews, Views); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::PSSetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_PS_RESOURCES); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_PSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.SRVs, ppShaderResourceViews, StartSlot, NumViews); + + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumViews; i++) + { + if(ppShaderResourceViews[i] && m_State >= WRITING_CAPFRAME) + { + ID3D11Resource *res = NULL; + ppShaderResourceViews[i]->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + + SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView, ppShaderResourceViews[i]); + } + + m_pRealContext->PSSetShaderResources(StartSlot, NumViews, SRVs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_PSSetSamplers(UINT StartSlot_, UINT NumSamplers_, ID3D11SamplerState *const *ppSamplers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); + + ID3D11SamplerState *Sampler[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + + for(UINT i=0; i < NumSamplers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); + + if(m_State <= EXECUTING) + Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Samplers, Sampler, StartSlot, NumSamplers); + + for(UINT i=0; i < NumSamplers; i++) + Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + + m_pRealContext->PSSetSamplers(StartSlot, NumSamplers, Sampler); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::PSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_PS_SAMPLERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_PSSetSamplers(StartSlot, NumSamplers, ppSamplers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Samplers, ppSamplers, StartSlot, NumSamplers); + + ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + for(UINT i=0; i < NumSamplers; i++) + samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); + + m_pRealContext->PSSetSamplers(StartSlot, NumSamplers, samps); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_PSSetShader(ID3D11PixelShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances_) +{ + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(pShader)); + SERIALISE_ELEMENT(uint32_t, NumClassInstances, NumClassInstances_); + + ID3D11ClassInstance **Instances = new ID3D11ClassInstance *[NumClassInstances]; + + for(UINT i=0; i < NumClassInstances; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppClassInstances[i])); + + if(m_State <= EXECUTING) + Instances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Instances, Instances, 0, NumClassInstances); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.NumInstances, NumClassInstances); + + for(UINT i=0; i < NumClassInstances; i++) + Instances[i] = UNWRAP(WrappedID3D11ClassInstance, Instances[i]); + + ID3D11DeviceChild *pShader = (ID3D11DeviceChild *)m_pDevice->GetResourceManager()->GetLiveResource(Shader); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Shader, pShader); + m_pRealContext->PSSetShader(UNWRAP(WrappedID3D11Shader, pShader), Instances, NumClassInstances); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::PSSetShader(ID3D11PixelShader *pPixelShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_PS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_PSSetShader(pPixelShader, ppClassInstances, NumClassInstances); + + MarkResourceReferenced(GetIDForResource(pPixelShader), eFrameRef_Read); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Shader, (ID3D11DeviceChild *)pPixelShader); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.NumInstances, NumClassInstances); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Instances, ppClassInstances, 0, NumClassInstances); + + ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; + if(ppClassInstances && NumClassInstances > 0) + for(UINT i=0; i < NumClassInstances; i++) + insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); + + m_pRealContext->PSSetShader(UNWRAP(WrappedID3D11Shader, pPixelShader), insts, NumClassInstances); + VerifyState(); +} + +#pragma endregion Pixel Shader + +#pragma region Output Merger + +void WrappedID3D11DeviceContext::OMGetRenderTargets(UINT NumViews, ID3D11RenderTargetView **ppRenderTargetViews, ID3D11DepthStencilView **ppDepthStencilView) +{ + if(ppRenderTargetViews == NULL && ppDepthStencilView == NULL) + return; + + ID3D11RenderTargetView *rtv[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; + ID3D11DepthStencilView *dsv = NULL; + m_pRealContext->OMGetRenderTargets(NumViews, rtv, &dsv); + + for(UINT i=0; i < NumViews; i++) + SAFE_RELEASE_NOCLEAR(rtv[i]); + + SAFE_RELEASE_NOCLEAR(dsv); + + if(ppRenderTargetViews) + { + for(UINT i=0; i < NumViews; i++) + { + ppRenderTargetViews[i] = (ID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetWrapper(rtv[i]); + SAFE_ADDREF(ppRenderTargetViews[i]); + + RDCASSERT(ppRenderTargetViews[i] == m_CurrentPipelineState->OM.RenderTargets[i]); + } + } + + if(ppDepthStencilView) + { + *ppDepthStencilView = (ID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetWrapper(dsv); + SAFE_ADDREF(*ppDepthStencilView); + + RDCASSERT(*ppDepthStencilView == m_CurrentPipelineState->OM.DepthView); + } +} + +void WrappedID3D11DeviceContext::OMGetRenderTargetsAndUnorderedAccessViews(UINT NumRTVs, ID3D11RenderTargetView **ppRenderTargetViews, + ID3D11DepthStencilView **ppDepthStencilView, + UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView **ppUnorderedAccessViews) +{ + if(ppRenderTargetViews == NULL && ppDepthStencilView == NULL && ppUnorderedAccessViews == NULL) + return; + + ID3D11RenderTargetView *rtv[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; + ID3D11UnorderedAccessView *uav[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; + ID3D11DepthStencilView *dsv = NULL; + m_pRealContext->OMGetRenderTargetsAndUnorderedAccessViews(NumRTVs, rtv, &dsv, UAVStartSlot, NumUAVs, uav); + + for(UINT i=0; i < NumRTVs; i++) + SAFE_RELEASE_NOCLEAR(rtv[i]); + + SAFE_RELEASE_NOCLEAR(dsv); + + for(UINT i=0; i < NumUAVs; i++) + SAFE_RELEASE_NOCLEAR(uav[i]); + + if(ppRenderTargetViews) + { + for(UINT i=0; i < NumRTVs; i++) + { + ppRenderTargetViews[i] = (ID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetWrapper(rtv[i]); + SAFE_ADDREF(ppRenderTargetViews[i]); + + RDCASSERT(ppRenderTargetViews[i] == m_CurrentPipelineState->OM.RenderTargets[i]); + } + } + + if(ppDepthStencilView) + { + *ppDepthStencilView = (ID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetWrapper(dsv); + SAFE_ADDREF(*ppDepthStencilView); + + RDCASSERT(*ppDepthStencilView == m_CurrentPipelineState->OM.DepthView); + } + + if(ppUnorderedAccessViews) + { + for(UINT i=0; i < NumUAVs; i++) + { + ppUnorderedAccessViews[i] = (ID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetWrapper(uav[i]); + SAFE_ADDREF(ppUnorderedAccessViews[i]); + + RDCASSERT(ppUnorderedAccessViews[i] == m_CurrentPipelineState->OM.UAVs[i]); + } + } +} + +void WrappedID3D11DeviceContext::OMGetBlendState(ID3D11BlendState **ppBlendState, FLOAT BlendFactor[4], UINT *pSampleMask) +{ + ID3D11BlendState *real = NULL; + m_pRealContext->OMGetBlendState(&real, BlendFactor, pSampleMask); + + SAFE_RELEASE_NOCLEAR(real); + + if(ppBlendState) + { + if(real != NULL) + { + ID3D11DeviceChild *state = m_pDevice->GetResourceManager()->GetWrapper(real); + if(WrappedID3D11BlendState1::IsAlloc(state)) + { + *ppBlendState = (ID3D11BlendState *)(ID3D11BlendState1 *)state; + (*ppBlendState)->AddRef(); + } + else + { + *ppBlendState = (ID3D11BlendState *)state; + (*ppBlendState)->AddRef(); + } + } + else + { + *ppBlendState = NULL; + } + + RDCASSERT(*ppBlendState == m_CurrentPipelineState->OM.BlendState); + } + if(BlendFactor) + RDCASSERT(memcmp(BlendFactor, m_CurrentPipelineState->OM.BlendFactor, sizeof(float)*4) == 0); + if(pSampleMask) + RDCASSERT(*pSampleMask == m_CurrentPipelineState->OM.SampleMask); +} + +void WrappedID3D11DeviceContext::OMGetDepthStencilState(ID3D11DepthStencilState **ppDepthStencilState, UINT *pStencilRef) +{ + ID3D11DepthStencilState *real = NULL; + m_pRealContext->OMGetDepthStencilState(&real, pStencilRef); + + SAFE_RELEASE_NOCLEAR(real); + + if(ppDepthStencilState) + { + if(real != NULL) + { + *ppDepthStencilState = (ID3D11DepthStencilState *)m_pDevice->GetResourceManager()->GetWrapper(real); + SAFE_ADDREF(*ppDepthStencilState); + } + else + { + *ppDepthStencilState = NULL; + } + + RDCASSERT(*ppDepthStencilState == m_CurrentPipelineState->OM.DepthStencilState); + } + if(pStencilRef) + RDCASSERT(*pStencilRef == m_CurrentPipelineState->OM.StencRef); +} + +bool WrappedID3D11DeviceContext::Serialise_OMSetRenderTargets(UINT NumViews_, ID3D11RenderTargetView *const *ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) +{ + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + SERIALISE_ELEMENT(ResourceId, DepthStencilView, GetIDForResource(pDepthStencilView)); + + ID3D11RenderTargetView **RenderTargetViews = new ID3D11RenderTargetView *[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + RenderTargetViews[i] = NULL; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppRenderTargetViews[i])); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) + RenderTargetViews[i] = (ID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + pDepthStencilView = NULL; + if(m_pDevice->GetResourceManager()->HasLiveResource(DepthStencilView)) + pDepthStencilView = (ID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetLiveResource(DepthStencilView); + + if(m_CurrentPipelineState->ValidOutputMerger(RenderTargetViews, pDepthStencilView)) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RenderTargetViews, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); + } + + ID3D11UnorderedAccessView *UAVs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_PS_CS_UAV_REGISTER_COUNT); + + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + RenderTargetViews[i] = UNWRAP(WrappedID3D11RenderTargetView, RenderTargetViews[i]); + + m_pRealContext->OMSetRenderTargets(NumViews, RenderTargetViews, + UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView)); + VerifyState(); + } + + SAFE_DELETE_ARRAY(RenderTargetViews); + + return true; +} + +void WrappedID3D11DeviceContext::OMSetRenderTargets(UINT NumViews, ID3D11RenderTargetView *const *ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_SMALL_CONTEXT(SET_RTARGET); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_OMSetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView); + + m_ContextRecord->AddChunk(scope.Get()); + } + + ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; + for(UINT i=0; i < NumViews && ppRenderTargetViews; i++) + RTs[i] = ppRenderTargetViews[i]; + + // this function always sets all render targets + if(m_CurrentPipelineState->ValidOutputMerger(RTs, pDepthStencilView)) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RTs, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, NumViews); + } + + ID3D11UnorderedAccessView *UAVs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_PS_CS_UAV_REGISTER_COUNT); + + for(UINT i=0; i < NumViews; i++) + { + if(ppRenderTargetViews[i] && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + ppRenderTargetViews[i]->GetResource(&res); + // technically this isn't dirty until the draw call, but let's be conservative + // to avoid having to track "possibly" dirty resources. + // Besides, it's unlikely an application will set an output then not draw to it + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + RTs[i] = UNWRAP(WrappedID3D11RenderTargetView, ppRenderTargetViews[i]); + } + + if(pDepthStencilView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pDepthStencilView->GetResource(&res); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + m_pRealContext->OMSetRenderTargets(NumViews, RTs, UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView)); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_OMSetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs_, ID3D11RenderTargetView *const *ppRenderTargetViews, + ID3D11DepthStencilView *pDepthStencilView, + UINT UAVStartSlot_, UINT NumUAVs_, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + const UINT *pUAVInitialCounts) +{ + SERIALISE_ELEMENT(ResourceId, DepthStencilView, GetIDForResource(pDepthStencilView)); + + SERIALISE_ELEMENT(uint32_t, NumRTVs, NumRTVs_); + + SERIALISE_ELEMENT(uint32_t, UAVStartSlot, UAVStartSlot_); + SERIALISE_ELEMENT(uint32_t, NumUAVs, NumUAVs_); + + ID3D11RenderTargetView **RenderTargetViews = NULL; + ID3D11UnorderedAccessView **UnorderedAccessViews = NULL; + + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + { + RenderTargetViews = new ID3D11RenderTargetView *[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + RenderTargetViews[i] = NULL; + } + + if(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) + { + UnorderedAccessViews = new ID3D11UnorderedAccessView *[D3D11_PS_CS_UAV_REGISTER_COUNT]; + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + UnorderedAccessViews[i] = NULL; + } + + SERIALISE_ELEMENT(uint8_t, HasInitialCounts, pUAVInitialCounts != NULL); + + SERIALISE_ELEMENT_ARR_OPT(uint32_t, UAVInitialCounts, pUAVInitialCounts, NumUAVs, HasInitialCounts && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS); + + RDCASSERT(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL || NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS); + + for(UINT i=0; i < NumRTVs && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppRenderTargetViews[i])); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) + RenderTargetViews[i] = (ID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + for(UINT i=0; i < NumUAVs && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppUnorderedAccessViews[i])); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) + UnorderedAccessViews[i] = (ID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + pDepthStencilView = NULL; + if(m_pDevice->GetResourceManager()->HasLiveResource(DepthStencilView)) + pDepthStencilView = (ID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetLiveResource(DepthStencilView); + + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + { + if(m_CurrentPipelineState->ValidOutputMerger(RenderTargetViews, pDepthStencilView)) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RenderTargetViews, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); + } + } + + if(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UnorderedAccessViews, 0, D3D11_PS_CS_UAV_REGISTER_COUNT); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, UAVStartSlot); + } + + for(UINT i=0; i < NumRTVs && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL; i++) + RenderTargetViews[i] = UNWRAP(WrappedID3D11RenderTargetView, RenderTargetViews[i]); + + for(UINT i=0; i < NumUAVs && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS; i++) + UnorderedAccessViews[i] = UNWRAP(WrappedID3D11UnorderedAccessView, UnorderedAccessViews[i]); + + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + pDepthStencilView = UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView); + else + pDepthStencilView = NULL; + + m_pRealContext->OMSetRenderTargetsAndUnorderedAccessViews(NumRTVs, RenderTargetViews, + pDepthStencilView, + UAVStartSlot, NumUAVs, UnorderedAccessViews, UAVInitialCounts); + VerifyState(); + } + + SAFE_DELETE_ARRAY(RenderTargetViews); + SAFE_DELETE_ARRAY(UnorderedAccessViews); + SAFE_DELETE_ARRAY(UAVInitialCounts); + + return true; +} + +void WrappedID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(UINT NumRTVs, ID3D11RenderTargetView *const *ppRenderTargetViews, + ID3D11DepthStencilView *pDepthStencilView, + UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + const UINT *pUAVInitialCounts) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_RTARGET_AND_UAVS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_OMSetRenderTargetsAndUnorderedAccessViews(NumRTVs, ppRenderTargetViews, pDepthStencilView, UAVStartSlot, NumUAVs, ppUnorderedAccessViews, pUAVInitialCounts); + + m_ContextRecord->AddChunk(scope.Get()); + } + + ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; + ID3D11UnorderedAccessView *UAVs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; + + for(UINT i=0; ppRenderTargetViews && i < NumRTVs; i++) + RTs[i] = ppRenderTargetViews[i]; + + for(UINT i=0; ppUnorderedAccessViews && i < NumUAVs; i++) + UAVs[i] = ppUnorderedAccessViews[i]; + + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + { + if(m_CurrentPipelineState->ValidOutputMerger(RTs, pDepthStencilView)) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RTs, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); + } + } + + if(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_PS_CS_UAV_REGISTER_COUNT); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, UAVStartSlot); + } + + for(UINT i=0; ppRenderTargetViews && i < NumRTVs; i++) + { + if(ppRenderTargetViews[i] && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + ppRenderTargetViews[i]->GetResource(&res); + // technically this isn't dirty until the draw call, but let's be conservative + // to avoid having to track "possibly" dirty resources. + // Besides, it's unlikely an application will set an output then not draw to it + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + RTs[i] = UNWRAP(WrappedID3D11RenderTargetView, ppRenderTargetViews[i]); + } + + for(UINT i=0; ppUnorderedAccessViews && i < NumUAVs; i++) + { + if(ppUnorderedAccessViews[i] && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + ppUnorderedAccessViews[i]->GetResource(&res); + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView, ppUnorderedAccessViews[i]); + } + + if(pDepthStencilView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pDepthStencilView->GetResource(&res); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + m_pRealContext->OMSetRenderTargetsAndUnorderedAccessViews(NumRTVs, ppRenderTargetViews ? RTs : NULL, UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView), + UAVStartSlot, NumUAVs, ppUnorderedAccessViews ? UAVs : NULL, pUAVInitialCounts); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_OMSetBlendState(ID3D11BlendState *pBlendState, const FLOAT BlendFactor_[4], UINT SampleMask_) +{ + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(pBlendState)); + + float BlendFactor[4] = {0}; + + if(m_State >= WRITING) + { + if((const FLOAT *)BlendFactor_ == NULL) + { + BlendFactor[0] = BlendFactor[1] = BlendFactor[2] = BlendFactor[3] = 1.0f; + } + else + { + memcpy(BlendFactor, BlendFactor_, sizeof(float)*4); + } + } + + m_pSerialiser->Serialise<4>("BlendFactor", BlendFactor); + + SERIALISE_ELEMENT(uint32_t, SampleMask, SampleMask_); + + if(m_State <= EXECUTING) + { + ID3D11DeviceChild *live = m_pDevice->GetResourceManager()->GetLiveResource(State); + if(WrappedID3D11BlendState1::IsAlloc(live)) + { + ID3D11BlendState1 *state = (ID3D11BlendState1 *)live; + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.BlendState, (ID3D11BlendState *)state); + m_pRealContext->OMSetBlendState((ID3D11BlendState *)UNWRAP(WrappedID3D11BlendState1, state), BlendFactor, SampleMask); + } + else + { + ID3D11BlendState *state = (ID3D11BlendState *)live; + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.BlendState, state); + m_pRealContext->OMSetBlendState(UNWRAP(WrappedID3D11BlendState, state), BlendFactor, SampleMask); + } + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.BlendFactor, BlendFactor, 0, 4); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.SampleMask, SampleMask); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::OMSetBlendState(ID3D11BlendState *pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_BLEND); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_OMSetBlendState(pBlendState, BlendFactor, SampleMask); + + m_ContextRecord->AddChunk(scope.Get()); + } + + FLOAT DefaultBlendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.BlendState, pBlendState); + if(BlendFactor != NULL) + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.BlendFactor, BlendFactor, 0, 4); + else + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.BlendFactor, DefaultBlendFactor, 0, 4); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.SampleMask, SampleMask); + if(!pBlendState || WrappedID3D11BlendState::IsAlloc(pBlendState)) + m_pRealContext->OMSetBlendState(UNWRAP(WrappedID3D11BlendState, pBlendState), BlendFactor, SampleMask); + else + m_pRealContext->OMSetBlendState((ID3D11BlendState *)UNWRAP(WrappedID3D11BlendState1, pBlendState), BlendFactor, SampleMask); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_OMSetDepthStencilState(ID3D11DepthStencilState *pDepthStencilState, UINT StencilRef_) +{ + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(pDepthStencilState)); + SERIALISE_ELEMENT(uint32_t, StencilRef, StencilRef_&0xff); + + if(m_State <= EXECUTING) + { + pDepthStencilState = (ID3D11DepthStencilState *)m_pDevice->GetResourceManager()->GetLiveResource(State); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.DepthStencilState, pDepthStencilState); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.StencRef, StencilRef&0xff); + m_pRealContext->OMSetDepthStencilState(UNWRAP(WrappedID3D11DepthStencilState, pDepthStencilState), StencilRef); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::OMSetDepthStencilState(ID3D11DepthStencilState *pDepthStencilState, UINT StencilRef) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_DEPTHSTENCIL); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_OMSetDepthStencilState(pDepthStencilState, StencilRef); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.DepthStencilState, pDepthStencilState); + m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.StencRef, StencilRef&0xff); + m_pRealContext->OMSetDepthStencilState(UNWRAP(WrappedID3D11DepthStencilState, pDepthStencilState), StencilRef); + VerifyState(); +} + +#pragma endregion Output Merger + +#pragma region Draw + +vector WrappedID3D11DeviceContext::Serialise_DebugMessages() +{ + SCOPED_SERIALISE_CONTEXT(DEBUG_MESSAGES); + + vector debugMessages; + + m_EmptyCommandList = false; + + // only grab debug messages for the immediate context, without serialising all + // API use there's no way to find out which messages come from which context :(. + if(m_State == WRITING_CAPFRAME && GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) + { + debugMessages = m_pDevice->GetDebugMessages(); + } + + SERIALISE_ELEMENT(bool, HasCallstack, RenderDoc::Inst().GetCaptureOptions().CaptureCallstacksOnlyDraws != 0); + + if(HasCallstack) + { + if(m_State >= WRITING) + { + Callstack::Stackwalk *call = Callstack::Collect(); + + RDCASSERT(call->NumLevels() < 0xff); + + size_t numLevels = call->NumLevels(); + uint64_t *stack = call->GetAddrs(); + + m_pSerialiser->Serialise("callstack", stack, numLevels); + + delete call; + } + else + { + size_t numLevels = 0; + uint64_t *stack = NULL; + + m_pSerialiser->Serialise("callstack", stack, numLevels); + + m_pSerialiser->SetCallstack(stack, numLevels); + + SAFE_DELETE_ARRAY(stack); + } + } + + SERIALISE_ELEMENT(uint32_t, NumMessages, (uint32_t)debugMessages.size()); + + for(uint32_t i=0; i < NumMessages; i++) + { + ScopedContext scope(m_pSerialiser, m_pDebugSerialiser, "DebugMessage", "DebugMessage", 0, false); + + string desc = debugMessages[i].description.elems; + + SERIALISE_ELEMENT(uint32_t, Category, debugMessages[i].category); + SERIALISE_ELEMENT(uint32_t, Severity, debugMessages[i].severity); + SERIALISE_ELEMENT(uint32_t, ID, debugMessages[i].messageID); + SERIALISE_ELEMENT(string, Description, desc); + + if(m_State == READING) + { + DebugMessage msg; + msg.category = (DebugMessageCategory)Category; + msg.severity = (DebugMessageSeverity)Severity; + msg.messageID = ID; + msg.description = Description; + + debugMessages.push_back(msg); + } + } + + return debugMessages; +} + + +bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstanced(UINT IndexCountPerInstance_, UINT InstanceCount_, UINT StartIndexLocation_, + INT BaseVertexLocation_, UINT StartInstanceLocation_) +{ + SERIALISE_ELEMENT(uint32_t, IndexCountPerInstance, IndexCountPerInstance_); + SERIALISE_ELEMENT(uint32_t, InstanceCount, InstanceCount_); + SERIALISE_ELEMENT(uint32_t, StartIndexLocation, StartIndexLocation_); + SERIALISE_ELEMENT(int32_t, BaseVertexLocation, BaseVertexLocation_); + SERIALISE_ELEMENT(uint32_t, StartInstanceLocation, StartInstanceLocation_); + + if(m_State <= EXECUTING) + { + m_pRealContext->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW_INDEXED_INST, desc); + string name = "DrawIndexedInstanced(" + ToStr::Get(IndexCountPerInstance) + + ", " + ToStr::Get(InstanceCount) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = IndexCountPerInstance; + draw.numInstances = InstanceCount; + draw.indexOffset = StartIndexLocation; + draw.vertexOffset = BaseVertexLocation; + draw.instanceOffset = StartInstanceLocation; + + draw.flags |= eDraw_Drawcall|eDraw_Instanced|eDraw_UseIBuffer; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DrawIndexedInstanced(UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, + INT BaseVertexLocation, UINT StartInstanceLocation) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_INDEXED_INST); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } +} + +bool WrappedID3D11DeviceContext::Serialise_DrawInstanced(UINT VertexCountPerInstance_, UINT InstanceCount_, UINT StartVertexLocation_, UINT StartInstanceLocation_) +{ + SERIALISE_ELEMENT(uint32_t, VertexCountPerInstance, VertexCountPerInstance_); + SERIALISE_ELEMENT(uint32_t, InstanceCount, InstanceCount_); + SERIALISE_ELEMENT(uint32_t, StartVertexLocation, StartVertexLocation_); + SERIALISE_ELEMENT(uint32_t, StartInstanceLocation, StartInstanceLocation_); + + if(m_State <= EXECUTING) + { + m_pRealContext->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW_INST, desc); + string name = "DrawInstanced(" + ToStr::Get(VertexCountPerInstance) + + ", " + ToStr::Get(InstanceCount) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = VertexCountPerInstance; + draw.numInstances = InstanceCount; + draw.vertexOffset = StartVertexLocation; + draw.instanceOffset = StartInstanceLocation; + + draw.flags |= eDraw_Drawcall|eDraw_Instanced; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DrawInstanced(UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_INST); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } +} + +bool WrappedID3D11DeviceContext::Serialise_DrawIndexed(UINT IndexCount_, UINT StartIndexLocation_, INT BaseVertexLocation_) +{ + SERIALISE_ELEMENT(uint32_t, IndexCount, IndexCount_); + SERIALISE_ELEMENT(uint32_t, StartIndexLocation, StartIndexLocation_); + SERIALISE_ELEMENT(int32_t, BaseVertexLocation, BaseVertexLocation_); + + if(m_State <= EXECUTING) + { + m_pRealContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW_INDEXED, desc); + string name = "DrawIndexed(" + ToStr::Get(IndexCount) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = IndexCount; + draw.vertexOffset = BaseVertexLocation; + draw.indexOffset = StartIndexLocation; + + draw.flags |= eDraw_Drawcall|eDraw_UseIBuffer; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DrawIndexed(UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_SMALL_CONTEXT(DRAW_INDEXED); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } +} + +bool WrappedID3D11DeviceContext::Serialise_Draw(UINT VertexCount_, UINT StartVertexLocation_) +{ + SERIALISE_ELEMENT(uint32_t, VertexCount, VertexCount_); + SERIALISE_ELEMENT(uint32_t, StartVertexLocation, StartVertexLocation_); + + if(m_State <= EXECUTING) + { + m_pRealContext->Draw(VertexCount, StartVertexLocation); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW, desc); + string name = "Draw(" + ToStr::Get(VertexCount) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = VertexCount; + draw.vertexOffset = StartVertexLocation; + + draw.flags |= eDraw_Drawcall; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::Draw(UINT VertexCount, UINT StartVertexLocation) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->Draw(VertexCount, StartVertexLocation); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_Draw(VertexCount, StartVertexLocation); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } +} + +bool WrappedID3D11DeviceContext::Serialise_DrawAuto() +{ + if(m_State <= EXECUTING) + { + m_pRealContext->DrawAuto(); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW_AUTO, desc); + string name = "DrawAuto()"; + + // Not implemented. Need to D3D11_QUERY_SO_STATISTICS to find out the + // index count etc to fill out FetchDrawcall + RDCUNIMPLEMENTED("Not fetching draw data for DrawAuto() display"); + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Drawcall|eDraw_Auto; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DrawAuto() +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DrawAuto(); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_AUTO); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DrawAuto(); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } +} + +bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstancedIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs_) +{ + SERIALISE_ELEMENT(ResourceId, BufferForArgs, GetIDForResource(pBufferForArgs)); + SERIALISE_ELEMENT(uint32_t, AlignedByteOffsetForArgs, AlignedByteOffsetForArgs_); + + if(m_State <= EXECUTING) + { + m_pRealContext->DrawIndexedInstancedIndirect(UNWRAP(WrappedID3D11Buffer, m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs)), AlignedByteOffsetForArgs); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW, desc); + + ID3D11Buffer *argBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs); + + vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 5*sizeof(uint32_t)); + uint32_t *uargs = (uint32_t *)&args[0]; + + string name = "DrawIndexedInstancedIndirect(<" + ToStr::Get(uargs[0]) + + ", " + ToStr::Get(uargs[1]) + ">)"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = uargs[0]; + draw.numInstances = uargs[1]; + draw.indexOffset = uargs[2]; + draw.vertexOffset = uargs[3]; + draw.instanceOffset = uargs[4]; + + draw.flags |= eDraw_Drawcall|eDraw_Instanced|eDraw_UseIBuffer|eDraw_Indirect; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DrawIndexedInstancedIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DrawIndexedInstancedIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_INDEXED_INST_INDIRECT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DrawIndexedInstancedIndirect(pBufferForArgs, AlignedByteOffsetForArgs); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } + + if(pBufferForArgs && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(pBufferForArgs), eFrameRef_Read); +} + +bool WrappedID3D11DeviceContext::Serialise_DrawInstancedIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs_) +{ + SERIALISE_ELEMENT(ResourceId, BufferForArgs, GetIDForResource(pBufferForArgs)); + SERIALISE_ELEMENT(uint32_t, AlignedByteOffsetForArgs, AlignedByteOffsetForArgs_); + + if(m_State <= EXECUTING) + { + m_pRealContext->DrawInstancedIndirect(UNWRAP(WrappedID3D11Buffer, m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs)), AlignedByteOffsetForArgs); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DRAW, desc); + + ID3D11Buffer *argBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs); + + vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 4*sizeof(uint32_t)); + uint32_t *uargs = (uint32_t *)&args[0]; + + string name = "DrawInstancedIndirect(<" + ToStr::Get(uargs[0]) + + ", " + ToStr::Get(uargs[1]) + ">)"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = uargs[0]; + draw.numInstances = uargs[1]; + draw.vertexOffset = uargs[2]; + draw.instanceOffset = uargs[3]; + + draw.flags |= eDraw_Drawcall|eDraw_Instanced|eDraw_Indirect; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DrawInstancedIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DrawInstancedIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_INST_INDIRECT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DrawInstancedIndirect(pBufferForArgs, AlignedByteOffsetForArgs); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } + + if(pBufferForArgs && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(pBufferForArgs), eFrameRef_Read); +} + +#pragma endregion Draw + +#pragma region Compute Shader + +void WrappedID3D11DeviceContext::CSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) +{ + if(ppConstantBuffers) + { + ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; + m_pRealContext->CSGetConstantBuffers(StartSlot, NumBuffers, real); + + for(UINT i=0; i < NumBuffers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppConstantBuffers[i]); + + RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->CS.ConstantBuffers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::CSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) +{ + if(ppShaderResourceViews) + { + ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; + m_pRealContext->CSGetShaderResources(StartSlot, NumViews, real); + + for(UINT i=0; i < NumViews; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppShaderResourceViews[i]); + + RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->CS.SRVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::CSGetUnorderedAccessViews(UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView **ppUnorderedAccessViews) +{ + if(ppUnorderedAccessViews) + { + ID3D11UnorderedAccessView *real[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; + m_pRealContext->CSGetUnorderedAccessViews(StartSlot, NumUAVs, real); + + for(UINT i=0; i < NumUAVs; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppUnorderedAccessViews[i] = (ID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppUnorderedAccessViews[i]); + + RDCASSERT(ppUnorderedAccessViews[i] == m_CurrentPipelineState->CS.UAVs[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::CSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) +{ + if(ppSamplers) + { + ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; + m_pRealContext->CSGetSamplers(StartSlot, NumSamplers, real); + + for(UINT i=0; i < NumSamplers; i++) + { + SAFE_RELEASE_NOCLEAR(real[i]); + ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); + SAFE_ADDREF(ppSamplers[i]); + + RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->CS.Samplers[i+StartSlot]); + } + } +} + +void WrappedID3D11DeviceContext::CSGetShader(ID3D11ComputeShader **ppComputeShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) +{ + if(ppComputeShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) + return; + + ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; + UINT numInsts = 0; + ID3D11ComputeShader *realShader = NULL; + m_pRealContext->CSGetShader(&realShader, realInsts, &numInsts); + + SAFE_RELEASE_NOCLEAR(realShader); + for(UINT i=0; i < numInsts; i++) + SAFE_RELEASE_NOCLEAR(realInsts[i]); + + if(ppComputeShader) + { + *ppComputeShader = (ID3D11ComputeShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); + SAFE_ADDREF(*ppComputeShader); + + RDCASSERT(*ppComputeShader == m_CurrentPipelineState->CS.Shader); + } + + if(ppClassInstances) + { + for(UINT i=0; i < numInsts; i++) + { + ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); + SAFE_ADDREF(ppClassInstances[i]); + + RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->CS.Instances[i]); + } + } + + if(pNumClassInstances) + { + *pNumClassInstances = numInsts; + } +} + +bool WrappedID3D11DeviceContext::Serialise_CSSetConstantBuffers(UINT StartSlot_, UINT NumBuffers_, ID3D11Buffer *const *ppConstantBuffers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumBuffers, NumBuffers_); + + ID3D11Buffer **Buffers = new ID3D11Buffer *[NumBuffers]; + + for(UINT i=0; i < NumBuffers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppConstantBuffers[i])); + + if(m_State <= EXECUTING) + Buffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.ConstantBuffers, Buffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + for(UINT i=0; i < NumBuffers; i++) + Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + + m_pRealContext->CSSetConstantBuffers(StartSlot, NumBuffers, Buffers); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Buffers); + + return true; +} + +void WrappedID3D11DeviceContext::CSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_CS_CBUFFERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBCounts, NullCBCounts, StartSlot, NumBuffers); + + ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + for(UINT i=0; i < NumBuffers; i++) + { + if(ppConstantBuffers[i] && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); + + bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); + } + + m_pRealContext->CSSetConstantBuffers(StartSlot, NumBuffers, bufs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_CSSetShaderResources(UINT StartSlot_, UINT NumViews_, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumViews, NumViews_); + + ID3D11ShaderResourceView **Views = new ID3D11ShaderResourceView *[NumViews]; + + for(UINT i=0; i < NumViews; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppShaderResourceViews[i])); + + if(m_State <= EXECUTING) + Views[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.SRVs, Views, StartSlot, NumViews); + + for(UINT i=0; i < NumViews; i++) + Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + + m_pRealContext->CSSetShaderResources(StartSlot, NumViews, Views); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Views); + + return true; +} + +void WrappedID3D11DeviceContext::CSSetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_CS_RESOURCES); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.SRVs, ppShaderResourceViews, StartSlot, NumViews); + + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumViews; i++) + { + if(ppShaderResourceViews[i] && m_State >= WRITING_CAPFRAME) + { + ID3D11Resource *res = NULL; + ppShaderResourceViews[i]->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + + SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView, ppShaderResourceViews[i]); + } + + m_pRealContext->CSSetShaderResources(StartSlot, NumViews, SRVs); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_CSSetUnorderedAccessViews(UINT StartSlot_, UINT NumUAVs_, + ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, const UINT *pUAVInitialCounts) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumUAVs, NumUAVs_); + SERIALISE_ELEMENT(uint8_t, HasInitialCounts, pUAVInitialCounts != NULL); + SERIALISE_ELEMENT_ARR_OPT(uint32_t, UAVInitialCounts, pUAVInitialCounts, NumUAVs, HasInitialCounts); + + ID3D11UnorderedAccessView **UAVs = new ID3D11UnorderedAccessView *[NumUAVs]; + + for(UINT i=0; i < NumUAVs; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppUnorderedAccessViews[i])); + + UAVs[i] = NULL; + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) + UAVs[i] = (WrappedID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->CS.UAVs, UAVs, StartSlot, NumUAVs); + + for(UINT i=0; i < NumUAVs; i++) + UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView, UAVs[i]); + + m_pRealContext->CSSetUnorderedAccessViews(StartSlot, NumUAVs, UAVs, UAVInitialCounts); + VerifyState(); + } + + SAFE_DELETE_ARRAY(UAVs); + SAFE_DELETE_ARRAY(UAVInitialCounts); + + return true; +} + +void WrappedID3D11DeviceContext::CSSetUnorderedAccessViews(UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + const UINT *pUAVInitialCounts) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_CS_UAVS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CSSetUnorderedAccessViews(StartSlot, NumUAVs, ppUnorderedAccessViews, pUAVInitialCounts); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->CS.UAVs, ppUnorderedAccessViews, StartSlot, NumUAVs); + + ID3D11UnorderedAccessView *UAVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + for(UINT i=0; i < NumUAVs; i++) + { + if(ppUnorderedAccessViews[i] && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + ppUnorderedAccessViews[i]->GetResource(&res); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView, ppUnorderedAccessViews[i]); + } + + m_pRealContext->CSSetUnorderedAccessViews(StartSlot, NumUAVs, UAVs, pUAVInitialCounts); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_CSSetSamplers(UINT StartSlot_, UINT NumSamplers_, ID3D11SamplerState *const *ppSamplers) +{ + SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); + SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); + + ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + + for(UINT i=0; i < NumSamplers; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); + + if(m_State <= EXECUTING) + Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Samplers, Sampler, StartSlot, NumSamplers); + + for(UINT i=0; i < NumSamplers; i++) + Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + + m_pRealContext->CSSetSamplers(StartSlot, NumSamplers, Sampler); + VerifyState(); + } + + SAFE_DELETE_ARRAY(Sampler); + + return true; +} + +void WrappedID3D11DeviceContext::CSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_CS_SAMPLERS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CSSetSamplers(StartSlot, NumSamplers, ppSamplers); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Samplers, ppSamplers, StartSlot, NumSamplers); + + ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + for(UINT i=0; i < NumSamplers; i++) + samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); + + m_pRealContext->CSSetSamplers(StartSlot, NumSamplers, samps); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_CSSetShader(ID3D11ComputeShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances_) +{ + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(pShader)); + SERIALISE_ELEMENT(uint32_t, NumClassInstances, NumClassInstances_); + + ID3D11ClassInstance **Instances = new ID3D11ClassInstance *[NumClassInstances]; + + for(UINT i=0; i < NumClassInstances; i++) + { + SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppClassInstances[i])); + + if(m_State <= EXECUTING) + Instances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetLiveResource(id); + } + + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Instances, Instances, 0, NumClassInstances); + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.NumInstances, NumClassInstances); + + for(UINT i=0; i < NumClassInstances; i++) + Instances[i] = UNWRAP(WrappedID3D11ClassInstance, Instances[i]); + + ID3D11DeviceChild *pShader = (ID3D11DeviceChild *)m_pDevice->GetResourceManager()->GetLiveResource(Shader); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Shader, pShader); + m_pRealContext->CSSetShader(UNWRAP(WrappedID3D11Shader, pShader), Instances, NumClassInstances); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::CSSetShader(ID3D11ComputeShader *pComputeShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_CS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CSSetShader(pComputeShader, ppClassInstances, NumClassInstances); + + MarkResourceReferenced(GetIDForResource(pComputeShader), eFrameRef_Read); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Shader, (ID3D11DeviceChild *)pComputeShader); + m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.NumInstances, NumClassInstances); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Instances, ppClassInstances, 0, NumClassInstances); + + ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; + if(ppClassInstances && NumClassInstances > 0) + for(UINT i=0; i < NumClassInstances; i++) + insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); + + m_pRealContext->CSSetShader(UNWRAP(WrappedID3D11Shader, pComputeShader), insts, NumClassInstances); + VerifyState(); +} + +#pragma endregion Compute Shader + +#pragma region Execute + +bool WrappedID3D11DeviceContext::Serialise_ExecuteCommandList(ID3D11CommandList *pCommandList, BOOL RestoreContextState_) +{ + SERIALISE_ELEMENT(uint8_t, RestoreContextState, RestoreContextState_ == TRUE); + SERIALISE_ELEMENT(ResourceId, cmdList, GetIDForResource(pCommandList)); + + RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE); + + if(m_State <= EXECUTING) + { + if(m_pDevice->GetResourceManager()->HasLiveResource(cmdList)) + m_pRealContext->ExecuteCommandList(UNWRAP(WrappedID3D11CommandList, m_pDevice->GetResourceManager()->GetLiveResource(cmdList)), RestoreContextState); + else + RDCERR("Don't have command list serialised for %llu", cmdList); + + if(!RestoreContextState) + m_CurrentPipelineState->Clear(); + + VerifyState(); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + string name = "ExecuteCommandList(" + ToStr::Get(cmdList) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_CmdList|eDraw_PushMarker; + + draw.debugMessages = debugMessages; + + if(m_CmdLists.find(cmdList) != m_CmdLists.end()) + draw.children = m_CmdLists[cmdList].Bake(); + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::ExecuteCommandList(ID3D11CommandList *pCommandList, BOOL RestoreContextState) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE); + + m_pRealContext->ExecuteCommandList(UNWRAP(WrappedID3D11CommandList, pCommandList), RestoreContextState); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LIST); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ExecuteCommandList(pCommandList, RestoreContextState); + + m_ContextRecord->AddChunk(scope.Get()); + + WrappedID3D11CommandList *wrapped = (WrappedID3D11CommandList *)pCommandList; + + if(!wrapped->IsCaptured()) + { + // we don't have this command list captured. This frame is no longer successful + RDCWARN("Don't have command list %llu captured! This frame is unsuccessful.", wrapped->GetResourceID()); + m_SuccessfulCapture = false; + m_FailureReason = CaptureFailed_UncappedCmdlist; + } + else + { + RDCDEBUG("Executed successful command list %llu", wrapped->GetResourceID()); + ResourceId contextId = wrapped->GetResourceID(); + + D3D11ResourceRecord *cmdListRecord = m_pDevice->GetResourceManager()->GetResourceRecord(contextId); + + if(m_DeferredRecords.find(cmdListRecord) == m_DeferredRecords.end()) + { + m_DeferredRecords.insert(cmdListRecord); + cmdListRecord->AddRef(); + } + + cmdListRecord->AddResourceReferences(m_pDevice->GetResourceManager()); + } + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } + + if(!RestoreContextState) + m_CurrentPipelineState->Clear(); + + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_Dispatch(UINT ThreadGroupCountX_, UINT ThreadGroupCountY_, UINT ThreadGroupCountZ_) +{ + SERIALISE_ELEMENT(uint32_t, ThreadGroupCountX, ThreadGroupCountX_); + SERIALISE_ELEMENT(uint32_t, ThreadGroupCountY, ThreadGroupCountY_); + SERIALISE_ELEMENT(uint32_t, ThreadGroupCountZ, ThreadGroupCountZ_); + + if(m_State <= EXECUTING) + { + m_pRealContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DISPATCH, desc); + string name = "Dispatch(" + + ToStr::Get(ThreadGroupCountX) + ", " + + ToStr::Get(ThreadGroupCountY) + ", " + + ToStr::Get(ThreadGroupCountZ) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Dispatch; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::Dispatch(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DISPATCH); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } +} + +bool WrappedID3D11DeviceContext::Serialise_DispatchIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs_) +{ + SERIALISE_ELEMENT(ResourceId, BufferForArgs, GetIDForResource(pBufferForArgs)); + SERIALISE_ELEMENT(uint32_t, AlignedByteOffsetForArgs, AlignedByteOffsetForArgs_); + + if(m_State <= EXECUTING) + { + m_pRealContext->DispatchIndirect(UNWRAP(WrappedID3D11Buffer, m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs)), AlignedByteOffsetForArgs); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(DISPATCH_INDIRECT, desc); + + ID3D11Buffer *argBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs); + + vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 5*sizeof(uint32_t)); + uint32_t *uargs = (uint32_t *)&args[0]; + + string name = "DispatchIndirect(<" + ToStr::Get(uargs[0]) + + ", " + ToStr::Get(uargs[1]) + + + ", " + ToStr::Get(uargs[2]) + ">)"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Dispatch|eDraw_Indirect; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedID3D11DeviceContext::DispatchIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + m_pRealContext->DispatchIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DISPATCH_INDIRECT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_DispatchIndirect(pBufferForArgs, AlignedByteOffsetForArgs); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } + + if(pBufferForArgs && m_State >= WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(pBufferForArgs), eFrameRef_Read); +} + +bool WrappedID3D11DeviceContext::Serialise_FinishCommandList(BOOL RestoreDeferredContextState_, ID3D11CommandList **ppCommandList) +{ + SERIALISE_ELEMENT(uint8_t, RestoreDeferredContextState, RestoreDeferredContextState_ == TRUE); + SERIALISE_ELEMENT(ResourceId, cmdList, GetIDForResource(*ppCommandList)); + + if(m_State <= EXECUTING && GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + ID3D11CommandList *ret = NULL; + HRESULT hr = m_pRealContext->FinishCommandList(RestoreDeferredContextState, &ret); + + if(!RestoreDeferredContextState) + m_CurrentPipelineState->Clear(); + + VerifyState(); + + if(FAILED(hr)) RDCERR("Failed on finishing command list, HRESULT: 0x%08x", hr); + + RDCASSERT(SUCCEEDED(hr) && ret); + + ret = new WrappedID3D11CommandList(ret, m_pDevice, this, true); + + if(ret) + { + m_pDevice->GetResourceManager()->AddLiveResource(cmdList, ret); + } + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(FINISH_CMD_LIST, desc); + string name = "FinishCommandList() -> " + ToStr::Get(cmdList); + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_CmdList; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + + m_pDevice->GetImmediateContext()->m_CmdLists[cmdList] = m_ParentDrawcall; + m_ParentDrawcall.children.clear(); + } + + return true; +} + +HRESULT WrappedID3D11DeviceContext::FinishCommandList(BOOL RestoreDeferredContextState, ID3D11CommandList **ppCommandList) +{ + DrainAnnotationQueue(); + + ID3D11CommandList *real = NULL; + HRESULT hr = m_pRealContext->FinishCommandList(RestoreDeferredContextState, &real); + + RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED); + + bool cmdListSuccessful = m_SuccessfulCapture; + + if(m_State != WRITING_CAPFRAME && !m_EmptyCommandList) + cmdListSuccessful = false; + + WrappedID3D11CommandList *wrapped = new WrappedID3D11CommandList(real, m_pDevice, this, cmdListSuccessful); + + if(m_State >= WRITING) + { + RDCASSERT(m_pDevice->GetResourceManager()->GetResourceRecord(wrapped->GetResourceID()) == NULL); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->AddResourceRecord(wrapped->GetResourceID()); + record->Length = 0; + record->ignoreSerialise = true; + } + + // if we got here and m_SuccessfulCapture is on, we have captured everything in this command list + if(m_State == WRITING_CAPFRAME && m_SuccessfulCapture) + { + RDCDEBUG("Deferred Context %llu Finish()'d successfully! Got successful command list %llu", GetResourceID(), wrapped->GetResourceID()); + + RDCASSERT(wrapped->IsCaptured()); + + ID3D11CommandList *w = wrapped; + + SCOPED_SERIALISE_CONTEXT(FINISH_CMD_LIST); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_FinishCommandList(RestoreDeferredContextState, &w); + + m_ContextRecord->AddChunk(scope.Get()); + + D3D11ResourceRecord *r = m_pDevice->GetResourceManager()->GetResourceRecord(wrapped->GetResourceID()); + RDCASSERT(r); + + m_ContextRecord->SwapChunks(r); + } + else if(m_State == WRITING_CAPFRAME && !m_SuccessfulCapture) + { + m_SuccessfulCapture = true; + + RDCDEBUG("Deferred Context %llu wasn't successful, but now we've Finish()'d so it is! Produced unsuccessful command list %llu.", + GetResourceID(), wrapped->GetResourceID()); + + RDCASSERT(!wrapped->IsCaptured()); + + // need to clear out anything we had serialised before + m_ContextRecord->LockChunks(); + while(m_ContextRecord->HasChunks()) + { + Chunk *chunk = m_ContextRecord->GetLastChunk(); + SAFE_DELETE(chunk); + m_ContextRecord->PopChunk(); + } + m_ContextRecord->UnlockChunks(); + } + else if(m_State >= WRITING) + { + // mark that this command list is empty so that if we immediately try and capture + // we pick up on that. + m_EmptyCommandList = true; + + RDCDEBUG("Deferred Context %llu not capturing at the moment, Produced unsuccessful command list %llu.", + GetResourceID(), wrapped->GetResourceID()); + } + + if(!RestoreDeferredContextState) + m_CurrentPipelineState->Clear(); + VerifyState(); + + *ppCommandList = wrapped; + + return hr; +} + +bool WrappedID3D11DeviceContext::Serialise_Flush() +{ + if(m_State <= EXECUTING) + { + m_pRealContext->Flush(); + } + + return true; +} + +void WrappedID3D11DeviceContext::Flush() +{ + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(FLUSH); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_Flush(); + + m_ContextRecord->AddChunk(scope.Get()); + + m_CurrentPipelineState->MarkReferenced(this, false); + } + else if(m_State == WRITING_IDLE) + { + m_CurrentPipelineState->MarkDirty(m_pDevice->GetResourceManager()); + } + + m_pRealContext->Flush(); +} + +#pragma endregion Execute + +#pragma region Copy + +bool WrappedID3D11DeviceContext::Serialise_CopySubresourceRegion( ID3D11Resource *pDstResource, UINT DstSubresource, + UINT DstX, UINT DstY, UINT DstZ, + ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox) +{ + SERIALISE_ELEMENT(ResourceId, Destination, GetIDForResource(pDstResource)); + SERIALISE_ELEMENT(uint32_t, DestSubresource, DstSubresource); + SERIALISE_ELEMENT(uint32_t, DestX, DstX); + SERIALISE_ELEMENT(uint32_t, DestY, DstY); + SERIALISE_ELEMENT(uint32_t, DestZ, DstZ); + SERIALISE_ELEMENT(ResourceId, Source, GetIDForResource(pSrcResource)); + SERIALISE_ELEMENT(uint32_t, SourceSubresource, SrcSubresource); + SERIALISE_ELEMENT(uint8_t, HasSourceBox, pSrcBox != NULL); + SERIALISE_ELEMENT_OPT(D3D11_BOX, SourceBox, *pSrcBox, HasSourceBox); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(Destination)) + { + D3D11_BOX *box = &SourceBox; + if(!HasSourceBox) + box = NULL; + + m_pRealContext->CopySubresourceRegion(m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(Destination)), + DestSubresource, DestX, DestY, DestZ, + m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(Source)), + SourceSubresource, box); + } + + return true; +} + +void WrappedID3D11DeviceContext::CopySubresourceRegion( ID3D11Resource *pDstResource, UINT DstSubresource, + UINT DstX, UINT DstY, UINT DstZ, + ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(COPY_SUBRESOURCE_REGION); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, pSrcResource, SrcSubresource, pSrcBox); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); + RDCASSERT(record); + D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); + RDCASSERT(srcRecord); + record->AddParent(srcRecord); + + m_ContextRecord->AddChunk(scope.Get()); + + m_MissingTracks.insert(GetIDForResource(pDstResource)); + // assume partial update + MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Read); + MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Write); + MarkResourceReferenced(GetIDForResource(pSrcResource), eFrameRef_Read); + } + else if(m_State >= WRITING) + { + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); + RDCASSERT(record); + + D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); + RDCASSERT(srcRecord); + + if(m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pSrcResource))) + { + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstResource)); + } + else if(WrappedID3D11Buffer::IsAlloc(pDstResource) && WrappedID3D11Buffer::IsAlloc(pSrcResource)) + { + // perform copy manually (since we have buffer contents locally) + + RDCASSERT(record->DataInSerialiser); + RDCASSERT(srcRecord->DataInSerialiser); + + byte *from = srcRecord->GetDataPtr(); + byte *to = record->GetDataPtr(); + + to += DstX; + + size_t length = record->Length; + + if(pSrcBox) + { + from += pSrcBox->left; + length = pSrcBox->right - pSrcBox->left; + } + + if(length > 0) + { + memcpy(to, from, length); + } + } + else + { + // GPU dirty. Just let initial state handle this. + + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstResource)); + + RDCASSERT( + (WrappedID3D11Texture1D::IsAlloc(pDstResource) && WrappedID3D11Texture1D::IsAlloc(pSrcResource)) || + (WrappedID3D11Texture2D::IsAlloc(pDstResource) && WrappedID3D11Texture2D::IsAlloc(pSrcResource)) || + (WrappedID3D11Texture3D::IsAlloc(pDstResource) && WrappedID3D11Texture3D::IsAlloc(pSrcResource)) + ); + } + } + + m_pRealContext->CopySubresourceRegion(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, DstX, DstY, DstZ, + m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource), SrcSubresource, pSrcBox); +} + +bool WrappedID3D11DeviceContext::Serialise_CopyResource(ID3D11Resource *pDstResource, ID3D11Resource *pSrcResource) +{ + SERIALISE_ELEMENT(ResourceId, Destination, GetIDForResource(pDstResource)); + SERIALISE_ELEMENT(ResourceId, Source, GetIDForResource(pSrcResource)); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(Destination)) + { + m_pRealContext->CopyResource(m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource*)m_pDevice->GetResourceManager()->GetLiveResource(Destination)), + m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource*)m_pDevice->GetResourceManager()->GetLiveResource(Source))); + } + + return true; +} + +void WrappedID3D11DeviceContext::CopyResource(ID3D11Resource *pDstResource, ID3D11Resource *pSrcResource) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(COPY_RESOURCE); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CopyResource(pDstResource, pSrcResource); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); + RDCASSERT(record); + D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); + RDCASSERT(srcRecord); + record->AddParent(srcRecord); + + m_ContextRecord->AddChunk(scope.Get()); + + m_MissingTracks.insert(GetIDForResource(pDstResource)); + MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Write); + MarkResourceReferenced(GetIDForResource(pSrcResource), eFrameRef_Read); + } + else if(m_State >= WRITING) + { + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); + RDCASSERT(record); + + D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); + RDCASSERT(srcRecord); + + if(m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pSrcResource))) + { + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstResource)); + } + else if(WrappedID3D11Buffer::IsAlloc(pDstResource) && WrappedID3D11Buffer::IsAlloc(pSrcResource)) + { + // perform copy manually (since we have buffer contents locally) + + RDCASSERT(record->DataInSerialiser); + RDCASSERT(srcRecord->DataInSerialiser); + + byte *from = srcRecord->GetDataPtr(); + byte *to = record->GetDataPtr(); + + memcpy(to, from, record->Length); + } + else if( + (WrappedID3D11Texture1D::IsAlloc(pDstResource) && WrappedID3D11Texture1D::IsAlloc(pSrcResource)) || + (WrappedID3D11Texture2D::IsAlloc(pDstResource) && WrappedID3D11Texture2D::IsAlloc(pSrcResource)) || + (WrappedID3D11Texture3D::IsAlloc(pDstResource) && WrappedID3D11Texture3D::IsAlloc(pSrcResource)) + ) + { + bool copied = false; + + // can't copy without data allocated + if(!record->DataInSerialiser || !srcRecord->DataInSerialiser) + { + SCOPED_SERIALISE_CONTEXT(COPY_RESOURCE); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CopyResource(pDstResource, pSrcResource); + + record->LockChunks(); + while(true) + { + Chunk *end = record->GetLastChunk(); + + if(end->GetChunkType() == CLEAR_RTV || + end->GetChunkType() == CLEAR_DSV || + end->GetChunkType() == CLEAR_UAV_FLOAT || + end->GetChunkType() == CLEAR_UAV_INT || + end->GetChunkType() == RESOLVE_SUBRESOURCE || + end->GetChunkType() == COPY_RESOURCE) + { + SAFE_DELETE(end); + + record->PopChunk(); + + continue; + } + + break; + } + record->UnlockChunks(); + + record->AddChunk(scope.Get()); + record->AddParent(srcRecord); + } + else + { + RDCASSERT(record->NumSubResources == srcRecord->NumSubResources); + + for(int i=0; i < record->NumSubResources; i++) + { + byte *from = srcRecord->SubResources[i]->GetDataPtr(); + byte *to = record->SubResources[i]->GetDataPtr(); + + memcpy(to, from, record->SubResources[i]->Length); + } + } + } + else + { + RDCERR("Unexpected resource type"); + } + } + + m_pRealContext->CopyResource(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource)); +} + +bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, const D3D11_BOX *pDstBox, + const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) +{ + return Serialise_UpdateSubresource1(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch, 0); +} + +void WrappedID3D11DeviceContext::UpdateSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, const D3D11_BOX *pDstBox, + const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(UPDATE_SUBRESOURCE); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_UpdateSubresource(pDstResource, DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch); + + m_MissingTracks.insert(GetIDForResource(pDstResource)); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + ResourceId idx = GetIDForResource(pDstResource); + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(idx); + RDCASSERT(record); + + // buffers MUST update the whole resource, and don't have any subresources, + // so this effectively becomes just a map/unmap pair. + if(WrappedID3D11Buffer::IsAlloc(pDstResource)) + { + RDCASSERT(record->NumSubResources == 0); + + size_t offs = 0; + size_t length = record->Length; + if(pDstBox) + { + offs += pDstBox->left; + length = RDCMIN((uint32_t)length, pDstBox->right - pDstBox->left); + } + + RDCASSERT(record->DataInSerialiser); + + void *ptr = record->GetDataPtr()+offs; + + memcpy(ptr, pSrcData, length); + } + else if(WrappedID3D11Texture1D::IsAlloc(pDstResource) || + WrappedID3D11Texture2D::IsAlloc(pDstResource) || + WrappedID3D11Texture3D::IsAlloc(pDstResource)) + { + RDCASSERT(record->Length == 1 && record->NumSubResources > 0); + + if(DstSubresource >= (UINT)record->NumSubResources) + { + RDCERR("DstSubresource %u >= %u (num subresources)", DstSubresource, record->NumSubResources); + return; + } + + // this record isn't in the log already, write out a chunk that we can update after. + if(!record->SubResources[DstSubresource]->DataInSerialiser) + { + SCOPED_SERIALISE_CONTEXT(UPDATE_SUBRESOURCE); + m_pSerialiser->Serialise("context", m_ResourceID); + + Serialise_UpdateSubresource(pDstResource, DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch); + + Chunk *chunk = scope.Get(); + + record->AddChunk(chunk); + record->SubResources[DstSubresource]->SetDataPtr(chunk->GetData()); + + record->SubResources[DstSubresource]->DataInSerialiser = true; + } + + { + RDCASSERT(record->SubResources[DstSubresource]->DataInSerialiser); + + void *ptr = record->SubResources[DstSubresource]->GetDataPtr(); + + // if the box is empty, we don't have to do anything! hooray! + if(pDstBox && + (pDstBox->back == pDstBox->front || + pDstBox->left == pDstBox->right || + pDstBox->top == pDstBox->bottom) + ) + { + // empty, do nothing. + } + else + { + WrappedID3D11Texture1D *tex1 = WrappedID3D11Texture1D::IsAlloc(pDstResource) ? (WrappedID3D11Texture1D *)pDstResource : NULL; + WrappedID3D11Texture2D *tex2 = WrappedID3D11Texture2D::IsAlloc(pDstResource) ? (WrappedID3D11Texture2D *)pDstResource : NULL; + WrappedID3D11Texture3D *tex3 = WrappedID3D11Texture3D::IsAlloc(pDstResource) ? (WrappedID3D11Texture3D *)pDstResource : NULL; + + RDCASSERT(tex1 || tex2 || tex3); + + DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN; + UINT subWidth = 1; + UINT subHeight = 1; + UINT subDepth = 1; + + UINT mipLevel = GetMipForSubresource(pDstResource, DstSubresource); + + if(tex1) + { + D3D11_TEXTURE1D_DESC desc = {0}; + tex1->GetDesc(&desc); + fmt = desc.Format; + subWidth = RDCMAX(1U, desc.Width>>mipLevel); + } + else if(tex2) + { + D3D11_TEXTURE2D_DESC desc = {0}; + tex2->GetDesc(&desc); + fmt = desc.Format; + subWidth = RDCMAX(1U, desc.Width>>mipLevel); + subHeight = RDCMAX(1U, desc.Height>>mipLevel); + } + else if(tex3) + { + D3D11_TEXTURE3D_DESC desc = {0}; + tex3->GetDesc(&desc); + fmt = desc.Format; + subWidth = RDCMAX(1U, desc.Width>>mipLevel); + subHeight = RDCMAX(1U, desc.Height>>mipLevel); + subDepth = RDCMAX(1U, desc.Depth>>mipLevel); + } + + UINT boxWidth = pDstBox ? pDstBox->right - pDstBox->left : subWidth; + UINT boxHeight = pDstBox ? pDstBox->bottom - pDstBox->top : subHeight; + UINT boxDepth = pDstBox ? pDstBox->back - pDstBox->front : subDepth; + + UINT boxTop = pDstBox ? pDstBox->top : 0; + + UINT DstRowPitch = GetByteSize(subWidth, 1, 1, fmt, 0); + UINT DstBoxRowPitch = GetByteSize(boxWidth, 1, 1, fmt, 0); + UINT DstSlicePitch = GetByteSize(subWidth, subHeight, 1, fmt, 0); + + // for block formats, rows are in blocks (so height is squished essentially) + if(IsBlockFormat(fmt)) + { + subWidth = AlignUp4(subWidth); + subHeight = AlignUp4(RDCMAX(1U, subHeight/4)); + boxHeight = RDCMAX(1U, boxHeight/4); + boxTop = RDCMAX(0U, boxTop/4); + } + + RDCASSERT(boxWidth <= subWidth && + boxHeight <= subHeight && + boxDepth <= subDepth); + + bool totalUpdate = false; + + // if there is no box, it's a totalUpdate (boxwidth/height are equal by inspection from the initialisation above) + // if the box describes the whole subresource, it's a totalUpdate + if(boxWidth == subWidth && boxHeight == subHeight && boxDepth == subDepth) + totalUpdate = true; + + // fast path for a total update from a source of the same size + if(totalUpdate && + ( + (tex1 && (UINT)record->SubResources[DstSubresource]->Length == SrcRowPitch) || + (tex2 && (UINT)record->SubResources[DstSubresource]->Length == SrcRowPitch*subHeight) || + (tex3 && (UINT)record->SubResources[DstSubresource]->Length == SrcDepthPitch*subDepth) + ) + ) + { + memcpy(ptr, pSrcData, record->SubResources[DstSubresource]->Length); + } + else + { + // need to fall back to copying row by row from the source + byte *dstBuf = (byte *)ptr; + byte *src = (byte *)pSrcData; + + // if we have a box, skip to the front of it + if(pDstBox) + dstBuf += DstSlicePitch*pDstBox->front; + + for(UINT slice=0; slice < boxDepth; slice++) + { + byte *slicedst = dstBuf; + byte *slicesrc = src; + + // if we have a box, skip to the top of it + if(pDstBox) + slicedst += DstRowPitch*boxTop; + + for(UINT row=0; row < boxHeight; row++) + { + byte *rowdst = slicedst; + + // if we have a box, skip to the left of it + if(pDstBox && pDstBox->left > 0) + rowdst += GetByteSize(pDstBox->left, 1, 1, fmt, 0); + + memcpy(rowdst, slicesrc, DstBoxRowPitch); + + slicedst += DstRowPitch; + slicesrc += SrcRowPitch; + } + + dstBuf += DstSlicePitch; + src += SrcDepthPitch; + } + } + } + } + } + } + + m_pRealContext->UpdateSubresource(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch); +} + +bool WrappedID3D11DeviceContext::Serialise_CopyStructureCount(ID3D11Buffer *pDstBuffer, UINT DstAlignedByteOffset, ID3D11UnorderedAccessView *pSrcView) +{ + SERIALISE_ELEMENT(ResourceId, DestBuffer, GetIDForResource(pDstBuffer)); + SERIALISE_ELEMENT(uint32_t, DestAlignedByteOffset, DstAlignedByteOffset); + SERIALISE_ELEMENT(ResourceId, SourceView, GetIDForResource(pSrcView)); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(DestBuffer)) + { + m_pRealContext->CopyStructureCount(UNWRAP(WrappedID3D11Buffer, m_pDevice->GetResourceManager()->GetLiveResource(DestBuffer)), + DestAlignedByteOffset, + UNWRAP(WrappedID3D11UnorderedAccessView, m_pDevice->GetResourceManager()->GetLiveResource(SourceView))); + } + + return true; +} + +void WrappedID3D11DeviceContext::CopyStructureCount(ID3D11Buffer *pDstBuffer, UINT DstAlignedByteOffset, ID3D11UnorderedAccessView *pSrcView) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(COPY_STRUCTURE_COUNT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_CopyStructureCount(pDstBuffer, DstAlignedByteOffset, pSrcView); + + m_ContextRecord->AddChunk(scope.Get()); + + m_MissingTracks.insert(GetIDForResource(pDstBuffer)); + MarkResourceReferenced(GetIDForResource(pDstBuffer), eFrameRef_Read); + MarkResourceReferenced(GetIDForResource(pDstBuffer), eFrameRef_Write); + + ID3D11Resource *res = NULL; + pSrcView->GetResource(&res); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + SAFE_RELEASE(res); + } + else if(m_State >= WRITING) + { + // needs to go into device serialiser + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstBuffer)); + RDCASSERT(record); + + D3D11ResourceRecord *srcRecord = ((WrappedID3D11UnorderedAccessView *)pSrcView)->GetResourceRecord(); + RDCASSERT(srcRecord); + + record->AddParent(srcRecord); + + ID3D11Resource *res = NULL; + pSrcView->GetResource(&res); + + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstBuffer)); + + SAFE_RELEASE(res); + } + + m_pRealContext->CopyStructureCount(UNWRAP(WrappedID3D11Buffer, pDstBuffer), DstAlignedByteOffset, UNWRAP(WrappedID3D11UnorderedAccessView, pSrcView)); +} + +bool WrappedID3D11DeviceContext::Serialise_ResolveSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, + ID3D11Resource *pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format_) +{ + SERIALISE_ELEMENT(ResourceId, DestResource, GetIDForResource(pDstResource)); + SERIALISE_ELEMENT(uint32_t, DestSubresource, DstSubresource); + SERIALISE_ELEMENT(ResourceId, SourceResource, GetIDForResource(pSrcResource)); + SERIALISE_ELEMENT(uint32_t, SourceSubresource, SrcSubresource); + SERIALISE_ELEMENT(DXGI_FORMAT, Format, Format_); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(DestResource)) + { + m_pRealContext->ResolveSubresource(m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource*)m_pDevice->GetResourceManager()->GetLiveResource(DestResource)), + DestSubresource, + m_pDevice->GetResourceManager()->UnwrapResource((ID3D11Resource*)m_pDevice->GetResourceManager()->GetLiveResource(SourceResource)), + SourceSubresource, Format); + } + + return true; +} + +void WrappedID3D11DeviceContext::ResolveSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, + ID3D11Resource *pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(RESOLVE_SUBRESOURCE); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); + + m_ContextRecord->AddChunk(scope.Get()); + + m_MissingTracks.insert(GetIDForResource(pDstResource)); + MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Read); + MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Write); + MarkResourceReferenced(GetIDForResource(pSrcResource), eFrameRef_Read); + } + else if(m_State >= WRITING) + { + // needs to go into device serialiser + + RDCASSERT(WrappedID3D11Texture2D::IsAlloc(pDstResource) && WrappedID3D11Texture2D::IsAlloc(pSrcResource)); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); + RDCASSERT(record); + + D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); + RDCASSERT(srcRecord); + + record->AddParent(srcRecord); + + if(m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pSrcResource))) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pDstResource)); + + SCOPED_SERIALISE_CONTEXT(RESOLVE_SUBRESOURCE); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); + + // resolve subresource only really 'clears' if it's the only subresource. + // This is usually the case for render target textures though. + if(record->NumSubResources == 1) + { + record->LockChunks(); + while(true) + { + Chunk *end = record->GetLastChunk(); + + if(end->GetChunkType() == CLEAR_RTV || + end->GetChunkType() == CLEAR_DSV || + end->GetChunkType() == CLEAR_UAV_FLOAT || + end->GetChunkType() == CLEAR_UAV_INT || + end->GetChunkType() == RESOLVE_SUBRESOURCE || + end->GetChunkType() == COPY_RESOURCE) + { + SAFE_DELETE(end); + + record->PopChunk(); + + continue; + } + + break; + } + record->UnlockChunks(); + } + + record->AddChunk(scope.Get()); + } + + m_pRealContext->ResolveSubresource(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, + m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource), SrcSubresource, Format); +} + +bool WrappedID3D11DeviceContext::Serialise_GenerateMips(ID3D11ShaderResourceView *pShaderResourceView) +{ + SERIALISE_ELEMENT(ResourceId, ShaderResourceView, GetIDForResource(pShaderResourceView)); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(ShaderResourceView)) + { + m_pRealContext->GenerateMips(UNWRAP(WrappedID3D11ShaderResourceView, m_pDevice->GetResourceManager()->GetLiveResource(ShaderResourceView))); + } + + return true; +} + +void WrappedID3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView *pShaderResourceView) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(GENERATE_MIPS); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_GenerateMips(pShaderResourceView); + + m_ContextRecord->AddChunk(scope.Get()); + + ID3D11Resource *res = NULL; + pShaderResourceView->GetResource(&res); + + m_MissingTracks.insert(GetIDForResource(res)); + m_MissingTracks.insert(GetIDForResource(pShaderResourceView)); + + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Read); + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Write); + SAFE_RELEASE(res); + } + else if(m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pShaderResourceView->GetResource(&res); + ResourceId id = GetIDForResource(res); + m_pDevice->GetResourceManager()->MarkDirtyResource(id); + SAFE_RELEASE(res); + } + + m_pRealContext->GenerateMips(UNWRAP(WrappedID3D11ShaderResourceView, pShaderResourceView)); +} + +#pragma endregion Copy + +#pragma region Clear + +bool WrappedID3D11DeviceContext::Serialise_ClearState() +{ + if(m_State <= EXECUTING) + { + m_CurrentPipelineState->Clear(); + m_pRealContext->ClearState(); + VerifyState(); + } + + return true; +} + +void WrappedID3D11DeviceContext::ClearState() +{ + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_STATE); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearState(); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_CurrentPipelineState->Clear(); + m_pRealContext->ClearState(); + VerifyState(); +} + +bool WrappedID3D11DeviceContext::Serialise_ClearRenderTargetView(ID3D11RenderTargetView *pRenderTargetView, const FLOAT ColorRGBA[4]) +{ + SERIALISE_ELEMENT(ResourceId, View, GetIDForResource(pRenderTargetView)); + + float Color[4] = {0}; + + if(m_State >= WRITING) + memcpy(Color, ColorRGBA, sizeof(float)*4); + + m_pSerialiser->Serialise<4>("ColorRGBA", Color); + + if(m_State <= EXECUTING) + { + m_pRealContext->ClearRenderTargetView(UNWRAP(WrappedID3D11RenderTargetView, m_pDevice->GetResourceManager()->GetLiveResource(View)), Color); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(CLEAR_RTV, desc); + string name = "ClearRenderTargetView(" + + ToStr::Get(Color[0]) + ", " + + ToStr::Get(Color[1]) + ", " + + ToStr::Get(Color[2]) + ", " + + ToStr::Get(Color[3]) + + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Clear; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + + m_ResourceUses[((WrappedID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetLiveResource(View))->GetResourceResID()] + .push_back(EventUsage(m_CurEventID, eUsage_Clear)); + } + + return true; +} + +void WrappedID3D11DeviceContext::ClearRenderTargetView(ID3D11RenderTargetView *pRenderTargetView, const FLOAT ColorRGBA[4]) +{ + DrainAnnotationQueue(); + + if(pRenderTargetView == NULL) return; + + m_EmptyCommandList = false; + + m_pRealContext->ClearRenderTargetView(UNWRAP(WrappedID3D11RenderTargetView, pRenderTargetView), ColorRGBA); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_RTV); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearRenderTargetView(pRenderTargetView, ColorRGBA); + + ID3D11Resource *res = NULL; + pRenderTargetView->GetResource(&res); + + m_MissingTracks.insert(GetIDForResource(res)); + m_MissingTracks.insert(GetIDForResource(pRenderTargetView)); + + SAFE_RELEASE(res); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_RTV); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearRenderTargetView(pRenderTargetView, ColorRGBA); + + ID3D11Resource *viewRes = NULL; + pRenderTargetView->GetResource(&viewRes); + ResourceId id = GetIDForResource(viewRes); + SAFE_RELEASE(viewRes); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(id); + RDCASSERT(record); + + record->LockChunks(); + while(true) + { + Chunk *end = record->GetLastChunk(); + + if(end->GetChunkType() == CLEAR_RTV || + end->GetChunkType() == CLEAR_DSV || + end->GetChunkType() == CLEAR_UAV_FLOAT || + end->GetChunkType() == CLEAR_UAV_INT || + end->GetChunkType() == RESOLVE_SUBRESOURCE || + end->GetChunkType() == COPY_RESOURCE) + { + SAFE_DELETE(end); + + record->PopChunk(); + + continue; + } + + break; + } + record->UnlockChunks(); + + record->AddChunk(scope.Get()); + } + + if(pRenderTargetView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pRenderTargetView->GetResource(&res); + + if(m_State == WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Write); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkCleanResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } +} + +bool WrappedID3D11DeviceContext::Serialise_ClearUnorderedAccessViewUint(ID3D11UnorderedAccessView *pUnorderedAccessView, const UINT Values_[4]) +{ + SERIALISE_ELEMENT(ResourceId, View, GetIDForResource(pUnorderedAccessView)); + + UINT Values[4] = {0}; + + if(m_State >= WRITING) + memcpy(Values, Values_, sizeof(UINT)*4); + + m_pSerialiser->Serialise<4>("Values", Values); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(View)) + { + m_pRealContext->ClearUnorderedAccessViewUint(UNWRAP(WrappedID3D11UnorderedAccessView, m_pDevice->GetResourceManager()->GetLiveResource(View)), Values); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + AddEvent(CLEAR_UAV_INT, desc); + string name = "ClearUnorderedAccessViewUint(" + + ToStr::Get(Values[0]) + ", " + + ToStr::Get(Values[1]) + ", " + + ToStr::Get(Values[2]) + ", " + + ToStr::Get(Values[3]) + ", " + + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + + draw.flags |= eDraw_Clear; + + AddDrawcall(draw, true); + + m_ResourceUses[((WrappedID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetLiveResource(View))->GetResourceResID()] + .push_back(EventUsage(m_CurEventID, eUsage_Clear)); + } + + return true; +} + +void WrappedID3D11DeviceContext::ClearUnorderedAccessViewUint(ID3D11UnorderedAccessView *pUnorderedAccessView, const UINT Values[4]) +{ + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_UAV_INT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearUnorderedAccessViewUint(pUnorderedAccessView, Values); + + ID3D11Resource *res = NULL; + pUnorderedAccessView->GetResource(&res); + + m_MissingTracks.insert(GetIDForResource(res)); + m_MissingTracks.insert(GetIDForResource(pUnorderedAccessView)); + + SAFE_RELEASE(res); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_UAV_INT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearUnorderedAccessViewUint(pUnorderedAccessView, Values); + + ID3D11Resource *viewRes = NULL; + pUnorderedAccessView->GetResource(&viewRes); + ResourceId id = GetIDForResource(viewRes); + SAFE_RELEASE(viewRes); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(id); + RDCASSERT(record); + + record->LockChunks(); + while(true) + { + Chunk *end = record->GetLastChunk(); + + if(end->GetChunkType() == CLEAR_RTV || + end->GetChunkType() == CLEAR_DSV || + end->GetChunkType() == CLEAR_UAV_FLOAT || + end->GetChunkType() == CLEAR_UAV_INT || + end->GetChunkType() == RESOLVE_SUBRESOURCE || + end->GetChunkType() == COPY_RESOURCE) + { + SAFE_DELETE(end); + + record->PopChunk(); + + continue; + } + + break; + } + record->UnlockChunks(); + + record->AddChunk(scope.Get()); + } + + if(pUnorderedAccessView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pUnorderedAccessView->GetResource(&res); + + if(m_State == WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Write); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkCleanResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + m_pRealContext->ClearUnorderedAccessViewUint(UNWRAP(WrappedID3D11UnorderedAccessView, pUnorderedAccessView), Values); +} + +bool WrappedID3D11DeviceContext::Serialise_ClearUnorderedAccessViewFloat(ID3D11UnorderedAccessView *pUnorderedAccessView, const FLOAT Values_[4]) +{ + SERIALISE_ELEMENT(ResourceId, View, GetIDForResource(pUnorderedAccessView)); + + FLOAT Values[4] = {0}; + + if(m_State >= WRITING) + memcpy(Values, Values_, sizeof(FLOAT)*4); + + m_pSerialiser->Serialise<4>("Values", Values); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(View)) + { + m_pRealContext->ClearUnorderedAccessViewFloat(UNWRAP(WrappedID3D11UnorderedAccessView, m_pDevice->GetResourceManager()->GetLiveResource(View)), Values); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + AddEvent(CLEAR_UAV_FLOAT, desc); + string name = "ClearUnorderedAccessViewFloat(" + + ToStr::Get(Values[0]) + ", " + + ToStr::Get(Values[1]) + ", " + + ToStr::Get(Values[2]) + ", " + + ToStr::Get(Values[3]) + ", " + + ")"; + + FetchDrawcall draw; + draw.name = (widen(name)); + draw.flags |= eDraw_Clear; + + AddDrawcall(draw, true); + + m_ResourceUses[((WrappedID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetLiveResource(View))->GetResourceResID()] + .push_back(EventUsage(m_CurEventID, eUsage_Clear)); + } + + return true; +} + +void WrappedID3D11DeviceContext::ClearUnorderedAccessViewFloat(ID3D11UnorderedAccessView *pUnorderedAccessView, const FLOAT Values[4]) +{ + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_UAV_FLOAT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearUnorderedAccessViewFloat(pUnorderedAccessView, Values); + + ID3D11Resource *res = NULL; + pUnorderedAccessView->GetResource(&res); + + m_MissingTracks.insert(GetIDForResource(res)); + m_MissingTracks.insert(GetIDForResource(pUnorderedAccessView)); + + SAFE_RELEASE(res); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_UAV_FLOAT); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearUnorderedAccessViewFloat(pUnorderedAccessView, Values); + + ID3D11Resource *viewRes = NULL; + pUnorderedAccessView->GetResource(&viewRes); + ResourceId id = GetIDForResource(viewRes); + SAFE_RELEASE(viewRes); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(id); + RDCASSERT(record); + + record->LockChunks(); + while(true) + { + Chunk *end = record->GetLastChunk(); + + if(end->GetChunkType() == CLEAR_RTV || + end->GetChunkType() == CLEAR_DSV || + end->GetChunkType() == CLEAR_UAV_FLOAT || + end->GetChunkType() == CLEAR_UAV_INT || + end->GetChunkType() == RESOLVE_SUBRESOURCE || + end->GetChunkType() == COPY_RESOURCE) + { + SAFE_DELETE(end); + + record->PopChunk(); + + continue; + } + + break; + } + record->UnlockChunks(); + + record->AddChunk(scope.Get()); + } + + if(pUnorderedAccessView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pUnorderedAccessView->GetResource(&res); + + if(m_State == WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Write); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkCleanResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + + m_pRealContext->ClearUnorderedAccessViewFloat(UNWRAP(WrappedID3D11UnorderedAccessView, pUnorderedAccessView), Values); +} + +bool WrappedID3D11DeviceContext::Serialise_ClearDepthStencilView(ID3D11DepthStencilView *pDepthStencilView, UINT ClearFlags_, FLOAT Depth_, UINT8 Stencil_) +{ + SERIALISE_ELEMENT(ResourceId, View, GetIDForResource(pDepthStencilView)); + SERIALISE_ELEMENT(uint32_t, ClearFlags, ClearFlags_); + SERIALISE_ELEMENT(float, Depth, Depth_); + SERIALISE_ELEMENT(uint8_t, Stencil, Stencil_); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(View)) + { + m_pRealContext->ClearDepthStencilView(UNWRAP(WrappedID3D11DepthStencilView, m_pDevice->GetResourceManager()->GetLiveResource(View)), ClearFlags, Depth, Stencil); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + vector debugMessages = Serialise_DebugMessages(); + + if(m_State == READING) + { + AddEvent(CLEAR_DSV, desc); + string name = "ClearDepthStencilView(" + + ToStr::Get(Depth) + ", " + + ToStr::Get(Stencil) + + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Clear; + + draw.debugMessages = debugMessages; + + AddDrawcall(draw, true); + + m_ResourceUses[((WrappedID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetLiveResource(View))->GetResourceResID()] + .push_back(EventUsage(m_CurEventID, eUsage_Clear)); + } + + return true; +} + +void WrappedID3D11DeviceContext::ClearDepthStencilView(ID3D11DepthStencilView *pDepthStencilView, UINT ClearFlags, FLOAT Depth, UINT8 Stencil) +{ + DrainAnnotationQueue(); + + if(pDepthStencilView == NULL) return; + + m_EmptyCommandList = false; + + m_pRealContext->ClearDepthStencilView(UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView), ClearFlags, Depth, Stencil); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_DSV); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearDepthStencilView(pDepthStencilView, ClearFlags, Depth, Stencil); + + ID3D11Resource *res = NULL; + pDepthStencilView->GetResource(&res); + + m_MissingTracks.insert(GetIDForResource(res)); + m_MissingTracks.insert(GetIDForResource(pDepthStencilView)); + + SAFE_RELEASE(res); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_DSV); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_ClearDepthStencilView(pDepthStencilView, ClearFlags, Depth, Stencil); + + ID3D11Resource *viewRes = NULL; + pDepthStencilView->GetResource(&viewRes); + ResourceId id = GetIDForResource(viewRes); + SAFE_RELEASE(viewRes); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(id); + RDCASSERT(record); + + record->LockChunks(); + while(true) + { + Chunk *end = record->GetLastChunk(); + + if(end->GetChunkType() == CLEAR_RTV || + end->GetChunkType() == CLEAR_DSV || + end->GetChunkType() == CLEAR_UAV_FLOAT || + end->GetChunkType() == CLEAR_UAV_INT || + end->GetChunkType() == RESOLVE_SUBRESOURCE || + end->GetChunkType() == COPY_RESOURCE) + { + SAFE_DELETE(end); + + record->PopChunk(); + + continue; + } + + break; + } + record->UnlockChunks(); + + record->AddChunk(scope.Get()); + } + + if(pDepthStencilView && m_State >= WRITING) + { + ID3D11Resource *res = NULL; + pDepthStencilView->GetResource(&res); + + if(m_State == WRITING_CAPFRAME) + MarkResourceReferenced(GetIDForResource(res), eFrameRef_Write); + + if(m_State == WRITING_IDLE) + m_pDevice->GetResourceManager()->MarkCleanResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } +} + +#pragma endregion Clear + +#pragma region Misc + +bool WrappedID3D11DeviceContext::Serialise_Begin(ID3D11Asynchronous *pAsync) +{ + SERIALISE_ELEMENT(ResourceId, Async, GetIDForResource(pAsync)); + + SERIALISE_ELEMENT(bool, IsQuery, WrappedID3D11Query::IsAlloc(pAsync)); + + if(IsQuery) + { + D3D11_QUERY qt = D3D11_QUERY_EVENT; + + if(m_State >= WRITING) + { + D3D11_QUERY_DESC desc; + ID3D11Query *q = (ID3D11Query *)pAsync; + q->GetDesc(&desc); + + qt = desc.Query; + } + + SERIALISE_ELEMENT(D3D11_QUERY, QueryType, qt); + } + + if(m_State <= EXECUTING) + { + //m_pImmediateContext->Begin((ID3D11Asynchronous *)m_pDevice->GetResourceManager()->GetLiveResource(Async)); + } + + return true; +} + +void WrappedID3D11DeviceContext::Begin(ID3D11Asynchronous *pAsync) +{ + ID3D11Asynchronous *unwrapped = NULL; + + if(WrappedID3D11Query::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Query, pAsync); + else if(WrappedID3D11Predicate::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + else if(WrappedID3D11Counter::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); + else + RDCERR("Unexpected ID3D11Asynchronous"); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(BEGIN); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_Begin(pAsync); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_pRealContext->Begin(unwrapped); +} + +bool WrappedID3D11DeviceContext::Serialise_End(ID3D11Asynchronous *pAsync) +{ + SERIALISE_ELEMENT(ResourceId, Async, GetIDForResource(pAsync)); + + SERIALISE_ELEMENT(bool, IsQuery, WrappedID3D11Query::IsAlloc(pAsync)); + + if(IsQuery) + { + D3D11_QUERY qt = D3D11_QUERY_EVENT; + + if(m_State >= WRITING) + { + D3D11_QUERY_DESC desc; + ID3D11Query *q = (ID3D11Query *)pAsync; + q->GetDesc(&desc); + + qt = desc.Query; + } + + SERIALISE_ELEMENT(D3D11_QUERY, QueryType, qt); + } + + if(m_State <= EXECUTING) + { + //m_pImmediateContext->End((ID3D11Asynchronous *)m_pDevice->GetResourceManager()->GetLiveResource(Async)); + } + + return true; +} + +void WrappedID3D11DeviceContext::End(ID3D11Asynchronous *pAsync) +{ + ID3D11Asynchronous *unwrapped = NULL; + + if(WrappedID3D11Query::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Query, pAsync); + else if(WrappedID3D11Predicate::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + else if(WrappedID3D11Counter::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); + else + RDCERR("Unexpected ID3D11Asynchronous"); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(BEGIN); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_End(pAsync); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_pRealContext->End(unwrapped); +} + +HRESULT WrappedID3D11DeviceContext::GetData(ID3D11Asynchronous *pAsync, void *pData, UINT DataSize, UINT GetDataFlags) +{ + ID3D11Asynchronous *unwrapped = NULL; + + if(WrappedID3D11Query::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Query, pAsync); + else if(WrappedID3D11Predicate::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + else if(WrappedID3D11Counter::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); + else + RDCERR("Unexpected ID3D11Asynchronous"); + + return m_pRealContext->GetData(unwrapped, pData, DataSize, GetDataFlags); +} + +bool WrappedID3D11DeviceContext::Serialise_SetPredication(ID3D11Predicate *pPredicate, BOOL PredicateValue_) +{ + SERIALISE_ELEMENT(ResourceId, Predicate, GetIDForResource(pPredicate)); + SERIALISE_ELEMENT(uint8_t, PredicateValue, PredicateValue_ == TRUE); + + if(m_State <= EXECUTING) + { + m_pRealContext->SetPredication(UNWRAP(WrappedID3D11Predicate, m_pDevice->GetResourceManager()->GetLiveResource(Predicate)), PredicateValue); + } + + return true; +} + +void WrappedID3D11DeviceContext::SetPredication(ID3D11Predicate *pPredicate, BOOL PredicateValue) +{ + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_PREDICATION); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_SetPredication(pPredicate, PredicateValue); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_pRealContext->SetPredication(UNWRAP(WrappedID3D11Predicate, pPredicate), PredicateValue); +} + +FLOAT WrappedID3D11DeviceContext::GetResourceMinLOD(ID3D11Resource *pResource) +{ + return m_pRealContext->GetResourceMinLOD(m_pDevice->GetResourceManager()->UnwrapResource(pResource)); +} + +bool WrappedID3D11DeviceContext::Serialise_SetResourceMinLOD(ID3D11Resource *pResource, FLOAT MinLOD_) +{ + SERIALISE_ELEMENT(ResourceId, Resource, GetIDForResource(pResource)); + SERIALISE_ELEMENT(float, MinLOD, MinLOD_); + + if(m_State <= EXECUTING) + { + m_pRealContext->SetResourceMinLOD((ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(Resource), MinLOD); + } + + return true; +} + +void WrappedID3D11DeviceContext::SetResourceMinLOD(ID3D11Resource *pResource, FLOAT MinLOD) +{ + m_EmptyCommandList = false; + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SET_RESOURCE_MINLOD); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_SetResourceMinLOD(pResource, MinLOD); + + m_ContextRecord->AddChunk(scope.Get()); + } + + m_pRealContext->SetResourceMinLOD(m_pDevice->GetResourceManager()->UnwrapResource(pResource), MinLOD); +} + +void WrappedID3D11DeviceContext::GetPredication(ID3D11Predicate **ppPredicate, BOOL *pPredicateValue) +{ + ID3D11Predicate *real = NULL; + m_pRealContext->GetPredication(&real, pPredicateValue); + SAFE_RELEASE_NOCLEAR(real); + + if(ppPredicate) + { + if(real) + *ppPredicate = UNWRAP(WrappedID3D11Predicate, real); + else + *ppPredicate = NULL; + } +} + +D3D11_DEVICE_CONTEXT_TYPE WrappedID3D11DeviceContext::GetType() +{ + return m_pRealContext->GetType(); +} + +UINT WrappedID3D11DeviceContext::GetContextFlags() +{ + return m_pRealContext->GetContextFlags(); +} + +#pragma endregion Misc + +#pragma region Map + +void MapIntercept::SetAppMemory(void *appMemory) +{ + app.pData = appMemory; +} + +void MapIntercept::SetD3D(D3D11_SUBRESOURCE_DATA d3dData) +{ + D3D11_MAPPED_SUBRESOURCE d3dMap; + d3dMap.pData = (void *)d3dData.pSysMem; + d3dMap.RowPitch = d3dData.SysMemPitch; + d3dMap.DepthPitch = d3dData.SysMemSlicePitch; + + d3d = d3dMap; + + RDCASSERT(d3d.pData); +} + +void MapIntercept::SetD3D(D3D11_MAPPED_SUBRESOURCE d3dMap) +{ + d3d = d3dMap; + + RDCASSERT(d3d.pData); +} + +void MapIntercept::InitWrappedResource(ID3D11Resource *res, UINT sub, void *appMemory) +{ + if(WrappedID3D11Buffer::IsAlloc(res)) + Init((ID3D11Buffer*)res, appMemory); + else if(WrappedID3D11Texture1D::IsAlloc(res)) + Init((ID3D11Texture1D*)res, sub, appMemory); + else if(WrappedID3D11Texture2D::IsAlloc(res)) + Init((ID3D11Texture2D*)res, sub, appMemory); + else if(WrappedID3D11Texture3D::IsAlloc(res)) + Init((ID3D11Texture3D*)res, sub, appMemory); + else + RDCERR("Unexpected resource type"); +} + +void MapIntercept::Init(ID3D11Buffer *buf, void *appMemory) +{ + app.pData = appMemory; + + if(buf == NULL) + return; + + D3D11_BUFFER_DESC desc; + buf->GetDesc(&desc); + + app.RowPitch = app.DepthPitch = desc.ByteWidth; + + if(d3d.RowPitch == 0) + d3d.RowPitch = desc.ByteWidth; + if(d3d.DepthPitch == 0) + d3d.DepthPitch = desc.ByteWidth; +} + +void MapIntercept::Init(ID3D11Texture1D *tex, UINT sub, void *appMemory) +{ + app.pData = appMemory; + + if(tex == NULL) + return; + + D3D11_TEXTURE1D_DESC desc; + tex->GetDesc(&desc); + + int width = desc.Width; + int height = 1; + int depth = 1; + DXGI_FORMAT fmt = desc.Format; + + int mip = GetMipForSubresource(tex, sub); + + // a row in block formats is a row of 4x4 blocks. + if(IsBlockFormat(fmt)) + numRows /= 4; + + numRows = RDCMAX(1, numRows>>mip); + numSlices = RDCMAX(1, numSlices>>mip); + + app.RowPitch = GetByteSize(width, 1, 1, fmt, mip); + app.DepthPitch = GetByteSize(width, height, 1, fmt, mip); + + if(d3d.DepthPitch == 0) + d3d.DepthPitch = app.RowPitch; + if(d3d.DepthPitch == 0) + d3d.DepthPitch = app.DepthPitch; +} + +void MapIntercept::Init(ID3D11Texture2D *tex, UINT sub, void *appMemory) +{ + app.pData = appMemory; + + if(tex == NULL) + return; + + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + + int width = desc.Width; + int height = numRows = desc.Height; + int depth = 1; + DXGI_FORMAT fmt = desc.Format; + + int mip = GetMipForSubresource(tex, sub); + + // a row in block formats is a row of 4x4 blocks. + if(IsBlockFormat(fmt)) + numRows /= 4; + + numRows = RDCMAX(1, numRows>>mip); + numSlices = RDCMAX(1, numSlices>>mip); + + app.RowPitch = GetByteSize(width, 1, 1, fmt, mip); + app.DepthPitch = GetByteSize(width, height, 1, fmt, mip); + + if(d3d.DepthPitch == 0) + d3d.DepthPitch = app.DepthPitch; +} + +void MapIntercept::Init(ID3D11Texture3D *tex, UINT sub, void *appMemory) +{ + app.pData = appMemory; + + if(tex == NULL) + return; + + D3D11_TEXTURE3D_DESC desc; + tex->GetDesc(&desc); + + int width = desc.Width; + int height = numRows = desc.Height; + int depth = numSlices = desc.Depth; + DXGI_FORMAT fmt = desc.Format; + + int mip = GetMipForSubresource(tex, sub); + + // a row in block formats is a row of 4x4 blocks. + if(IsBlockFormat(fmt)) + numRows /= 4; + + numRows = RDCMAX(1, numRows>>mip); + numSlices = RDCMAX(1, numSlices>>mip); + + app.RowPitch = GetByteSize(width, 1, 1, fmt, mip); + app.DepthPitch = GetByteSize(width, height, 1, fmt, mip); +} + +void MapIntercept::CopyFromD3D() +{ + byte *sliceSrc = (byte *)d3d.pData; + byte *sliceDst = (byte *)app.pData; + + RDCASSERT(numSlices > 0 && numRows > 0 && + (numRows == 1 || (app.RowPitch > 0 && d3d.RowPitch > 0)) && + (numSlices == 1 || (app.DepthPitch > 0 && d3d.DepthPitch > 0))); + + for(int slice=0; slice < numSlices; slice++) + { + byte *rowSrc = sliceSrc; + byte *rowDst = sliceDst; + + for(int row=0; row < numRows; row++) + { + memcpy(rowDst, rowSrc, app.RowPitch); + + rowSrc += d3d.RowPitch; + rowDst += app.RowPitch; + } + + sliceSrc += d3d.DepthPitch; + sliceDst += app.DepthPitch; + } +} + +void MapIntercept::CopyToD3D(size_t RangeStart, size_t RangeEnd) +{ + byte *sliceSrc = (byte *)app.pData; + byte *sliceDst = (byte *)d3d.pData + RangeStart; + + RDCASSERT(numSlices > 0 && numRows > 0 && + app.RowPitch > 0 && d3d.RowPitch > 0 && + app.DepthPitch > 0 && d3d.DepthPitch > 0); + + for(int slice=0; slice < numSlices; slice++) + { + byte *rowSrc = sliceSrc; + byte *rowDst = sliceDst; + + for(int row=0; row < numRows; row++) + { + size_t len = app.RowPitch; + + if(RangeEnd > 0) + { + if(rowSrc + len > (byte *)app.pData + (RangeEnd-RangeStart)) + len = (byte *)app.pData + (RangeEnd-RangeStart) - rowSrc; + } + + memcpy(rowDst, rowSrc, len); + + rowSrc += app.RowPitch; + rowDst += d3d.RowPitch; + + if(RangeEnd > 0 && rowSrc > (byte *)app.pData + (RangeEnd-RangeStart)) + return; + } + + sliceSrc += app.DepthPitch; + sliceDst += d3d.DepthPitch; + } +} + +static __m128 zero = {0}; + +// assumes a and b both point to 16-byte aligned 16-byte chunks of memory. +// Returns if they're equal or different +bool Vec16NotEqual(void *a, void *b) +{ + // disabled SSE version as it's acting dodgy +#if 0 + __m128 avec = _mm_load_ps(aflt); + __m128 bvec = _mm_load_ps(bflt); + + __m128 diff = _mm_xor_ps(avec, bvec); + + __m128 eq = _mm_cmpeq_ps(diff, zero); + int mask = _mm_movemask_ps(eq); + int signMask = _mm_movemask_ps(diff); + + // first check ensures that diff is floatequal to zero (ie. avec bitwise equal to bvec). + // HOWEVER -0 is floatequal to 0, so we ensure no sign bits are set on diff + if((mask^0xf) || signMask != 0) + { + return true; + } + + return false; +#elif defined(WIN64) + uint64_t *a64 = (uint64_t *)a; + uint64_t *b64 = (uint64_t *)b; + + return a64[0] != b64[0] || + a64[1] != b64[1]; +#else + uint32_t *a32 = (uint32_t *)a; + uint32_t *b32 = (uint32_t *)b; + + return a32[0] != b32[0] || + a32[1] != b32[1] || + a32[2] != b32[2] || + a32[3] != b32[3]; +#endif +} + +bool FindDiffRange(void *a, void *b, size_t bufSize, size_t &diffStart, size_t &diffEnd) +{ + RDCASSERT(((unsigned long)a)%16 == 0); + RDCASSERT(((unsigned long)b)%16 == 0); + + diffStart = bufSize+1; + diffEnd = 0; + + size_t alignedSize = bufSize&(~0xf); + size_t numVecs = alignedSize/16; + + size_t offs = 0; + + float *aflt = (float *)a; + float *bflt = (float *)b; + + // init a vector to 0 + __m128 zero = {0}; + + // sweep to find the start of differences + for(size_t v=0; v < numVecs; v++) + { + if(Vec16NotEqual(aflt, bflt)) + { + diffStart = offs; + break; + } + + aflt+=4;bflt+=4;offs+=4*sizeof(float); + } + + // make sure we're byte-accurate, to comply with WRITE_NO_OVERWRITE + while(diffStart < bufSize && *((byte *)a + diffStart) == *((byte *)b + diffStart)) diffStart++; + + // do we have some unaligned bytes at the end of the buffer? + if(bufSize > alignedSize) + { + size_t numBytes = alignedSize-bufSize; + + // if we haven't even found a start, check in these bytes + if(diffStart > bufSize) + { + offs = bufSize; + + for(size_t by=0; by < numBytes; by++) + { + if(*((byte *)a + alignedSize + by) != *((byte *)b + alignedSize + by)) + { + diffStart = offs; + break; + } + + offs++; + } + } + + // sweep from the last byte to find the end + for(size_t by=0; by < numBytes; by++) + { + if(*((byte *)a + bufSize-1 - by) != *((byte *)b + bufSize-1 - by)) + { + diffEnd = bufSize-by; + break; + } + } + } + + // if we haven't found a start, or we've found a start AND and end, + // then we're done. + if(diffStart > bufSize || diffEnd > 0) + return diffStart < bufSize; + + offs = alignedSize; + + // sweep from the last __m128 + aflt = (float *)a + offs/sizeof(float) - 4; + bflt = (float *)b + offs/sizeof(float) - 4; + + for(size_t v=0; v < numVecs; v++) + { + if(Vec16NotEqual(aflt, bflt)) + { + diffEnd = offs; + break; + } + + aflt-=4;bflt-=4;offs-=16; + } + + // make sure we're byte-accurate, to comply with WRITE_NO_OVERWRITE + while(diffEnd > 0 && *((byte *)a + diffEnd - 1) == *((byte *)b + diffEnd - 1)) diffEnd--; + + // if we found a start then we necessarily found an end + return diffStart < bufSize; +} + +bool WrappedID3D11DeviceContext::Serialise_Map(ID3D11Resource *pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE *pMappedResource) +{ + D3D11_MAPPED_SUBRESOURCE mappedResource = D3D11_MAPPED_SUBRESOURCE(); + + if(pMappedResource) + mappedResource = *pMappedResource; + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + + // we only serialise out unmap - should never hit this on read. + RDCASSERT(m_State >= WRITING); + + RDCASSERT(record); + + if(record->NumSubResources > (int)Subresource) + record = (D3D11ResourceRecord *)record->SubResources[Subresource]; + + MapIntercept intercept; + + size_t mapLength = record->Length; + + if(m_State == WRITING_CAPFRAME || (record && !record->DataInSerialiser)) + { + ResourceId Resource = GetIDForResource(pResource); + + RDCASSERT(m_OpenMaps.find(MappedResource(Resource, Subresource)) == m_OpenMaps.end()); + + ID3D11Resource *resMap = pResource; + if(m_pDevice->GetResourceManager()->HasLiveResource(Resource)) + resMap = (ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(Resource); + + RDCASSERT(resMap); + + int ctxMapID = 0; + + if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + if(m_MapResourceRecordAllocs[Resource] == 0) + m_MapResourceRecordAllocs[Resource] = record->GetContextID(); + + ctxMapID = m_MapResourceRecordAllocs[Resource]; + + RDCASSERT(ctxMapID != 0); + } + + void *appMem = record->GetShadowPtr(ctxMapID, 0); + + if(appMem == NULL) + { + record->AllocShadowStorage(ctxMapID, mapLength); + appMem = record->GetShadowPtr(ctxMapID, 0); + + if(MapType != D3D11_MAP_WRITE_DISCARD) + { + if(m_pDevice->GetResourceManager()->IsResourceDirty(Resource)) + { + ID3D11DeviceChild *initial = m_pDevice->GetResourceManager()->GetInitialContents(Resource); + + if(WrappedID3D11Buffer::IsAlloc(pResource)) + { + RDCASSERT(initial); + + ID3D11Buffer *stage = (ID3D11Buffer *)initial; + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = m_pRealContext->Map(stage, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map while getting initial states %08x", hr); + } + else + { + MapIntercept intercept; + intercept.SetD3D(mapped); + intercept.Init((ID3D11Buffer *)pResource, record->GetDataPtr()); + intercept.CopyFromD3D(); + + RDCASSERT(mapLength == (size_t)record->Length); + + memcpy(appMem, record->GetDataPtr(), mapLength); + + m_pRealContext->Unmap(stage, 0); + } + } + else + { + RDCUNIMPLEMENTED("Not getting initial contents for non-buffer GPU dirty map"); // need to get initial contents out + RDCERR("CORRUPTION - Invalid/inaccurate initial data for Map() - non-buffer GPU dirty data mapped"); + } + } + else if(record->DataInSerialiser) + { + RDCASSERT(mapLength == (size_t)record->Length); + memcpy(appMem, record->GetDataPtr(), mapLength); + } + else + { + memset(appMem, 0, mapLength); + } + } + + memcpy(record->GetShadowPtr(ctxMapID, 1), appMem, mapLength); + } + + if(MapType == D3D11_MAP_WRITE_DISCARD) + { + memset(appMem, 0xcc, mapLength); + memcpy(record->GetShadowPtr(ctxMapID, 1), appMem, mapLength); + } + + intercept = MapIntercept(); + intercept.SetD3D(mappedResource); + intercept.InitWrappedResource(resMap, Subresource, appMem); + intercept.MapType = MapType; + intercept.MapFlags = MapFlags; + + RDCASSERT(pMappedResource); + *pMappedResource = intercept.app; + + m_OpenMaps[MappedResource(Resource, Subresource)] = intercept; + } + else if(m_State == WRITING_IDLE) + { + RDCASSERT(record->DataInSerialiser); + + mapLength = record->Length; + + intercept = MapIntercept(); + intercept.SetD3D(mappedResource); + intercept.InitWrappedResource(pResource, Subresource, record->GetDataPtr()); + intercept.MapType = MapType; + intercept.MapFlags = MapFlags; + + *pMappedResource = intercept.app; + + m_OpenMaps[MappedResource(GetIDForResource(pResource), Subresource)] = intercept; + } + else + { + RDCERR("Unexpected and unhandled case"); + RDCEraseEl(intercept); + } + + // for read write fill out the buffer with what's on the mapped resource already + if(MapType == D3D11_MAP_READ_WRITE || MapType == D3D11_MAP_READ) + { + intercept.CopyFromD3D(); + } + else if(MapType == D3D11_MAP_WRITE_DISCARD) + { + // the easy case! + } + else if(MapType == D3D11_MAP_WRITE || MapType == D3D11_MAP_WRITE_NO_OVERWRITE) + { + // For now we'll just assume that the buffer contents are perfectly accurate + // (which they are if no gpu writes to the buffer happens). + + // could take the performance hit and just copy anyway, spec doesn't see if the + // data will be invalid but it will certainly be slow. + } + + return true; +} + +HRESULT WrappedID3D11DeviceContext::Map(ID3D11Resource *pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE *pMappedResource) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + bool straightUp = false; + if(m_HighTrafficResources.find(pResource) != m_HighTrafficResources.end() && m_State != WRITING_CAPFRAME) + straightUp = true; + + if(m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pResource)) && m_State != WRITING_CAPFRAME) + straightUp = true; + + if((!straightUp && MapType == D3D11_MAP_WRITE_NO_OVERWRITE && m_State != WRITING_CAPFRAME) || + m_pRealContext->GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + straightUp = true; + m_HighTrafficResources.insert(pResource); + if(m_State != WRITING_CAPFRAME) + m_pDevice->GetResourceManager()->MarkDirtyResource(GetIDForResource(pResource)); + } + + if(straightUp && m_State == WRITING_IDLE) + { + return m_pRealContext->Map(m_pDevice->GetResourceManager()->UnwrapResource(pResource), Subresource, + MapType, MapFlags, pMappedResource); + } + + // can't promise no-overwrite as we're going to blat the whole buffer! + HRESULT ret = m_pRealContext->Map(m_pDevice->GetResourceManager()->UnwrapResource(pResource), Subresource, + MapType == D3D11_MAP_WRITE_NO_OVERWRITE ? D3D11_MAP_WRITE_DISCARD : MapType, + MapFlags, pMappedResource); + + if(SUCCEEDED(ret)) + { + if(m_State == WRITING_CAPFRAME) + { + if(MapType == D3D11_MAP_READ) + { + MapIntercept intercept; + intercept.MapType = MapType; + intercept.MapFlags = MapFlags; + + m_OpenMaps[MappedResource(GetIDForResource(pResource), Subresource)] = intercept; + } + else + { + m_MissingTracks.insert(GetIDForResource(pResource)); + + Serialise_Map(pResource, Subresource, MapType, MapFlags, pMappedResource); + } + } + else if(m_State >= WRITING) + { + RDCASSERT(WrappedID3D11Buffer::IsAlloc(pResource) || + WrappedID3D11Texture1D::IsAlloc(pResource) || + WrappedID3D11Texture2D::IsAlloc(pResource) || + WrappedID3D11Texture3D::IsAlloc(pResource)); + + ResourceId Id = GetIDForResource(pResource); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(Id); + RDCASSERT(record); + + D3D11ResourceRecord *parent = record; + + if(record->NumSubResources > (int)Subresource) + record = (D3D11ResourceRecord *)record->SubResources[Subresource]; + + record->UpdateCount++; + + if(record->UpdateCount > 60) + { + m_HighTrafficResources.insert(pResource); + m_pDevice->GetResourceManager()->MarkDirtyResource(Id); + + return ret; + } + + Serialise_Map(pResource, Subresource, MapType, MapFlags, pMappedResource); + } + } + + return ret; +} + +bool WrappedID3D11DeviceContext::Serialise_Unmap(ID3D11Resource *pResource, UINT Subresource_) +{ + MappedResource mapIdx; + + D3D11ResourceRecord *record = NULL; + + if(m_State >= WRITING) + { + record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + RDCASSERT(record); + + if(record->NumSubResources > (int)Subresource_) + record = (D3D11ResourceRecord *)record->SubResources[Subresource_]; + } + + if(m_State < WRITING || m_State == WRITING_CAPFRAME || !record->DataInSerialiser) + { + SERIALISE_ELEMENT(ResourceId, Resource, GetIDForResource(pResource)); + SERIALISE_ELEMENT(uint32_t, Subresource, Subresource_); + + mapIdx = MappedResource(Resource, Subresource); + } + else if(m_State == WRITING_IDLE) + { + mapIdx = MappedResource(GetIDForResource(pResource), Subresource_); + } + + MapIntercept intercept; + + if(m_State >= WRITING) + { + auto it = m_OpenMaps.find(mapIdx); + + RDCASSERT(it != m_OpenMaps.end()); + + intercept = it->second; + + m_OpenMaps.erase(it); + } + + if(m_State < WRITING || m_State == WRITING_CAPFRAME) + { + size_t len = record ? record->Length : 0; + + byte *appWritePtr = NULL; + + appWritePtr = (byte *)intercept.app.pData; + + size_t diffStart = 0; + size_t diffEnd = len; + + int ctxMapID = 0; + + if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED && m_State == WRITING_CAPFRAME) + { + ctxMapID = m_MapResourceRecordAllocs[mapIdx.resource]; + + RDCASSERT(ctxMapID != 0); + } + + if(m_State == WRITING_CAPFRAME && len > 512 && intercept.MapType != D3D11_MAP_WRITE_DISCARD) + { + bool found = FindDiffRange(appWritePtr, record->GetShadowPtr(ctxMapID, 1), len, diffStart, diffEnd); + if(found) + { + static size_t saved = 0; + + saved += len - (diffEnd-diffStart); + + RDCDEBUG("Mapped resource size %u, difference: %u -> %u. Total bytes saved so far: %u", + (uint32_t)len, (uint32_t)diffStart, (uint32_t)diffEnd, (uint32_t)saved); + + len = diffEnd-diffStart; + } + else + { + diffStart = 0; + diffEnd = 0; + + len = 1; + } + } + + appWritePtr += diffStart; + if(m_State == WRITING_CAPFRAME && record->GetShadowPtr(ctxMapID, 1)) + { + memcpy(record->GetShadowPtr(ctxMapID, 1)+diffStart, appWritePtr, diffEnd-diffStart); + } + + SERIALISE_ELEMENT(D3D11_MAP, MapType, intercept.MapType); + SERIALISE_ELEMENT(uint32_t, MapFlags, intercept.MapFlags); + + SERIALISE_ELEMENT(uint32_t, DiffStart, (uint32_t)diffStart); + SERIALISE_ELEMENT(uint32_t, DiffEnd, (uint32_t)diffEnd); + + m_pSerialiser->SerialiseBuffer("MapData", appWritePtr, len); + + if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(mapIdx.resource)) + { + intercept.app.pData = appWritePtr; + + ID3D11Resource *res = (ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(mapIdx.resource); + + if(DiffStart >= DiffEnd) + { + // do nothing + } + else if(MapType == D3D11_MAP_WRITE_NO_OVERWRITE) + { + RDCASSERT(WrappedID3D11Buffer::IsAlloc(res)); + ID3D11Buffer *mapContents = NULL; + + D3D11_BUFFER_DESC bdesc; + bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bdesc.ByteWidth = DiffEnd-DiffStart; + bdesc.CPUAccessFlags = 0; + bdesc.MiscFlags = 0; + bdesc.StructureByteStride = 0; + bdesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = appWritePtr; + data.SysMemPitch = bdesc.ByteWidth; + data.SysMemSlicePitch = bdesc.ByteWidth; + + HRESULT hr = m_pDevice->GetReal()->CreateBuffer(&bdesc, &data, &mapContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create temp Unmap() buffer %08x", hr); + } + else + { + m_pRealContext->CopySubresourceRegion(m_pDevice->GetResourceManager()->UnwrapResource(res), mapIdx.subresource, + DiffStart, 0, 0, + mapContents, 0, NULL); + + SAFE_RELEASE(mapContents); + } + } + else + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + + HRESULT hr = m_pRealContext->Map(m_pDevice->GetResourceManager()->UnwrapResource(res), mapIdx.subresource, + MapType, MapFlags, &mappedResource); + + RDCASSERT(mappedResource.pData); + + if(FAILED(hr)) + { + RDCERR("Failed to map resource, HRESULT: 0x%08x", hr); + } + else + { + intercept.SetD3D(mappedResource); + intercept.InitWrappedResource(res, mapIdx.subresource, appWritePtr); + + intercept.CopyToD3D(DiffStart, DiffEnd); + + m_pRealContext->Unmap(m_pDevice->GetResourceManager()->UnwrapResource(res), mapIdx.subresource); + } + } + + SAFE_DELETE_ARRAY(appWritePtr); + } + else if(m_State == WRITING_CAPFRAME) + { + intercept.CopyToD3D(); + } + } + else if(m_State == WRITING_IDLE) + { + size_t len = record->Length; + + intercept.CopyToD3D(); + + if(!record->DataInSerialiser) + { + uint32_t diffStart = 0; + uint32_t diffEnd = (uint32_t)len; + + m_pSerialiser->Serialise("MapType", intercept.MapType); + m_pSerialiser->Serialise("MapFlags", intercept.MapFlags); + + m_pSerialiser->Serialise("DiffStart", diffStart); + m_pSerialiser->Serialise("DiffEnd", diffEnd); + + byte *buf = (byte *)intercept.app.pData; + m_pSerialiser->SerialiseBuffer("MapData", buf, len); + + intercept.app.pData = buf; + + record->DataInSerialiser = true; + record->SetDataOffset(m_pSerialiser->GetOffset()-record->Length); + + if(m_State < WRITING) + SAFE_DELETE_ARRAY(buf); + } + } + + return true; +} + +void WrappedID3D11DeviceContext::Unmap(ID3D11Resource *pResource, UINT Subresource) +{ + DrainAnnotationQueue(); + + m_EmptyCommandList = false; + + auto it = m_OpenMaps.find(MappedResource(GetIDForResource(pResource), Subresource)); + + if(m_State == WRITING_IDLE && m_HighTrafficResources.find(pResource) != m_HighTrafficResources.end()) + { + // we intercepted this, even though we now don't need to serialise it. Time to finish what we started! + if(it != m_OpenMaps.end() && it->second.MapType != D3D11_MAP_READ) + { + it->second.CopyToD3D(); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(it->first.resource); + if(record) record->FreeShadowStorage(); + + m_OpenMaps.erase(it); + } + else if(it != m_OpenMaps.end()) + { + m_OpenMaps.erase(it); + } + } + else if(m_State >= WRITING) + { + if(it == m_OpenMaps.end() && m_State == WRITING_CAPFRAME) + { + RDCWARN("Saw an Unmap that we didn't capture the corresponding Map for - this frame is unsuccessful"); + m_SuccessfulCapture = false; + m_FailureReason = CaptureFailed_UncappedUnmap; + } + + if(it != m_OpenMaps.end()) + { + if(it->second.MapType == D3D11_MAP_READ) + { + m_OpenMaps.erase(it); + } + else if(m_State == WRITING_CAPFRAME) + { + MarkResourceReferenced(it->first.resource, eFrameRef_Read); + MarkResourceReferenced(it->first.resource, eFrameRef_Write); + + SCOPED_SERIALISE_CONTEXT(UNMAP); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_Unmap(pResource, Subresource); + + m_ContextRecord->AddChunk(scope.Get()); + } + else if(m_State >= WRITING) + { + RDCASSERT(WrappedID3D11Buffer::IsAlloc(pResource) || + WrappedID3D11Texture1D::IsAlloc(pResource) || + WrappedID3D11Texture2D::IsAlloc(pResource) || + WrappedID3D11Texture3D::IsAlloc(pResource)); + + D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + RDCASSERT(record); + + D3D11ResourceRecord *parent = record; + + if(record->NumSubResources > (int)Subresource) + record = (D3D11ResourceRecord *)record->SubResources[Subresource]; + + if(record->DataInSerialiser) + { + Serialise_Unmap(pResource, Subresource); + } + else + { + SCOPED_SERIALISE_CONTEXT(UNMAP); + m_pSerialiser->Serialise("context", m_ResourceID); + Serialise_Unmap(pResource, Subresource); + + Chunk *chunk = scope.Get(); + + record->AddChunk(chunk); + record->SetDataPtr(chunk->GetData()); + + record->DataInSerialiser = true; + } + } + } + } + + m_pRealContext->Unmap(m_pDevice->GetResourceManager()->UnwrapResource(pResource), Subresource); +} + +#pragma endregion Map + diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp new file mode 100644 index 0000000000..495a85e72c --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -0,0 +1,4699 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "d3d11_manager.h" +#include "d3d11_context.h" +#include "d3d11_debug.h" +#include "shaders/dxbc_debug.h" +#include "maths/matrix.h" +#include "maths/camera.h" +#include "data/resource.h" +#include "common/string_utils.h" + +#include "driver/d3d11/d3d11_resources.h" + +#include "d3d11_renderstate.h" + +#include + +// used for serialising out ms textures - converts typeless to uint typed where possible, +// or float/unorm if necessary. Only typeless formats are converted. +DXGI_FORMAT GetTypedFormatUIntPreferred(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + return DXGI_FORMAT_R32G32B32A32_UINT; + case DXGI_FORMAT_R32G32B32_TYPELESS: + return DXGI_FORMAT_R32G32B32_UINT; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + return DXGI_FORMAT_R16G16B16A16_UINT; + case DXGI_FORMAT_R32G32_TYPELESS: + return DXGI_FORMAT_R32G32_UINT; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + return DXGI_FORMAT_R10G10B10A2_UINT; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + return DXGI_FORMAT_R8G8B8A8_UINT; + case DXGI_FORMAT_R16G16_TYPELESS: + return DXGI_FORMAT_R16G16_UINT; + case DXGI_FORMAT_R32_TYPELESS: + return DXGI_FORMAT_R32_UINT; + case DXGI_FORMAT_R8G8_TYPELESS: + return DXGI_FORMAT_R8G8_UINT; + case DXGI_FORMAT_R16_TYPELESS: + return DXGI_FORMAT_R16_UINT; + case DXGI_FORMAT_R8_TYPELESS: + return DXGI_FORMAT_R8_UINT; + case DXGI_FORMAT_BC1_TYPELESS: + return DXGI_FORMAT_BC1_UNORM; + case DXGI_FORMAT_BC2_TYPELESS: + return DXGI_FORMAT_BC2_UNORM; + case DXGI_FORMAT_BC3_TYPELESS: + return DXGI_FORMAT_BC3_UNORM; + case DXGI_FORMAT_BC4_TYPELESS: + return DXGI_FORMAT_BC4_UNORM; + case DXGI_FORMAT_BC5_TYPELESS: + return DXGI_FORMAT_BC5_UNORM; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + case DXGI_FORMAT_BC6H_TYPELESS: + return DXGI_FORMAT_BC6H_UF16; + case DXGI_FORMAT_BC7_TYPELESS: + return DXGI_FORMAT_BC7_UNORM; + + default: + break; + } + + return f; +} + +D3D11DebugManager::D3D11DebugManager(WrappedID3D11Device *wrapper) +{ + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(D3D11DebugManager)); + + m_pDevice = wrapper->GetReal(); + m_pDevice->GetImmediateContext(&m_pImmediateContext); + m_ResourceManager = wrapper->GetResourceManager(); + + m_OutputWindowID = 1; + + m_WrappedDevice = wrapper; + ID3D11DeviceContext *ctx = NULL; + m_WrappedDevice->GetImmediateContext(&ctx); + m_WrappedDevice->InternalRef(); + m_WrappedContext = (WrappedID3D11DeviceContext *)ctx; + + RenderDoc::Inst().SetProgress(DebugManagerInit, 0.0f); + + m_pFactory = NULL; + + HRESULT hr = S_OK; + + IDXGIDevice *pDXGIDevice; + hr = m_WrappedDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice); + + if(FAILED(hr)) + { + RDCERR("Couldn't get DXGI device from D3D device"); + } + else + { + IDXGIAdapter *pDXGIAdapter; + hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter); + + if(FAILED(hr)) + { + RDCERR("Couldn't get DXGI adapter from DXGI device"); + SAFE_RELEASE(pDXGIDevice); + } + else + { + hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&m_pFactory); + + SAFE_RELEASE(pDXGIDevice); + SAFE_RELEASE(pDXGIAdapter); + + if(FAILED(hr)) + { + RDCERR("Couldn't get DXGI factory from DXGI adapter"); + } + } + } + + wstring shadercache = FileIO::GetAppFolderFilename(L"shaders.cache"); + + m_ShaderCacheDirty = true; + + FILE *f = FileIO::fopen(shadercache.c_str(), L"rb"); + if(f) + { + FileIO::fseek64(f, 0, SEEK_END); + uint64_t cachelen = FileIO::ftell64(f); + FileIO::fseek64(f, 0, SEEK_SET); + + if(cachelen < 8) + { + RDCERR("Invalid shader cache"); + m_ShaderCacheDirty = true; + } + else + { + byte *cache = new byte[(size_t)cachelen]; + FileIO::fread(cache, 1, (size_t)cachelen, f); + + uint32_t *header = (uint32_t *)cache; + + uint32_t version = header[0]; + + if(version != m_ShaderCacheVersion) + { + RDCDEBUG("Out of date or invalid shader cache version: %d", version); + m_ShaderCacheDirty = true; + } + else + { + uint32_t numentries = header[1]; + + byte *ptr = cache+sizeof(uint32_t)*2; + + int64_t bufsize = (int64_t)cachelen-sizeof(uint32_t)*2; + + HMODULE d3dcompiler = GetD3DCompiler(); + + if(d3dcompiler == NULL) + { + RDCFATAL("Can't get handle to d3dcompiler_??.dll"); + } + + typedef HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T Size, ID3DBlob** ppBlob); + + pD3DCreateBlob blobCreate = (pD3DCreateBlob)GetProcAddress(d3dcompiler, "D3DCreateBlob"); + + if(blobCreate == NULL) + { + RDCFATAL("Can't get D3DCreateBlob from d3dcompiler_??.dll"); + } + + m_ShaderCacheDirty = false; + + for(uint32_t i=0; i < numentries; i++) + { + if(bufsize < sizeof(uint32_t)) + { + RDCERR("Invalid shader cache"); + m_ShaderCacheDirty = true; + break; + } + + uint32_t hash = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t); + + if(bufsize < sizeof(uint32_t)) + { + RDCERR("Invalid shader cache"); + m_ShaderCacheDirty = true; + break; + } + + uint32_t len = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t); + + if(bufsize < len) + { + RDCERR("Invalid shader cache"); + m_ShaderCacheDirty = true; + break; + } + + byte *data = ptr; ptr += len; bufsize -= len; + + ID3DBlob *blob = NULL; + HRESULT hr = blobCreate((SIZE_T)len, &blob); + + if(FAILED(hr)) + { + RDCERR("Couldn't create blob of size %d from shadercache: %08x", len, hr); + m_ShaderCacheDirty = true; + } + + memcpy(blob->GetBufferPointer(), data, len); + + m_ShaderCache[hash] = blob; + } + + if(bufsize != 0) + { + RDCERR("Invalid shader cache"); + m_ShaderCacheDirty = true; + } + + RDCDEBUG("Successfully loaded %d shaders from shader cache", m_ShaderCache.size()); + } + + delete[] cache; + } + + fclose(f); + } + + m_CacheShaders = true; + + InitStreamOut(); + InitDebugRendering(); + InitFontRendering(); + + m_CacheShaders = false; + + RenderDoc::Inst().SetProgress(DebugManagerInit, 1.0f); +} + +D3D11DebugManager::~D3D11DebugManager() +{ + if(m_ShaderCacheDirty) + { + wstring shadercache = FileIO::GetAppFolderFilename(L"shaders.cache"); + + FILE *f = FileIO::fopen(shadercache.c_str(), L"wb"); + if(f) + { + uint32_t version = m_ShaderCacheVersion; + FileIO::fwrite(&version, 1, sizeof(version), f); + uint32_t numentries = (uint32_t)m_ShaderCache.size(); + FileIO::fwrite(&numentries, 1, sizeof(numentries), f); + + auto it = m_ShaderCache.begin(); + for(uint32_t i=0; i < numentries; i++) + { + uint32_t hash = it->first; + uint32_t len = (uint32_t)it->second->GetBufferSize(); + FileIO::fwrite(&hash, 1, sizeof(hash), f); + FileIO::fwrite(&len, 1, sizeof(len), f); + FileIO::fwrite(it->second->GetBufferPointer(), 1, len, f); + + it->second->Release(); + ++it; + } + + RDCDEBUG("Successfully wrote %d shaders to shader cache", m_ShaderCache.size()); + + fclose(f); + } + else + { + RDCERR("Error opening shader cache for write"); + } + } + + ShutdownFontRendering(); + ShutdownStreamOut(); + + if(m_OverlayResourceId != ResourceId()) + SAFE_RELEASE(m_OverlayRenderTex); + + SAFE_RELEASE(m_CustomShaderRTV); + + if(m_CustomShaderResourceId != ResourceId()) + SAFE_RELEASE(m_CustomShaderTex); + + SAFE_RELEASE(m_pFactory); + + while(!m_ShaderItemCache.empty()) + { + CacheElem &elem = m_ShaderItemCache.back(); + elem.Release(); + m_ShaderItemCache.pop_back(); + } + + for(auto it=m_PostVSData.begin(); it != m_PostVSData.end(); ++it) + { + SAFE_RELEASE(it->second.vsout.buf); + SAFE_RELEASE(it->second.gsout.buf); + } + + m_PostVSData.clear(); + + SAFE_RELEASE(m_WrappedContext); + m_WrappedDevice->InternalRelease(); + SAFE_RELEASE(m_pImmediateContext); + + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); +} + +////////////////////////////////////////////////////// +// debug/replay functions + +static uint32_t strhash(const char *str, uint32_t seed = 5381) +{ + if(str == NULL) return seed; + + uint32_t hash = seed; + int c = *str; + str++; + + while(c) + { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + c = *str; + str++; + } + + return hash; +} + +string D3D11DebugManager::GetShaderBlob(const char *source, const char *entry, const uint32_t compileFlags, const char *profile, ID3DBlob **srcblob) +{ + uint32_t hash = strhash(source); + hash = strhash(entry, hash); + hash = strhash(profile, hash); + hash ^= compileFlags; + + if(m_ShaderCache.find(hash) != m_ShaderCache.end()) + { + *srcblob = m_ShaderCache[hash]; + (*srcblob)->AddRef(); + return ""; + } + + HRESULT hr = S_OK; + + ID3DBlob *byteBlob = NULL; + ID3DBlob *errBlob = NULL; + + HMODULE d3dcompiler = GetD3DCompiler(); + + if(d3dcompiler == NULL) + { + RDCFATAL("Can't get handle to d3dcompiler_??.dll"); + } + + pD3DCompile compileFunc = (pD3DCompile)GetProcAddress(d3dcompiler, "D3DCompile"); + + if(compileFunc == NULL) + { + RDCFATAL("Can't get D3DCompile from d3dcompiler_??.dll"); + } + + uint32_t flags = compileFlags & ~D3DCOMPILE_NO_PRESHADER; + + hr = compileFunc(source, strlen(source), entry, NULL, NULL, entry, profile, + flags, 0, &byteBlob, &errBlob); + + string errors = ""; + + if(errBlob) + { + errors = (char *)errBlob->GetBufferPointer(); + + string logerror = errors; + if(logerror.length() > 1024) + logerror = logerror.substr(0, 1024) + "..."; + + RDCWARN("Shader compile error in '%hs':\n%hs", entry, logerror.c_str()); + + SAFE_RELEASE(errBlob); + + if(FAILED(hr)) + { + SAFE_RELEASE(byteBlob); + return errors; + } + } + + void *bytecode = byteBlob->GetBufferPointer(); + size_t bytecodeLen = byteBlob->GetBufferSize(); + + if(m_CacheShaders) + { + m_ShaderCache[hash] = byteBlob; + byteBlob->AddRef(); + m_ShaderCacheDirty = true; + } + + SAFE_RELEASE(errBlob); + + *srcblob = byteBlob; + return errors; +} + +ID3D11VertexShader *D3D11DebugManager::MakeVShader(const char *source, const char *entry, const char *profile, + int numInputDescs, D3D11_INPUT_ELEMENT_DESC *inputs, ID3D11InputLayout **ret, + vector *blob) +{ + ID3DBlob *byteBlob = NULL; + + if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "") + { + RDCERR("Couldn't get shader blob for %hs", entry); + return NULL; + } + + void *bytecode = byteBlob->GetBufferPointer(); + size_t bytecodeLen = byteBlob->GetBufferSize(); + + ID3D11VertexShader *ps = NULL; + + HRESULT hr = m_pDevice->CreateVertexShader(bytecode, bytecodeLen, NULL, &ps); + + if(FAILED(hr)) + { + RDCERR("Couldn't create vertex shader for %hs %08x", entry, hr); + + SAFE_RELEASE(byteBlob); + + return NULL; + } + + if(numInputDescs) + { + hr = m_pDevice->CreateInputLayout(inputs, numInputDescs, bytecode, bytecodeLen, ret); + + if(FAILED(hr)) + { + RDCERR("Couldn't create input layout for %hs %08x", entry, hr); + } + } + + if(blob) + { + blob->resize(bytecodeLen); + memcpy(&(*blob)[0], bytecode, bytecodeLen); + } + + SAFE_RELEASE(byteBlob); + + return ps; +} + +ID3D11GeometryShader *D3D11DebugManager::MakeGShader(const char *source, const char *entry, const char *profile) +{ + ID3DBlob *byteBlob = NULL; + + if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "") + { + return NULL; + } + + void *bytecode = byteBlob->GetBufferPointer(); + size_t bytecodeLen = byteBlob->GetBufferSize(); + + ID3D11GeometryShader *gs = NULL; + + HRESULT hr = m_pDevice->CreateGeometryShader(bytecode, bytecodeLen, NULL, &gs); + + SAFE_RELEASE(byteBlob); + + if(FAILED(hr)) + { + RDCERR("Couldn't create geometry shader for %hs %08x", entry, hr); + return NULL; + } + + return gs; +} + +ID3D11PixelShader *D3D11DebugManager::MakePShader(const char *source, const char *entry, const char *profile) +{ + ID3DBlob *byteBlob = NULL; + + if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "") + { + return NULL; + } + + void *bytecode = byteBlob->GetBufferPointer(); + size_t bytecodeLen = byteBlob->GetBufferSize(); + + ID3D11PixelShader *ps = NULL; + + HRESULT hr = m_pDevice->CreatePixelShader(bytecode, bytecodeLen, NULL, &ps); + + SAFE_RELEASE(byteBlob); + + if(FAILED(hr)) + { + RDCERR("Couldn't create pixel shader for %hs %08x", entry, hr); + return NULL; + } + + return ps; +} + +ID3D11ComputeShader *D3D11DebugManager::MakeCShader(const char *source, const char *entry, const char *profile) +{ + ID3DBlob *byteBlob = NULL; + + if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "") + { + return NULL; + } + + void *bytecode = byteBlob->GetBufferPointer(); + size_t bytecodeLen = byteBlob->GetBufferSize(); + + ID3D11ComputeShader *cs = NULL; + + HRESULT hr = m_pDevice->CreateComputeShader(bytecode, bytecodeLen, NULL, &cs); + + SAFE_RELEASE(byteBlob); + + if(FAILED(hr)) + { + RDCERR("Couldn't create compute shader for %hs %08x", entry, hr); + return NULL; + } + + return cs; +} + +void D3D11DebugManager::BuildShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) +{ + if(id == NULL || errors == NULL) + { + if(id) *id = ResourceId(); + return; + } + + char *profile = NULL; + + switch(type) + { + case eShaderStage_Vertex: profile = "vs_5_0"; break; + case eShaderStage_Hull: profile = "hs_5_0"; break; + case eShaderStage_Domain: profile = "ds_5_0"; break; + case eShaderStage_Geometry: profile = "gs_5_0"; break; + case eShaderStage_Pixel: profile = "ps_5_0"; break; + case eShaderStage_Compute: profile = "cs_5_0"; break; + default: RDCERR("Unexpected type in BuildShader!"); *id = ResourceId(); return; + } + + ID3DBlob *blob = NULL; + *errors = GetShaderBlob(source.c_str(), entry.c_str(), compileFlags, profile, &blob); + + if(blob == NULL) + { + *id = ResourceId(); + return; + } + + switch(type) + { + case eShaderStage_Vertex: + { + ID3D11VertexShader *sh = NULL; + m_WrappedDevice->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh); + + SAFE_RELEASE(blob); + + *id = ((WrappedID3D11Shader *)sh)->GetResourceID(); + return; + } + case eShaderStage_Hull: + { + ID3D11HullShader *sh = NULL; + m_WrappedDevice->CreateHullShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh); + + SAFE_RELEASE(blob); + + *id = ((WrappedID3D11Shader *)sh)->GetResourceID(); + return; + } + case eShaderStage_Domain: + { + ID3D11DomainShader *sh = NULL; + m_WrappedDevice->CreateDomainShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh); + + SAFE_RELEASE(blob); + + *id = ((WrappedID3D11Shader *)sh)->GetResourceID(); + return; + } + case eShaderStage_Geometry: + { + ID3D11GeometryShader *sh = NULL; + m_WrappedDevice->CreateGeometryShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh); + + SAFE_RELEASE(blob); + + *id = ((WrappedID3D11Shader *)sh)->GetResourceID(); + return; + } + case eShaderStage_Pixel: + { + ID3D11PixelShader *sh = NULL; + m_WrappedDevice->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh); + + SAFE_RELEASE(blob); + + *id = ((WrappedID3D11Shader *)sh)->GetResourceID(); + return; + } + case eShaderStage_Compute: + { + ID3D11ComputeShader *sh = NULL; + m_WrappedDevice->CreateComputeShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh); + + SAFE_RELEASE(blob); + + *id = ((WrappedID3D11Shader *)sh)->GetResourceID(); + return; + } + default: + break; + } + + SAFE_RELEASE(blob); + + RDCERR("Unexpected type in BuildShader!"); + *id = ResourceId(); +} + +ID3D11Buffer *D3D11DebugManager::MakeCBuffer(UINT size) +{ + D3D11_BUFFER_DESC bufDesc; + + bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufDesc.Usage = D3D11_USAGE_DYNAMIC; + bufDesc.ByteWidth = size; + bufDesc.StructureByteStride = 0; + bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufDesc.MiscFlags = 0; + + ID3D11Buffer *ret = NULL; + + HRESULT hr = m_pDevice->CreateBuffer(&bufDesc, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed to create CBuffer %08x", hr); + return NULL; + } + + return ret; +} + +void D3D11DebugManager::FillCBuffer(ID3D11Buffer *buf, float *data, size_t size) +{ + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Can't fill cbuffer %08x", hr); + } + else + { + memcpy(mapped.pData, data, size); + m_pImmediateContext->Unmap(buf, 0); + } +} + +ID3D11Buffer *D3D11DebugManager::MakeCBuffer(float *data, size_t size) +{ + int idx = m_DebugRender.publicCBufIdx; + + FillCBuffer(m_DebugRender.PublicCBuffers[idx], data, size); + + m_DebugRender.publicCBufIdx = (m_DebugRender.publicCBufIdx+1)%ARRAY_COUNT(m_DebugRender.PublicCBuffers); + + return m_DebugRender.PublicCBuffers[idx]; +} + +#include "data/hlsl/debugcbuffers.h" + +bool D3D11DebugManager::InitDebugRendering() +{ + HRESULT hr = S_OK; + + m_CustomShaderTex = NULL; + m_CustomShaderRTV = NULL; + m_CustomShaderResourceId = ResourceId(); + + m_OverlayRenderTex = NULL; + m_OverlayResourceId = ResourceId(); + + m_DebugRender.GenericVSCBuffer = MakeCBuffer(sizeof(DebugVertexCBuffer)); + m_DebugRender.GenericGSCBuffer = MakeCBuffer(sizeof(DebugGeometryCBuffer)); + m_DebugRender.GenericPSCBuffer = MakeCBuffer(sizeof(DebugPixelCBufferData)); + + for(int i=0; i < ARRAY_COUNT(m_DebugRender.PublicCBuffers); i++) + m_DebugRender.PublicCBuffers[i] = MakeCBuffer(sizeof(float)*4 * 100); + + m_DebugRender.publicCBufIdx = 0; + + string displayhlsl = GetEmbeddedResource(debugcbuffers_h); + displayhlsl += GetEmbeddedResource(debugcommon_hlsl); + displayhlsl += GetEmbeddedResource(debugdisplay_hlsl); + + D3D11_INPUT_ELEMENT_DESC inputDesc; + + inputDesc.SemanticName = "POSITION"; + inputDesc.SemanticIndex = 0; + inputDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT; + inputDesc.InputSlot = 0; + inputDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + inputDesc.AlignedByteOffset = 0; + inputDesc.InstanceDataStepRate = 0; + + vector bytecode; + + m_DebugRender.GenericVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_DebugVS", "vs_4_0", 1, &inputDesc, &m_DebugRender.GenericLayout); + m_DebugRender.TexDisplayPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_TexDisplayPS", "ps_5_0"); + m_DebugRender.WireframeVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_WireframeVS", "vs_4_0"); + m_DebugRender.MeshVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_MeshVS", "vs_4_0", 0, NULL, NULL, &bytecode); + m_DebugRender.MeshGS = MakeGShader(displayhlsl.c_str(), "RENDERDOC_MeshGS", "gs_4_0"); + m_DebugRender.MeshPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_MeshPS", "ps_4_0"); + + m_DebugRender.MeshVSBytecode = new byte[bytecode.size()]; + m_DebugRender.MeshVSBytelen = (uint32_t)bytecode.size(); + memcpy(m_DebugRender.MeshVSBytecode, &bytecode[0], bytecode.size()); + + inputDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + + m_DebugRender.WireframeHomogVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_WireframeHomogVS", "vs_4_0", 1, &inputDesc, &m_DebugRender.GenericHomogLayout); + m_DebugRender.WireframePS = MakePShader(displayhlsl.c_str(), "RENDERDOC_WireframePS", "ps_4_0"); + m_DebugRender.FullscreenVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0"); + m_DebugRender.OverlayPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_OverlayPS", "ps_4_0"); + m_DebugRender.CheckerboardPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_CheckerboardPS", "ps_4_0"); + + string multisamplehlsl = GetEmbeddedResource(multisample_hlsl); + + m_DebugRender.CopyMSToArrayPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_CopyMSToArray", "ps_5_0"); + m_DebugRender.CopyArrayToMSPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_CopyArrayToMS", "ps_5_0"); + m_DebugRender.FloatCopyMSToArrayPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyMSToArray", "ps_5_0"); + m_DebugRender.FloatCopyArrayToMSPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyArrayToMS", "ps_5_0"); + m_DebugRender.DepthCopyMSToArrayPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyMSToArray", "ps_5_0"); + m_DebugRender.DepthCopyArrayToMSPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyArrayToMS", "ps_5_0"); + + string histogramhlsl = GetEmbeddedResource(debugcbuffers_h); + histogramhlsl += GetEmbeddedResource(debugcommon_hlsl); + histogramhlsl += GetEmbeddedResource(histogram_hlsl); + + RenderDoc::Inst().SetProgress(DebugManagerInit, 0.1f); + + if(RenderDoc::Inst().IsReplayApp()) + { + for(int t=eTexType_1D; t < eTexType_Max; t++) + { + // float, uint, sint + for(int i=0; i < 3; i++) + { + string hlsl = string("#define SHADER_RESTYPE ") + ToStr::Get(t) + "\n"; + hlsl += string("#define UINT_TEX ") + (i == 1 ? "1" : "0") + "\n"; + hlsl += string("#define SINT_TEX ") + (i == 2 ? "1" : "0") + "\n"; + hlsl += histogramhlsl; + + m_DebugRender.TileMinMaxCS[t][i] = MakeCShader(hlsl.c_str(), "RENDERDOC_TileMinMaxCS", "cs_5_0"); + m_DebugRender.HistogramCS[t][i] = MakeCShader(hlsl.c_str(), "RENDERDOC_HistogramCS", "cs_5_0"); + + if(t == 1) + m_DebugRender.ResultMinMaxCS[i] = MakeCShader(hlsl.c_str(), "RENDERDOC_ResultMinMaxCS", "cs_5_0"); + + RenderDoc::Inst().SetProgress(DebugManagerInit, (float(i + 3.0f*t)/float(2.0f + 3.0f*(eTexType_Max-1)))*0.7f+0.1f); + } + } + } + + RenderDoc::Inst().SetProgress(DebugManagerInit, 0.8f); + + RDCCOMPILE_ASSERT(eTexType_1D == RESTYPE_TEX1D, "Tex type enum doesn't match shader defines"); + RDCCOMPILE_ASSERT(eTexType_2D == RESTYPE_TEX2D, "Tex type enum doesn't match shader defines"); + RDCCOMPILE_ASSERT(eTexType_3D == RESTYPE_TEX3D, "Tex type enum doesn't match shader defines"); + RDCCOMPILE_ASSERT(eTexType_Depth == RESTYPE_DEPTH, "Tex type enum doesn't match shader defines"); + RDCCOMPILE_ASSERT(eTexType_Stencil == RESTYPE_DEPTH_STENCIL, "Tex type enum doesn't match shader defines"); + RDCCOMPILE_ASSERT(eTexType_DepthMS == RESTYPE_DEPTH_MS, "Tex type enum doesn't match shader defines"); + RDCCOMPILE_ASSERT(eTexType_StencilMS == RESTYPE_DEPTH_STENCIL_MS, "Tex type enum doesn't match shader defines"); + + D3D11_BLEND_DESC blendDesc; + RDCEraseEl(blendDesc); + + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + blendDesc.RenderTarget[0].BlendEnable = TRUE; + blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + hr = m_pDevice->CreateBlendState(&blendDesc, &m_DebugRender.BlendState); + + if(FAILED(hr)) + { + RDCERR("Failed to create default blendstate %08x", hr); + } + + D3D11_RASTERIZER_DESC rastDesc; + RDCEraseEl(rastDesc); + + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.DepthBias = 0; + + hr = m_pDevice->CreateRasterizerState(&rastDesc, &m_DebugRender.RastState); + + if(FAILED(hr)) + { + RDCERR("Failed to create default rasterizer state %08x", hr); + } + + D3D11_SAMPLER_DESC sampDesc; + RDCEraseEl(sampDesc); + + sampDesc.AddressU = sampDesc.AddressV = sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + sampDesc.MaxAnisotropy = 1; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = FLT_MAX; + sampDesc.MipLODBias = 0.0f; + + hr = m_pDevice->CreateSamplerState(&sampDesc, &m_DebugRender.LinearSampState); + + if(FAILED(hr)) + { + RDCERR("Failed to create linear sampler state %08x", hr); + } + + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + + hr = m_pDevice->CreateSamplerState(&sampDesc, &m_DebugRender.PointSampState); + + if(FAILED(hr)) + { + RDCERR("Failed to create point sampler state %08x", hr); + } + + { + D3D11_DEPTH_STENCIL_DESC desc; + + desc.BackFace.StencilFailOp = desc.BackFace.StencilPassOp = desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.FrontFace.StencilFailOp = desc.FrontFace.StencilPassOp = desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.DepthEnable = FALSE; + desc.DepthFunc = D3D11_COMPARISON_ALWAYS; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + desc.StencilEnable = FALSE; + desc.StencilReadMask = desc.StencilWriteMask = 0xff; + + hr = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.NoDepthState); + + if(FAILED(hr)) + { + RDCERR("Failed to create no-depth depthstencilstate %08x", hr); + } + + desc.DepthEnable = TRUE; + desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + + hr = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.LEqualDepthState); + + if(FAILED(hr)) + { + RDCERR("Failed to create less-equal depthstencilstate %08x", hr); + } + } + + { + D3D11_SUBRESOURCE_DATA initialPos; + + float *buf = new float[(2 + FONT_MAX_CHARS*4) *3]; + + // tri strip with degenerates to split characters: + // + // 0--24--68--.. + // | /|| /|| / + // |/ ||/ ||/ + // 1--35--79--.. + + buf[0] = 0.0f; + buf[1] = 0.0f; + buf[2] = 0.0f; + + buf[3] = 0.0f; + buf[4] = -1.0f; + buf[5] = 0.0f; + + for(int i=1; i <= FONT_MAX_CHARS; i++) + { + buf[i*12 - 6 + 0] = 1.0f; + buf[i*12 - 6 + 1] = 0.0f; + buf[i*12 - 6 + 2] = float(i-1); + + buf[i*12 - 6 + 3] = 1.0f; + buf[i*12 - 6 + 4] = -1.0f; + buf[i*12 - 6 + 5] = float(i-1); + + + buf[i*12 + 0 + 0] = 0.0f; + buf[i*12 + 0 + 1] = 0.0f; + buf[i*12 + 0 + 2] = float(i); + + buf[i*12 + 0 + 3] = 0.0f; + buf[i*12 + 0 + 4] = -1.0f; + buf[i*12 + 0 + 5] = float(i); + } + + initialPos.pSysMem = buf; + initialPos.SysMemPitch = initialPos.SysMemSlicePitch = 0; + + D3D11_BUFFER_DESC bufDesc; + + bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufDesc.Usage = D3D11_USAGE_DEFAULT; + bufDesc.ByteWidth = (2 + FONT_MAX_CHARS*4) *3*sizeof(float); + bufDesc.CPUAccessFlags = 0; + bufDesc.MiscFlags = 0; + + hr = m_pDevice->CreateBuffer(&bufDesc, &initialPos, &m_DebugRender.PosBuffer); + + if(FAILED(hr)) + { + RDCERR("Failed to create font pos buffer %08x", hr); + } + + delete[] buf; + } + + RenderDoc::Inst().SetProgress(DebugManagerInit, 0.9f); + + { + float data[] = { + 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + }; + + D3D11_SUBRESOURCE_DATA initialPos; + + initialPos.pSysMem = data; + initialPos.SysMemPitch = initialPos.SysMemSlicePitch = 0; + + D3D11_BUFFER_DESC bufDesc; + + bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufDesc.Usage = D3D11_USAGE_IMMUTABLE; + bufDesc.ByteWidth = sizeof(data); + bufDesc.CPUAccessFlags = 0; + bufDesc.MiscFlags = 0; + + hr = m_pDevice->CreateBuffer(&bufDesc, &initialPos, &m_DebugRender.OutlineStripVB); + + if(FAILED(hr)) + { + RDCERR("Failed to create outline strip buffer %08x", hr); + } + } + + { + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D *pickTex = NULL; + + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + desc.Width = 100; + desc.Height = 100; + desc.MipLevels = 1; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + desc.MiscFlags = 0; + + hr = m_pDevice->CreateTexture2D(&desc, NULL, &pickTex); + + if(FAILED(hr)) + { + RDCERR("Failed to create pick tex %08x", hr); + } + else + { + hr = m_pDevice->CreateRenderTargetView(pickTex, NULL, &m_DebugRender.PickPixelRT); + + if(FAILED(hr)) + { + RDCERR("Failed to create pick rt %08x", hr); + } + + SAFE_RELEASE(pickTex); + } + } + + { + D3D11_TEXTURE2D_DESC desc; + RDCEraseEl(desc); + desc.ArraySize = 1; + desc.MipLevels = 1; + desc.Width = 1; + desc.Height = 1; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_STAGING; + desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + + hr = m_pDevice->CreateTexture2D(&desc, NULL, &m_DebugRender.PickPixelStageTex); + + if(FAILED(hr)) + { + RDCERR("Failed to create pick stage tex %08x", hr); + } + } + + { + D3D11_BUFFER_DESC bDesc; + + const uint32_t maxTexDim = 16384; + const uint32_t blockPixSize = HGRAM_TILES_PER_BLOCK*HGRAM_PIXELS_PER_TILE; + const uint32_t maxBlocksNeeded = (maxTexDim*maxTexDim)/(blockPixSize*blockPixSize); + + bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; + bDesc.ByteWidth = 2*4*sizeof(float)*HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK*maxBlocksNeeded; + bDesc.CPUAccessFlags = 0; + bDesc.MiscFlags = 0; + bDesc.StructureByteStride = 0; + bDesc.Usage = D3D11_USAGE_DEFAULT; + + hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.tileResultBuff); + + if(FAILED(hr)) + { + RDCERR("Failed to create tile result buffer %08x", hr); + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + srvDesc.Buffer.ElementOffset = 0; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.ElementWidth = 4*sizeof(float); + srvDesc.Buffer.NumElements = bDesc.ByteWidth/srvDesc.Buffer.ElementWidth; + + hr = m_pDevice->CreateShaderResourceView(m_DebugRender.tileResultBuff, &srvDesc, &m_DebugRender.tileResultSRV[0]); + + if(FAILED(hr)) + RDCERR("Failed to create tile result SRV 0 %08x", hr); + + srvDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT; + hr = m_pDevice->CreateShaderResourceView(m_DebugRender.tileResultBuff, &srvDesc, &m_DebugRender.tileResultSRV[1]); + + if(FAILED(hr)) + RDCERR("Failed to create tile result SRV 1 %08x", hr); + + srvDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT; + hr = m_pDevice->CreateShaderResourceView(m_DebugRender.tileResultBuff, &srvDesc, &m_DebugRender.tileResultSRV[2]); + + if(FAILED(hr)) + RDCERR("Failed to create tile result SRV 2 %08x", hr); + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.Flags = 0; + uavDesc.Buffer.NumElements = srvDesc.Buffer.NumElements; + + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.tileResultBuff, &uavDesc, &m_DebugRender.tileResultUAV[0]); + + if(FAILED(hr)) + RDCERR("Failed to create tile result UAV 0 %08x", hr); + + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT; + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.tileResultBuff, &uavDesc, &m_DebugRender.tileResultUAV[1]); + + if(FAILED(hr)) + RDCERR("Failed to create tile result UAV 1 %08x", hr); + + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT; + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.tileResultBuff, &uavDesc, &m_DebugRender.tileResultUAV[2]); + + if(FAILED(hr)) + RDCERR("Failed to create tile result UAV 2 %08x", hr); + + uavDesc.Format = DXGI_FORMAT_R32_UINT; + uavDesc.Buffer.NumElements = HGRAM_NUM_BUCKETS; + bDesc.ByteWidth = uavDesc.Buffer.NumElements*sizeof(int); + + hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.histogramBuff); + + if(FAILED(hr)) + RDCERR("Failed to create histogram buff %08x", hr); + + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.histogramBuff, &uavDesc, &m_DebugRender.histogramUAV); + + if(FAILED(hr)) + RDCERR("Failed to create histogram UAV %08x", hr); + + bDesc.BindFlags = 0; + bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bDesc.Usage = D3D11_USAGE_STAGING; + + hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.histogramStageBuff); + + if(FAILED(hr)) + RDCERR("Failed to create histogram stage buff %08x", hr); + + bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + bDesc.CPUAccessFlags = 0; + bDesc.ByteWidth = 2*4*sizeof(float); + bDesc.Usage = D3D11_USAGE_DEFAULT; + + hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.resultBuff); + + if(FAILED(hr)) + RDCERR("Failed to create result buff %08x", hr); + + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + uavDesc.Buffer.NumElements = 2; + + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.resultBuff, &uavDesc, &m_DebugRender.resultUAV[0]); + + if(FAILED(hr)) + RDCERR("Failed to create result UAV 0 %08x", hr); + + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT; + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.resultBuff, &uavDesc, &m_DebugRender.resultUAV[1]); + + if(FAILED(hr)) + RDCERR("Failed to create result UAV 1 %08x", hr); + + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT; + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.resultBuff, &uavDesc, &m_DebugRender.resultUAV[2]); + + if(FAILED(hr)) + RDCERR("Failed to create result UAV 2 %08x", hr); + + bDesc.BindFlags = 0; + bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bDesc.Usage = D3D11_USAGE_STAGING; + + hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.resultStageBuff); + + if(FAILED(hr)) + RDCERR("Failed to create result stage buff %08x", hr); + } + + { + D3D11_BUFFER_DESC desc; + + desc.StructureByteStride = 0; + desc.ByteWidth = STAGE_BUFFER_BYTE_SIZE; + desc.BindFlags = 0; + desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + hr = m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.StageBuffer); + + if(FAILED(hr)) + RDCERR("Failed to create map staging buffer %08x", hr); + } + + return true; +} + +void D3D11DebugManager::ShutdownFontRendering() +{ +} + +void D3D11DebugManager::ShutdownStreamOut() +{ + SAFE_RELEASE(m_SOBuffer); + SAFE_RELEASE(m_SOStatsQuery); + SAFE_RELEASE(m_SOStagingBuffer); + + SAFE_RELEASE(m_WireframeHelpersRS); + SAFE_RELEASE(m_WireframeHelpersBS); + SAFE_RELEASE(m_SolidHelpersRS); + + SAFE_RELEASE(m_MeshDisplayLayout); + + SAFE_RELEASE(m_FrustumHelper); + SAFE_RELEASE(m_AxisHelper); + SAFE_RELEASE(m_TriHighlightHelper); +} + +bool D3D11DebugManager::InitStreamOut() +{ + m_MeshDisplayLayout = NULL; + m_MeshDisplayNULLVB = 0; + m_PrevMeshInputLayout = NULL; + + D3D11_BUFFER_DESC bufferDesc = + { + m_SOBufferSize, + D3D11_USAGE_DEFAULT, + D3D11_BIND_STREAM_OUTPUT, + 0, + 0, + 0 + }; + HRESULT hr = S_OK; + + hr = m_pDevice->CreateBuffer( &bufferDesc, NULL, &m_SOBuffer ); + + if(FAILED(hr)) RDCERR("Failed to create m_SOBuffer %08x", hr); + + bufferDesc.Usage = D3D11_USAGE_STAGING; + bufferDesc.BindFlags = 0; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + hr = m_pDevice->CreateBuffer( &bufferDesc, NULL, &m_SOStagingBuffer ); + if(FAILED(hr)) RDCERR("Failed to create m_SOStagingBuffer %08x", hr); + + D3D11_QUERY_DESC qdesc; + qdesc.MiscFlags = 0; + qdesc.Query = D3D11_QUERY_SO_STATISTICS; + + hr = m_pDevice->CreateQuery(&qdesc, &m_SOStatsQuery); + if(FAILED(hr)) RDCERR("Failed to create m_SOStatsQuery %08x", hr); + + D3D11_RASTERIZER_DESC desc; + { + desc.AntialiasedLineEnable = TRUE; + desc.DepthBias = 0; + desc.DepthBiasClamp = 0.0f; + desc.DepthClipEnable = FALSE; + desc.FrontCounterClockwise = FALSE; + desc.MultisampleEnable = FALSE; + desc.ScissorEnable = FALSE; + desc.SlopeScaledDepthBias = 0.0f; + desc.FillMode = D3D11_FILL_WIREFRAME; + desc.CullMode = D3D11_CULL_NONE; + + hr = m_pDevice->CreateRasterizerState(&desc, &m_WireframeHelpersRS); + if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersRS %08x", hr); + + desc.FrontCounterClockwise = TRUE; + desc.CullMode = D3D11_CULL_FRONT; + + hr = m_pDevice->CreateRasterizerState(&desc, &m_WireframeHelpersCullCCWRS); + if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersCullCCWRS %08x", hr); + + desc.FrontCounterClockwise = FALSE; + desc.CullMode = D3D11_CULL_FRONT; + + hr = m_pDevice->CreateRasterizerState(&desc, &m_WireframeHelpersCullCWRS); + if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersCullCCWRS %08x", hr); + } + + { + D3D11_BLEND_DESC desc; + RDCEraseEl(desc); + + desc.AlphaToCoverageEnable = TRUE; + desc.IndependentBlendEnable = FALSE; + desc.RenderTarget[0].BlendEnable = TRUE; + desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].RenderTargetWriteMask = 0xf; + + hr = m_pDevice->CreateBlendState(&desc, &m_WireframeHelpersBS); + if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersRS %08x", hr); + } + + { + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_NONE; + + hr = m_pDevice->CreateRasterizerState(&desc, &m_SolidHelpersRS); + if(FAILED(hr)) RDCERR("Failed to create m_SolidHelpersRS %08x", hr); + } + + { + Vec3f axisVB[6] = + { + Vec3f(0.0f, 0.0f, 0.0f), + Vec3f(1.0f, 0.0f, 0.0f), + Vec3f(0.0f, 0.0f, 0.0f), + Vec3f(0.0f, 1.0f, 0.0f), + Vec3f(0.0f, 0.0f, 0.0f), + Vec3f(0.0f, 0.0f, 1.0f), + }; + + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = axisVB; + data.SysMemPitch = data.SysMemSlicePitch = 0; + + D3D11_BUFFER_DESC bdesc; + bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bdesc.CPUAccessFlags = 0; + bdesc.ByteWidth = sizeof(axisVB); + bdesc.MiscFlags = 0; + bdesc.Usage = D3D11_USAGE_IMMUTABLE; + + hr = m_pDevice->CreateBuffer(&bdesc, &data, &m_AxisHelper); + if(FAILED(hr)) RDCERR("Failed to create m_AxisHelper %08x", hr); + } + + { + Vec3f TLN = Vec3f(-1.0f, 1.0f, 0.0f); // TopLeftNear, etc... + Vec3f TRN = Vec3f( 1.0f, 1.0f, 0.0f); + Vec3f BLN = Vec3f(-1.0f, -1.0f, 0.0f); + Vec3f BRN = Vec3f( 1.0f, -1.0f, 0.0f); + + Vec3f TLF = Vec3f(-1.0f, 1.0f, 1.0f); + Vec3f TRF = Vec3f( 1.0f, 1.0f, 1.0f); + Vec3f BLF = Vec3f(-1.0f, -1.0f, 1.0f); + Vec3f BRF = Vec3f( 1.0f, -1.0f, 1.0f); + + // 12 frustum lines => 24 verts + Vec3f axisVB[24] = + { + TLN, TRN, + TRN, BRN, + BRN, BLN, + BLN, TLN, + + TLN, TLF, + TRN, TRF, + BLN, BLF, + BRN, BRF, + + TLF, TRF, + TRF, BRF, + BRF, BLF, + BLF, TLF, + }; + + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = axisVB; + data.SysMemPitch = data.SysMemSlicePitch = 0; + + D3D11_BUFFER_DESC bdesc; + bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bdesc.CPUAccessFlags = 0; + bdesc.ByteWidth = sizeof(axisVB); + bdesc.MiscFlags = 0; + bdesc.Usage = D3D11_USAGE_IMMUTABLE; + + hr = m_pDevice->CreateBuffer(&bdesc, &data, &m_FrustumHelper); + + if(FAILED(hr)) + RDCERR("Failed to create m_FrustumHelper %08x", hr); + } + + { + D3D11_BUFFER_DESC bdesc; + bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bdesc.ByteWidth = sizeof(Vec4f)*4; + bdesc.MiscFlags = 0; + bdesc.Usage = D3D11_USAGE_DYNAMIC; + + hr = m_pDevice->CreateBuffer(&bdesc, NULL, &m_TriHighlightHelper); + + if(FAILED(hr)) + RDCERR("Failed to create m_TriHighlightHelper %08x", hr); + } + + return true; +} + +bool D3D11DebugManager::InitFontRendering() +{ + D3D11_TEXTURE2D_DESC desc; + RDCEraseEl(desc); + + int width = FONT_TEX_WIDTH, height = FONT_TEX_HEIGHT; + + desc.ArraySize = 1; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.Width = width; + desc.Height = height; + + { + int h=height>>1; + + desc.MipLevels = 1; + + while(h >= 8) + { + desc.MipLevels++; + + h >>= 1; + } + } + desc.MiscFlags = 0; + desc.SampleDesc.Quality = 0; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + + D3D11_SUBRESOURCE_DATA *initialData = new D3D11_SUBRESOURCE_DATA[desc.MipLevels]; + + ///////////////////////////////////////////////////////////////////// + BITMAPINFOHEADER bih; + RDCEraseEl(bih); + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = width; + bih.biHeight = height; + bih.biPlanes = 1; + bih.biBitCount = 32; + bih.biCompression = BI_RGB; + + byte **buffers = new byte *[desc.MipLevels]; + + HDC pDC = GetDC(NULL); + HDC MemDC = CreateCompatibleDC(pDC); + + SetBkColor(MemDC, RGB(0, 0, 0)); + SetTextColor(MemDC, RGB(255, 255, 255)); + + HBITMAP *bmps = new HBITMAP[desc.MipLevels]; + + for(UINT i=0; i < desc.MipLevels; i++) + { + int w = width>>i; + int h = height>>i; + + bih.biWidth = w; + bih.biHeight = h; + + HFONT font = CreateFont(h,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, + CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, FIXED_PITCH,TEXT("Consolas")); + + bmps[i] = CreateCompatibleBitmap(pDC, w, h); + + SelectObject(MemDC, bmps[i]); + + SelectObject(MemDC, font); + + char str[2] = {0, 0}; + + for(int s=0; s < 127-' '-1; s++) + { + str[0] = (char)(' '+s+1); + TextOutA(MemDC, int(s*h*0.75), -1, str, 1); + } + + byte *buf = buffers[i] = new byte[w*h*4]; + + GetDIBits(MemDC, bmps[i], 0, h, buf, (BITMAPINFO *)&bih, DIB_RGB_COLORS); + + DeleteObject(font); + + // flip it right side up + byte *tmpRow = new byte[w*4]; + for(int j=0; j < h/2; j++) + { + int x = h-j-1; + memcpy(tmpRow, &buf[j*w*4], w*4); + memcpy(&buf[j*w*4], &buf[x*w*4], w*4); + memcpy(&buf[x*w*4], tmpRow, w*4); + } + delete[] tmpRow; + + ///////////////////////////////////////////////////////////////////// + + initialData[i].pSysMem = buffers[i]; + initialData[i].SysMemPitch = w*4; + initialData[i].SysMemSlicePitch = w*h*4; + } + + ID3D11Texture2D *debugTex; + + HRESULT hr = S_OK; + + hr = m_pDevice->CreateTexture2D(&desc, initialData, &debugTex); + + if(FAILED(hr)) + RDCERR("Failed to create debugTex %08x", hr); + + delete[] initialData; + + hr = m_pDevice->CreateShaderResourceView(debugTex, NULL, &m_Font.Tex); + + if(FAILED(hr)) + RDCERR("Failed to create m_Font.Tex %08x", hr); + + SAFE_RELEASE(debugTex); + + for(UINT i=0; i < desc.MipLevels; i++) + { + SAFE_DELETE_ARRAY(buffers[i]); + DeleteObject(bmps[i]); + } + SAFE_DELETE_ARRAY(buffers); + SAFE_DELETE_ARRAY(bmps); + + DeleteDC(pDC); + DeleteDC(MemDC); + + { + HRESULT hr = S_OK; + + m_Font.CBuffer = MakeCBuffer(sizeof(FontCBuffer)); + + D3D11_BUFFER_DESC bufDesc; + + bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufDesc.MiscFlags = 0; + bufDesc.Usage = D3D11_USAGE_DYNAMIC; + bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufDesc.ByteWidth = 2+FONT_MAX_CHARS*4*4; + + hr = m_pDevice->CreateBuffer(&bufDesc, NULL, &m_Font.CharBuffer); + + if(FAILED(hr)) + RDCERR("Failed to create m_Font.CharBuffer %08x", hr); + + string fullhlsl = ""; + { + string textShaderHLSL = GetEmbeddedResource(debugtext_hlsl); + string debugShaderCBuf = GetEmbeddedResource(debugcbuffers_h); + + fullhlsl = debugShaderCBuf + textShaderHLSL; + } + + D3D11_INPUT_ELEMENT_DESC inputDescs[2]; + + inputDescs[0].SemanticName = "POSITION"; + inputDescs[0].SemanticIndex = 0; + inputDescs[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; + inputDescs[0].InputSlot = 0; + inputDescs[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + inputDescs[0].AlignedByteOffset = 0; + inputDescs[0].InstanceDataStepRate = 0; + + inputDescs[1].SemanticName = "TEXCOORD"; + inputDescs[1].SemanticIndex = 0; + inputDescs[1].Format = DXGI_FORMAT_R32_UINT; + inputDescs[1].InputSlot = 1; + inputDescs[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + inputDescs[1].AlignedByteOffset = 0; + inputDescs[1].InstanceDataStepRate = 0; + + m_Font.VS = MakeVShader(fullhlsl.c_str(), "RENDERDOC_TextVS", "vs_4_0", 2, inputDescs, &m_Font.Layout); + m_Font.PS = MakePShader(fullhlsl.c_str(), "RENDERDOC_TextPS", "ps_4_0"); + } + + return true; +} + +void D3D11DebugManager::OutputWindow::MakeRTV() +{ + ID3D11Texture2D *texture = NULL; + HRESULT hr = swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&texture); + + if(FAILED(hr)) + { + RDCERR("Failed to get swap chain buffer, HRESULT: 0x%08x", hr); + SAFE_RELEASE(texture); + return; + } + + hr = dev->CreateRenderTargetView(texture, NULL, &rtv); + + SAFE_RELEASE(texture); + + if(FAILED(hr)) + { + RDCERR("Failed to create RTV for swap chain buffer, HRESULT: 0x%08x", hr); + SAFE_RELEASE(swap); + return; + } +} + +void D3D11DebugManager::OutputWindow::MakeDSV() +{ + ID3D11Texture2D *texture = NULL; + HRESULT hr = swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&texture); + + if(FAILED(hr)) + { + RDCERR("Failed to get swap chain buffer, HRESULT: 0x%08x", hr); + SAFE_RELEASE(texture); + return; + } + + D3D11_TEXTURE2D_DESC texDesc; + texture->GetDesc(&texDesc); + + SAFE_RELEASE(texture); + + texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + hr = dev->CreateTexture2D(&texDesc, NULL, &texture); + + if(FAILED(hr)) + { + RDCERR("Failed to create DSV texture for main output, HRESULT: 0x%08x", hr); + SAFE_RELEASE(swap); + SAFE_RELEASE(rtv); + return; + } + + hr = dev->CreateDepthStencilView(texture, NULL, &dsv); + + SAFE_RELEASE(texture); + + if(FAILED(hr)) + { + RDCERR("Failed to create DSV for main output, HRESULT: 0x%08x", hr); + SAFE_RELEASE(swap); + SAFE_RELEASE(rtv); + return; + } +} + +uint64_t D3D11DebugManager::MakeOutputWindow(void *w, bool depth) +{ + OutputWindow outw; + outw.wnd = (HWND)w; + outw.dev = m_WrappedDevice; + + DXGI_SWAP_CHAIN_DESC swapDesc; + RDCEraseEl(swapDesc); + + RECT rect;GetClientRect(outw.wnd, &rect); + + swapDesc.BufferCount = 2; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + outw.width = swapDesc.BufferDesc.Width = rect.right-rect.left; + outw.height = swapDesc.BufferDesc.Height = rect.bottom-rect.top; + swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapDesc.SampleDesc.Count = 1; + swapDesc.SampleDesc.Quality = 0; + swapDesc.OutputWindow = outw.wnd; + swapDesc.Windowed = TRUE; + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapDesc.Flags = 0; + + HRESULT hr = S_OK; + + hr = m_pFactory->CreateSwapChain(m_WrappedDevice, &swapDesc, &outw.swap); + + if(FAILED(hr)) + { + RDCERR("Failed to create swap chain for HWND, HRESULT: 0x%08x", hr); + return 0; + } + + outw.MakeRTV(); + + outw.dsv = NULL; + if(depth) outw.MakeDSV(); + + uint64_t id = m_OutputWindowID++; + m_OutputWindows[id] = outw; + return id; +} + +void D3D11DebugManager::DestroyOutputWindow(uint64_t id) +{ + auto it = m_OutputWindows.find(id); + if(id == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + SAFE_RELEASE(outw.swap); + SAFE_RELEASE(outw.rtv); + SAFE_RELEASE(outw.dsv); + + m_OutputWindows.erase(it); +} + +bool D3D11DebugManager::CheckResizeOutputWindow(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return false; + + OutputWindow &outw = m_OutputWindows[id]; + + if(outw.wnd == NULL || outw.swap == NULL) + return false; + + RECT rect;GetClientRect(outw.wnd, &rect); + long w = rect.right-rect.left; + long h = rect.bottom-rect.top; + + if(w != outw.width || h != outw.height) + { + outw.width = w; + outw.height = h; + + m_WrappedContext->OMSetRenderTargets(0, 0, 0); + + if(outw.width > 0 && outw.height > 0) + { + SAFE_RELEASE(outw.rtv); + SAFE_RELEASE(outw.dsv); + + DXGI_SWAP_CHAIN_DESC desc; + outw.swap->GetDesc(&desc); + + HRESULT hr = outw.swap->ResizeBuffers(desc.BufferCount, outw.width, outw.height, desc.BufferDesc.Format, desc.Flags); + + if(FAILED(hr)) + { + RDCERR("Failed to resize swap chain, HRESULT: 0x%08x", hr); + return true; + } + + outw.MakeRTV(); + outw.MakeDSV(); + } + + return true; + } + + return false; +} + +void D3D11DebugManager::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + w = m_OutputWindows[id].width; + h = m_OutputWindows[id].height; +} + +void D3D11DebugManager::ClearOutputWindowColour(uint64_t id, float col[4]) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + m_WrappedContext->ClearRenderTargetView(m_OutputWindows[id].rtv, col); +} + +void D3D11DebugManager::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + if(m_OutputWindows[id].dsv) + m_WrappedContext->ClearDepthStencilView(m_OutputWindows[id].dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, depth, stencil); +} + +void D3D11DebugManager::BindOutputWindow(uint64_t id, bool depth) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + m_WrappedContext->OMSetRenderTargets(1, &m_OutputWindows[id].rtv, depth && m_OutputWindows[id].dsv ? m_OutputWindows[id].dsv : NULL); + + D3D11_VIEWPORT viewport = { 0, 0, (float)m_OutputWindows[id].width, (float)m_OutputWindows[id].height, 0.0f, 1.0f }; + m_WrappedContext->RSSetViewports(1, &viewport); + + SetOutputDimensions(m_OutputWindows[id].width, m_OutputWindows[id].height); +} + +bool D3D11DebugManager::IsOutputWindowVisible(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return false; + + return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE); +} + +void D3D11DebugManager::FlipOutputWindow(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + if(m_OutputWindows[id].swap) + m_OutputWindows[id].swap->Present(0, 0); +} + +uint32_t D3D11DebugManager::GetStructCount(ID3D11UnorderedAccessView *uav) +{ + m_pImmediateContext->CopyStructureCount(m_DebugRender.StageBuffer, 0, UNWRAP(WrappedID3D11UnorderedAccessView, uav)); + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = m_pImmediateContext->Map(m_DebugRender.StageBuffer, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to Map %08x", hr); + return ~0U; + } + + uint32_t ret = *((uint32_t *)mapped.pData); + + m_pImmediateContext->Unmap(m_DebugRender.StageBuffer, 0); + + return ret; +} + +bool D3D11DebugManager::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram) +{ + if(minval >= maxval) return false; + + TextureShaderDetails details = GetShaderDetails(texid, true); + + if(details.texFmt == DXGI_FORMAT_UNKNOWN) + return false; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + HistogramCBufferData cdata; + cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth>>mip, 1U); + cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight>>mip, 1U); + cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth>>mip, 1U); + cdata.HistogramSlice = (float)sliceFace; + cdata.HistogramMip = mip; + cdata.HistogramMin = minval; + cdata.HistogramMax = maxval; + cdata.HistogramChannels = 0; + if(channels[0]) cdata.HistogramChannels |= 0x1; + if(channels[1]) cdata.HistogramChannels |= 0x2; + if(channels[2]) cdata.HistogramChannels |= 0x4; + if(channels[3]) cdata.HistogramChannels |= 0x8; + cdata.HistogramFlags = 0; + + int srvOffset = 0; + int intIdx = 0; + + if(IsUIntFormat(details.texFmt)) + { + cdata.HistogramFlags |= TEXDISPLAY_UINT_TEX; + srvOffset = 10; + intIdx = 1; + } + if(IsIntFormat(details.texFmt)) + { + cdata.HistogramFlags |= TEXDISPLAY_SINT_TEX; + srvOffset = 20; + intIdx = 2; + } + + if(details.texType == eTexType_3D) + cdata.HistogramSlice = float(sliceFace)/float(details.texDepth); + + ID3D11Buffer *cbuf = MakeCBuffer((float *)&cdata, sizeof(cdata)); + + UINT zeroes[] = { 0, 0, 0, 0 }; + m_pImmediateContext->ClearUnorderedAccessViewUint(m_DebugRender.histogramUAV, zeroes); + + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL); + + ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { 0 }; + UINT UAV_keepcounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 }; + uavs[0] = m_DebugRender.histogramUAV; + m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, UAV_keepcounts); + + m_pImmediateContext->CSSetConstantBuffers(0, 1, &cbuf); + + m_pImmediateContext->CSSetShaderResources(srvOffset, eTexType_Max, details.srv); + + ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState }; + m_pImmediateContext->CSSetSamplers(0, 2, samps); + + m_pImmediateContext->CSSetShader(m_DebugRender.HistogramCS[details.texType][intIdx], NULL, 0); + + int tilesX = (int)ceil(cdata.HistogramTextureResolution.x/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + int tilesY = (int)ceil(cdata.HistogramTextureResolution.y/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + + m_pImmediateContext->Dispatch(tilesX, tilesY, 1); + + m_pImmediateContext->CopyResource(m_DebugRender.histogramStageBuff, m_DebugRender.histogramBuff); + + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->Map(m_DebugRender.histogramStageBuff, 0, D3D11_MAP_READ, 0, &mapped); + + histogram.clear(); + histogram.resize(HGRAM_NUM_BUCKETS); + + if(FAILED(hr)) + { + RDCERR("Can't map histogram stage buff %08x", hr); + } + else + { + memcpy(&histogram[0], mapped.pData, sizeof(uint32_t)*HGRAM_NUM_BUCKETS); + + m_pImmediateContext->Unmap(m_DebugRender.histogramStageBuff, 0); + } + + return true; +} + +bool D3D11DebugManager::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval) +{ + TextureShaderDetails details = GetShaderDetails(texid, true); + + if(details.texFmt == DXGI_FORMAT_UNKNOWN) + return false; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + HistogramCBufferData cdata; + cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth>>mip, 1U); + cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight>>mip, 1U); + cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth>>mip, 1U); + cdata.HistogramSlice = (float)sliceFace; + cdata.HistogramMip = mip; + cdata.HistogramMin = 0.0f; + cdata.HistogramMax = 1.0f; + cdata.HistogramChannels = 0xf; + cdata.HistogramFlags = 0; + + int srvOffset = 0; + int intIdx = 0; + + DXGI_FORMAT fmt = GetTypedFormat(details.texFmt); + + if(IsUIntFormat(fmt)) + { + cdata.HistogramFlags |= TEXDISPLAY_UINT_TEX; + srvOffset = 10; + intIdx = 1; + } + if(IsIntFormat(fmt)) + { + cdata.HistogramFlags |= TEXDISPLAY_SINT_TEX; + srvOffset = 20; + intIdx = 2; + } + + if(details.texType == eTexType_3D) + cdata.HistogramSlice = float(sliceFace)/float(details.texDepth); + + ID3D11Buffer *cbuf = MakeCBuffer((float *)&cdata, sizeof(cdata)); + + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL); + + m_pImmediateContext->CSSetConstantBuffers(0, 1, &cbuf); + + ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { NULL }; + uavs[intIdx] = m_DebugRender.tileResultUAV[intIdx]; + m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, NULL); + + m_pImmediateContext->CSSetShaderResources(srvOffset, eTexType_Max, details.srv); + + ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState }; + m_pImmediateContext->CSSetSamplers(0, 2, samps); + + m_pImmediateContext->CSSetShader(m_DebugRender.TileMinMaxCS[details.texType][intIdx], NULL, 0); + + int blocksX = (int)ceil(cdata.HistogramTextureResolution.x/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + int blocksY = (int)ceil(cdata.HistogramTextureResolution.y/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE)); + + m_pImmediateContext->Dispatch(blocksX, blocksY, 1); + + m_pImmediateContext->CSSetUnorderedAccessViews(intIdx, 1, &m_DebugRender.resultUAV[intIdx], NULL); + m_pImmediateContext->CSSetShaderResources(intIdx, 1, &m_DebugRender.tileResultSRV[intIdx]); + + m_pImmediateContext->CSSetShader(m_DebugRender.ResultMinMaxCS[intIdx], NULL, 0); + + m_pImmediateContext->Dispatch(1, 1, 1); + + m_pImmediateContext->CopyResource(m_DebugRender.resultStageBuff, m_DebugRender.resultBuff); + + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->Map(m_DebugRender.resultStageBuff, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map minmax results buffer %08x", hr); + } + else + { + Vec4f *minmax = (Vec4f *)mapped.pData; + + minval[0] = minmax[0].x; + minval[1] = minmax[0].y; + minval[2] = minmax[0].z; + minval[3] = minmax[0].w; + + maxval[0] = minmax[1].x; + maxval[1] = minmax[1].y; + maxval[2] = minmax[1].z; + maxval[3] = minmax[1].w; + + m_pImmediateContext->Unmap(m_DebugRender.resultStageBuff, 0); + } + + /* + // debugging - copy out tile results + const uint32_t maxTexDim = 16384; + const uint32_t blockPixSize = HGRAM_TILES_PER_BLOCK*HGRAM_PIXELS_PER_TILE; + const uint32_t maxBlocksNeeded = (maxTexDim*maxTexDim)/(blockPixSize*blockPixSize); + + D3D11_BUFFER_DESC bdesc; + bdesc.BindFlags = 0; + bdesc.Usage = D3D11_USAGE_STAGING; + bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bdesc.MiscFlags = 0; + bdesc.StructureByteStride = 0; + bdesc.ByteWidth = 2*4*sizeof(float)*HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK*maxBlocksNeeded; + + ID3D11Buffer *test = NULL; + + m_pDevice->CreateBuffer(&bdesc, NULL, &test); + + m_pImmediateContext->CopyResource(test, m_DebugRender.tileResultBuff); + + m_pImmediateContext->Map(test, 0, D3D11_MAP_READ, 0, &mapped); + + m_pImmediateContext->Unmap(test, 0); + + SAFE_RELEASE(test); + */ + + return true; +} + +vector D3D11DebugManager::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) +{ + ID3D11Buffer *buffer = WrappedID3D11Buffer::m_BufferList[buff].m_Buffer; + + RDCASSERT(buffer); + + return GetBufferData(buffer, offset, len); +} + +vector D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint32_t offset, uint32_t len) +{ + D3D11_MAPPED_SUBRESOURCE mapped; + + if(buffer == NULL) + return vector(); + + D3D11_BUFFER_DESC desc; + buffer->GetDesc(&desc); + + if(len > 0 && offset+len > desc.ByteWidth) + { + RDCWARN("Attempting to read off the end of the array. Will be clamped"); + len = RDCMIN(len, desc.ByteWidth-offset); + } + else if(len == 0) + { + len = desc.ByteWidth; + } + + uint32_t outOffs = 0; + + vector ret; + + ret.resize(len); + + D3D11_BOX box; + box.top = 0; + box.bottom = 1; + box.front = 0; + box.back = 1; + + ID3D11Buffer *src = UNWRAP(WrappedID3D11Buffer, buffer); + + while(len > 0) + { + uint32_t chunkSize = RDCMIN(len, STAGE_BUFFER_BYTE_SIZE); + + if(desc.StructureByteStride > 0) + chunkSize -= (chunkSize % desc.StructureByteStride); + + box.left = RDCMIN(offset + outOffs, desc.ByteWidth); + box.right = RDCMIN(offset + outOffs + chunkSize, desc.ByteWidth); + + if(box.right-box.left == 0) + break; + + m_pImmediateContext->CopySubresourceRegion(m_DebugRender.StageBuffer, 0, 0, 0, 0, src, 0, &box); + + HRESULT hr = m_pImmediateContext->Map(m_DebugRender.StageBuffer, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map bufferdata buffer %08x", hr); + return ret; + } + else + { + memcpy(&ret[outOffs], mapped.pData, RDCMIN(len, STAGE_BUFFER_BYTE_SIZE)); + + m_pImmediateContext->Unmap(m_DebugRender.StageBuffer, 0); + } + + outOffs += chunkSize; + len -= chunkSize; + } + + return ret; +} + +void D3D11DebugManager::CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Texture2D *srcArray) +{ + D3D11RenderStateTracker tracker(m_WrappedContext); + + // copy to textures with right bind flags for operation + D3D11_TEXTURE2D_DESC descArr; + srcArray->GetDesc(&descArr); + + D3D11_TEXTURE2D_DESC descMS; + destMS->GetDesc(&descMS); + + bool depth = IsDepthFormat(descMS.Format); + + ID3D11Texture2D *rtvResource = NULL; + ID3D11Texture2D *srvResource = NULL; + + D3D11_TEXTURE2D_DESC rtvResDesc = descMS; + D3D11_TEXTURE2D_DESC srvResDesc = descArr; + + rtvResDesc.BindFlags = depth ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET; + srvResDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + if(depth) + { + rtvResDesc.Format = GetTypelessFormat(rtvResDesc.Format); + srvResDesc.Format = GetTypelessFormat(srvResDesc.Format); + } + + rtvResDesc.Usage = D3D11_USAGE_DEFAULT; + srvResDesc.Usage = D3D11_USAGE_DEFAULT; + + rtvResDesc.CPUAccessFlags = 0; + srvResDesc.CPUAccessFlags = 0; + + HRESULT hr = S_OK; + + hr = m_pDevice->CreateTexture2D(&rtvResDesc, NULL, &rtvResource); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + hr = m_pDevice->CreateTexture2D(&srvResDesc, NULL, &srvResource); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + m_pImmediateContext->CopyResource(srvResource, srcArray); + + ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { NULL }; + UINT uavCounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 }; + + m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, uavCounts); + + m_pImmediateContext->VSSetShader(m_DebugRender.FullscreenVS, NULL, 0); + m_pImmediateContext->PSSetShader(depth ? m_DebugRender.DepthCopyArrayToMSPS : m_DebugRender.CopyArrayToMSPS, NULL, 0); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + D3D11_VIEWPORT view = { 0.0f, 0.0f, (float)descArr.Width, (float)descArr.Height, 0.0f, 1.0f }; + + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + m_pImmediateContext->RSSetViewports(1, &view); + + m_pImmediateContext->IASetInputLayout(NULL); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + float blendFactor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + m_pImmediateContext->OMSetBlendState(NULL, blendFactor, ~0U); + + if(depth) + { + D3D11_DEPTH_STENCIL_DESC dsDesc; + ID3D11DepthStencilState *dsState = NULL; + RDCEraseEl(dsDesc); + + dsDesc.DepthEnable = TRUE; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + dsDesc.StencilEnable = FALSE; + + dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff; + + m_pDevice->CreateDepthStencilState(&dsDesc, &dsState); + m_pImmediateContext->OMSetDepthStencilState(dsState, 0); + SAFE_RELEASE(dsState); + } + + ID3D11DepthStencilView *dsvMS = NULL; + ID3D11RenderTargetView *rtvMS = NULL; + ID3D11ShaderResourceView *srvArray = NULL; + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtvDesc.Format = depth ? GetUIntTypedFormat(descMS.Format) : GetTypedFormatUIntPreferred(descMS.Format); + rtvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize; + rtvDesc.Texture2DMSArray.FirstArraySlice = 0; + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; + dsvDesc.Flags = 0; + dsvDesc.Format = GetDepthTypedFormat(descMS.Format); + dsvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize; + dsvDesc.Texture2DMSArray.FirstArraySlice = 0; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Format = depth ? GetUIntTypedFormat(descArr.Format) : GetTypedFormatUIntPreferred(descArr.Format); + srvDesc.Texture2DArray.ArraySize = descArr.ArraySize; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.MipLevels = descArr.MipLevels; + srvDesc.Texture2DArray.MostDetailedMip = 0; + + bool stencil = false; + DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN; + + if(depth) + { + switch(descArr.Format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + break; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_TYPELESS: + srvDesc.Format = DXGI_FORMAT_R16_FLOAT; + break; + } + } + + hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvArray); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + ID3D11ShaderResourceView *srvs[8] = { NULL }; + srvs[0] = srvArray; + + m_pImmediateContext->PSSetShaderResources(0, D3D11_PS_CS_UAV_REGISTER_COUNT, srvs); + + // loop over every array slice in MS texture + for(UINT slice=0; slice < descMS.ArraySize; slice++) + { + uint32_t cdata[4] = { descMS.SampleDesc.Count, 1000, 0, slice}; + + ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf); + + rtvDesc.Texture2DMSArray.FirstArraySlice = slice; + rtvDesc.Texture2DMSArray.ArraySize = 1; + dsvDesc.Texture2DMSArray.FirstArraySlice = slice; + dsvDesc.Texture2DMSArray.ArraySize = 1; + + if(depth) + hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvMS); + else + hr = m_pDevice->CreateRenderTargetView(rtvResource, &rtvDesc, &rtvMS); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + if(depth) + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvMS, 0, 0, NULL, NULL); + else + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtvMS, NULL, 0, 0, NULL, NULL); + + m_pImmediateContext->Draw(3, 0); + + SAFE_RELEASE(rtvMS); + SAFE_RELEASE(dsvMS); + } + + SAFE_RELEASE(srvArray); + + if(stencil) + { + srvDesc.Format = stencilFormat; + + hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvArray); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + m_pImmediateContext->PSSetShaderResources(1, 1, &srvArray); + + D3D11_DEPTH_STENCIL_DESC dsDesc; + ID3D11DepthStencilState *dsState = NULL; + RDCEraseEl(dsDesc); + + dsDesc.DepthEnable = FALSE; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.StencilEnable = TRUE; + + dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff; + + dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH; + dsvDesc.Texture2DArray.ArraySize = 1; + + m_pDevice->CreateDepthStencilState(&dsDesc, &dsState); + + // loop over every array slice in MS texture + for(UINT slice=0; slice < descMS.ArraySize; slice++) + { + dsvDesc.Texture2DMSArray.FirstArraySlice = slice; + + hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvMS); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvMS, 0, 0, NULL, NULL); + + // loop over every stencil value (zzzzzz, no shader stencil read/write) + for(UINT stencil=0; stencil < 256; stencil++) + { + uint32_t cdata[4] = { descMS.SampleDesc.Count, stencil, 0, slice}; + + ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf); + + m_pImmediateContext->OMSetDepthStencilState(dsState, stencil); + + m_pImmediateContext->Draw(3, 0); + } + + SAFE_RELEASE(dsvMS); + } + + SAFE_RELEASE(dsState); + } + + m_pImmediateContext->CopyResource(destMS, rtvResource); + + SAFE_RELEASE(rtvResource); + SAFE_RELEASE(srvResource); +} + +void D3D11DebugManager::CopyTex2DMSToArray(ID3D11Texture2D *destArray, ID3D11Texture2D *srcMS) +{ + D3D11RenderStateTracker tracker(m_WrappedContext); + + // copy to textures with right bind flags for operation + D3D11_TEXTURE2D_DESC descMS; + srcMS->GetDesc(&descMS); + + D3D11_TEXTURE2D_DESC descArr; + destArray->GetDesc(&descArr); + + ID3D11Texture2D *rtvResource = NULL; + ID3D11Texture2D *srvResource = NULL; + + D3D11_TEXTURE2D_DESC rtvResDesc = descArr; + D3D11_TEXTURE2D_DESC srvResDesc = descMS; + + bool depth = IsDepthFormat(descMS.Format); + + rtvResDesc.BindFlags = depth ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET; + srvResDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + if(depth) + { + rtvResDesc.Format = GetTypelessFormat(rtvResDesc.Format); + srvResDesc.Format = GetTypelessFormat(srvResDesc.Format); + } + + rtvResDesc.Usage = D3D11_USAGE_DEFAULT; + srvResDesc.Usage = D3D11_USAGE_DEFAULT; + + rtvResDesc.CPUAccessFlags = 0; + srvResDesc.CPUAccessFlags = 0; + + HRESULT hr = S_OK; + + hr = m_pDevice->CreateTexture2D(&rtvResDesc, NULL, &rtvResource); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + hr = m_pDevice->CreateTexture2D(&srvResDesc, NULL, &srvResource); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + m_pImmediateContext->CopyResource(srvResource, srcMS); + + ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { NULL }; + UINT uavCounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 }; + + m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, uavCounts); + + m_pImmediateContext->VSSetShader(m_DebugRender.FullscreenVS, NULL, 0); + m_pImmediateContext->PSSetShader(depth ? m_DebugRender.DepthCopyMSToArrayPS : m_DebugRender.CopyMSToArrayPS, NULL, 0); + + m_pImmediateContext->IASetInputLayout(NULL); + float blendFactor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + m_pImmediateContext->OMSetBlendState(NULL, blendFactor, ~0U); + + if(depth) + { + D3D11_DEPTH_STENCIL_DESC dsDesc; + ID3D11DepthStencilState *dsState = NULL; + RDCEraseEl(dsDesc); + + dsDesc.DepthEnable = TRUE; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + dsDesc.StencilEnable = FALSE; + + dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff; + + m_pDevice->CreateDepthStencilState(&dsDesc, &dsState); + m_pImmediateContext->OMSetDepthStencilState(dsState, 0); + SAFE_RELEASE(dsState); + } + + ID3D11RenderTargetView *rtvArray = NULL; + ID3D11DepthStencilView *dsvArray = NULL; + ID3D11ShaderResourceView *srvMS = NULL; + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Format = depth ? GetUIntTypedFormat(descArr.Format) : GetTypedFormatUIntPreferred(descArr.Format); + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = 1; + rtvDesc.Texture2DArray.MipSlice = 0; + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Format = GetDepthTypedFormat(descArr.Format); + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.FirstArraySlice = 0; + dsvDesc.Texture2DArray.ArraySize = 1; + dsvDesc.Texture2DArray.MipSlice = 0; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + srvDesc.Format = depth ? GetUIntTypedFormat(descMS.Format) : GetTypedFormatUIntPreferred(descMS.Format); + srvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize; + srvDesc.Texture2DMSArray.FirstArraySlice = 0; + + bool stencil = false; + DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN; + + if(depth) + { + switch(descMS.Format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + break; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_TYPELESS: + srvDesc.Format = DXGI_FORMAT_R16_FLOAT; + break; + } + } + + hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvMS); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + ID3D11ShaderResourceView *srvs[8] = { NULL }; + + int srvIndex = 0; + + for(int i=0; i < 8; i++) + if(descMS.SampleDesc.Count == UINT(1<PSSetShaderResources(0, D3D11_PS_CS_UAV_REGISTER_COUNT, srvs); + + // loop over every array slice in MS texture + for(UINT slice=0; slice < descMS.ArraySize; slice++) + { + // loop over every multi sample + for(UINT sample=0; sample < descMS.SampleDesc.Count; sample++) + { + uint32_t cdata[4] = { descMS.SampleDesc.Count, 1000, sample, slice}; + + ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf); + + rtvDesc.Texture2DArray.FirstArraySlice = slice*descMS.SampleDesc.Count + sample; + dsvDesc.Texture2DArray.FirstArraySlice = slice*descMS.SampleDesc.Count + sample; + + if(depth) + hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvArray); + else + hr = m_pDevice->CreateRenderTargetView(rtvResource, &rtvDesc, &rtvArray); + + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + if(depth) + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvArray, 0, 0, NULL, NULL); + else + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtvArray, NULL, 0, 0, NULL, NULL); + + m_pImmediateContext->Draw(3, 0); + + SAFE_RELEASE(rtvArray); + SAFE_RELEASE(dsvArray); + } + } + + SAFE_RELEASE(srvMS); + + if(stencil) + { + srvDesc.Format = stencilFormat; + + hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvMS); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + m_pImmediateContext->PSSetShaderResources(10+srvIndex, 1, &srvMS); + + D3D11_DEPTH_STENCIL_DESC dsDesc; + ID3D11DepthStencilState *dsState = NULL; + RDCEraseEl(dsDesc); + + dsDesc.DepthEnable = FALSE; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.StencilEnable = TRUE; + + dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff; + + dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH; + dsvDesc.Texture2DArray.ArraySize = 1; + + m_pDevice->CreateDepthStencilState(&dsDesc, &dsState); + + // loop over every array slice in MS texture + for(UINT slice=0; slice < descMS.ArraySize; slice++) + { + // loop over every multi sample + for(UINT sample=0; sample < descMS.SampleDesc.Count; sample++) + { + dsvDesc.Texture2DArray.FirstArraySlice = slice*descMS.SampleDesc.Count + sample; + + hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvArray); + if(FAILED(hr)) + { + RDCERR("0x%08x", hr); + return; + } + + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvArray, 0, 0, NULL, NULL); + + // loop over every stencil value (zzzzzz, no shader stencil read/write) + for(UINT stencil=0; stencil < 256; stencil++) + { + uint32_t cdata[4] = { descMS.SampleDesc.Count, stencil, sample, slice}; + + ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf); + + m_pImmediateContext->OMSetDepthStencilState(dsState, stencil); + + m_pImmediateContext->Draw(3, 0); + } + + SAFE_RELEASE(dsvArray); + } + } + + SAFE_RELEASE(dsState); + } + + m_pImmediateContext->CopyResource(destArray, rtvResource); + + SAFE_RELEASE(rtvResource); + SAFE_RELEASE(srvResource); +} + +D3D11DebugManager::CacheElem &D3D11DebugManager::GetCachedElem(ResourceId id, bool raw) +{ + for(auto it=m_ShaderItemCache.begin(); it != m_ShaderItemCache.end(); ++it) + { + if(it->id == id && it->raw == raw) + return *it; + } + + if(m_ShaderItemCache.size() >= NUM_CACHED_SRVS) + { + CacheElem &elem = m_ShaderItemCache.back(); + elem.Release(); + m_ShaderItemCache.pop_back(); + } + + m_ShaderItemCache.push_front(CacheElem(id, raw)); + return m_ShaderItemCache.front(); +} + +D3D11DebugManager::TextureShaderDetails D3D11DebugManager::GetShaderDetails(ResourceId id, bool rawOutput) +{ + TextureShaderDetails details; + HRESULT hr = S_OK; + + bool foundResource = false; + + CacheElem &cache = GetCachedElem(id, rawOutput); + + bool msaaDepth = false; + + bool cube = false; + DXGI_FORMAT srvFormat = DXGI_FORMAT_UNKNOWN; + + if(WrappedID3D11Texture1D::m_TextureList.find(id) != WrappedID3D11Texture1D::m_TextureList.end()) + { + WrappedID3D11Texture1D *wrapTex1D = (WrappedID3D11Texture1D *)WrappedID3D11Texture1D::m_TextureList[id].m_Texture; + TextureDisplayType mode = WrappedID3D11Texture1D::m_TextureList[id].m_Type; + + foundResource = true; + + details.texType = eTexType_1D; + + if(mode == TEXDISPLAY_DEPTH_TARGET) + details.texType = eTexType_Depth; + + D3D11_TEXTURE1D_DESC desc1d = {0}; + wrapTex1D->GetDesc(&desc1d); + + details.texFmt = desc1d.Format; + details.texWidth = desc1d.Width; + details.texHeight = 1; + details.texDepth = 1; + details.texArraySize = desc1d.ArraySize; + details.texMips = desc1d.MipLevels; + + srvFormat = GetTypedFormat(details.texFmt); + + details.srvResource = wrapTex1D->GetReal(); + + if(mode == TEXDISPLAY_INDIRECT_VIEW || + mode == TEXDISPLAY_DEPTH_TARGET) + { + D3D11_TEXTURE1D_DESC desc = desc1d; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + + if(mode == TEXDISPLAY_DEPTH_TARGET) + desc.Format = GetTypelessFormat(desc.Format); + + if(!cache.created) + { + ID3D11Texture1D *tmp = NULL; + hr = m_pDevice->CreateTexture1D(&desc, NULL, &tmp); + + if(FAILED(hr)) + { + RDCERR("Failed to create temporary Texture1D %08x", hr); + } + + cache.srvResource = tmp; + } + + details.previewCopy = cache.srvResource; + + m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource); + + details.srvResource = details.previewCopy; + } + } + else if(WrappedID3D11Texture2D::m_TextureList.find(id) != WrappedID3D11Texture2D::m_TextureList.end()) + { + WrappedID3D11Texture2D *wrapTex2D = (WrappedID3D11Texture2D *)WrappedID3D11Texture2D::m_TextureList[id].m_Texture; + TextureDisplayType mode = WrappedID3D11Texture2D::m_TextureList[id].m_Type; + + foundResource = true; + + details.texType = eTexType_2D; + + D3D11_TEXTURE2D_DESC desc2d = {0}; + wrapTex2D->GetDesc(&desc2d); + + if(desc2d.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) + cube = true; + + details.texFmt = desc2d.Format; + details.texWidth = desc2d.Width; + details.texHeight = desc2d.Height; + details.texDepth = 1; + details.texArraySize = desc2d.ArraySize; + details.texMips = desc2d.MipLevels; + details.sampleCount = desc2d.SampleDesc.Count; + details.sampleQuality = desc2d.SampleDesc.Quality; + + if(mode == TEXDISPLAY_DEPTH_TARGET || IsDepthFormat(details.texFmt)) + { + details.texType = eTexType_Depth; + details.texFmt = GetTypedFormat(details.texFmt); + } + + // backbuffer is always interpreted as SRGB data regardless of format specified: + // http://msdn.microsoft.com/en-us/library/windows/desktop/hh972627(v=vs.85).aspx + // + // "The app must always place sRGB data into back buffers with integer-valued formats + // to present the sRGB data to the screen, even if the data doesn't have this format + // modifier in its format name." + // + // This essentially corrects for us always declaring an SRGB render target for our + // output displays, as any app with a non-SRGB backbuffer would be incorrectly converted + // unless we read out SRGB here. + // + // However when picking a pixel we want the actual value stored, not the corrected perceptual + // value so for raw output we don't do this. This does my head in, it really does. + if(wrapTex2D->m_RealDescriptor) + { + if(rawOutput) + details.texFmt = wrapTex2D->m_RealDescriptor->Format; + else + details.texFmt = GetSRGBFormat(wrapTex2D->m_RealDescriptor->Format); + } + + srvFormat = GetTypedFormat(details.texFmt); + + details.srvResource = wrapTex2D->GetReal(); + + if(mode == TEXDISPLAY_INDIRECT_VIEW || + mode == TEXDISPLAY_DEPTH_TARGET || + desc2d.SampleDesc.Count > 1 || desc2d.SampleDesc.Quality > 0) + { + D3D11_TEXTURE2D_DESC desc = desc2d; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + + if(mode == TEXDISPLAY_DEPTH_TARGET) + { + desc.Format = GetTypelessFormat(desc.Format); + } + else + { + desc.Format = srvFormat; + + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + } + + if(!cache.created) + { + ID3D11Texture2D *tmp = NULL; + hr = m_pDevice->CreateTexture2D(&desc, NULL, &tmp); + + if(FAILED(hr)) + { + RDCERR("Failed to create temporary Texture2D %08x", hr); + } + + cache.srvResource = tmp; + } + + details.previewCopy = cache.srvResource; + + if(desc2d.SampleDesc.Count > 1 || desc2d.SampleDesc.Quality > 0) + { + if(mode == TEXDISPLAY_DEPTH_TARGET) + { + msaaDepth = true; + m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource); + } + else + { + for(UINT sub=0; sub < desc.MipLevels*desc.ArraySize; sub++) + m_pImmediateContext->ResolveSubresource(details.previewCopy, sub, details.srvResource, sub, srvFormat); + } + } + else + { + m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource); + } + + details.srvResource = details.previewCopy; + } + } + else if(WrappedID3D11Texture3D::m_TextureList.find(id) != WrappedID3D11Texture3D::m_TextureList.end()) + { + WrappedID3D11Texture3D *wrapTex3D = (WrappedID3D11Texture3D *)WrappedID3D11Texture3D::m_TextureList[id].m_Texture; + TextureDisplayType mode = WrappedID3D11Texture3D::m_TextureList[id].m_Type; + + foundResource = true; + + details.texType = eTexType_3D; + + D3D11_TEXTURE3D_DESC desc3d = {0}; + wrapTex3D->GetDesc(&desc3d); + + details.texFmt = desc3d.Format; + details.texWidth = desc3d.Width; + details.texHeight = desc3d.Height; + details.texDepth = desc3d.Depth; + details.texArraySize = 1; + details.texMips = desc3d.MipLevels; + + srvFormat = GetTypedFormat(details.texFmt); + + details.srvResource = wrapTex3D->GetReal(); + + if(mode == TEXDISPLAY_INDIRECT_VIEW) + { + D3D11_TEXTURE3D_DESC desc = desc3d; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + + if(IsUIntFormat(srvFormat) || IsIntFormat(srvFormat)) + desc.Format = GetTypelessFormat(desc.Format); + + if(!cache.created) + { + ID3D11Texture3D *tmp = NULL; + hr = m_pDevice->CreateTexture3D(&desc, NULL, &tmp); + + if(FAILED(hr)) + { + RDCERR("Failed to create temporary Texture3D %08x", hr); + } + + cache.srvResource = tmp; + } + + details.previewCopy = cache.srvResource; + + m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource); + + details.srvResource = details.previewCopy; + } + } + + if(!foundResource) + { + RDCERR("bad texture trying to be displayed"); + return TextureShaderDetails(); + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc[eTexType_Max]; + + srvDesc[eTexType_1D].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; + srvDesc[eTexType_1D].Texture1DArray.ArraySize = details.texArraySize; + srvDesc[eTexType_1D].Texture1DArray.FirstArraySlice = 0; + srvDesc[eTexType_1D].Texture1DArray.MipLevels = details.texMips; + srvDesc[eTexType_1D].Texture1DArray.MostDetailedMip = 0; + + srvDesc[eTexType_2D].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc[eTexType_2D].Texture2DArray.ArraySize = details.texArraySize; + srvDesc[eTexType_2D].Texture2DArray.FirstArraySlice = 0; + srvDesc[eTexType_2D].Texture2DArray.MipLevels = details.texMips; + srvDesc[eTexType_2D].Texture2DArray.MostDetailedMip = 0; + + srvDesc[eTexType_Stencil] = srvDesc[eTexType_Depth] = srvDesc[eTexType_2D]; + + srvDesc[eTexType_3D].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc[eTexType_3D].Texture3D.MipLevels = details.texMips; + srvDesc[eTexType_3D].Texture3D.MostDetailedMip = 0; + + srvDesc[eTexType_Cube].ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; + srvDesc[eTexType_Cube].TextureCubeArray.First2DArrayFace = 0; + srvDesc[eTexType_Cube].TextureCubeArray.MipLevels = details.texMips; + srvDesc[eTexType_Cube].TextureCubeArray.MostDetailedMip = 0; + srvDesc[eTexType_Cube].TextureCubeArray.NumCubes = RDCMAX(1U, details.texArraySize/6); + + for(int i=0; i < eTexType_Max; i++) + srvDesc[i].Format = srvFormat; + + if(details.texType == eTexType_Depth) + { + switch(details.texFmt) + { + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + { + srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + break; + } + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + { + srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R32_FLOAT; + srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_UNKNOWN; + break; + } + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + { + srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + break; + } + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UINT: + { + srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R16_UNORM; + srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_UNKNOWN; + break; + } + default: + break; + } + } + + if(msaaDepth) + { + srvDesc[eTexType_Stencil].ViewDimension = + srvDesc[eTexType_Depth].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + + srvDesc[eTexType_Depth].Texture2DMSArray.ArraySize = srvDesc[eTexType_2D].Texture2DArray.ArraySize; + srvDesc[eTexType_Stencil].Texture2DMSArray.ArraySize = srvDesc[eTexType_2D].Texture2DArray.ArraySize; + srvDesc[eTexType_Depth].Texture2DMSArray.FirstArraySlice = srvDesc[eTexType_2D].Texture2DArray.FirstArraySlice; + srvDesc[eTexType_Stencil].Texture2DMSArray.FirstArraySlice = srvDesc[eTexType_2D].Texture2DArray.FirstArraySlice; + } + + if(!cache.created) + { + hr = m_pDevice->CreateShaderResourceView(details.srvResource, &srvDesc[details.texType], &cache.srv[0]); + + if(FAILED(hr)) + RDCERR("Failed to create cache SRV 0, type %d %08x", details.texType, hr); + } + + details.srv[details.texType] = cache.srv[0]; + + if(details.texType == eTexType_Depth && srvDesc[eTexType_Stencil].Format != DXGI_FORMAT_UNKNOWN) + { + if(!cache.created) + { + hr = m_pDevice->CreateShaderResourceView(details.srvResource, &srvDesc[eTexType_Stencil], &cache.srv[1]); + + if(FAILED(hr)) + RDCERR("Failed to create cache SRV 1, type %d %08x", details.texType, hr); + } + + details.srv[eTexType_Stencil] = cache.srv[1]; + + details.texType = eTexType_Stencil; + } + + if(msaaDepth) + { + if(details.texType == eTexType_Depth) + details.texType = eTexType_DepthMS; + if(details.texType == eTexType_Stencil) + details.texType = eTexType_StencilMS; + + details.srv[eTexType_Depth] = NULL; + details.srv[eTexType_Stencil] = NULL; + details.srv[eTexType_DepthMS] = cache.srv[0]; + details.srv[eTexType_StencilMS] = cache.srv[1]; + } + + if((details.texType == eTexType_2D || + details.texType == eTexType_Depth || + details.texType == eTexType_Stencil) + && cube) + { + if(!cache.created) + { + hr = m_pDevice->CreateShaderResourceView(details.srvResource, &srvDesc[eTexType_Cube], &cache.srv[2]); + + if(FAILED(hr)) + RDCERR("Failed to create cache SRV 2 %08x", hr); + } + + details.srv[eTexType_Cube] = cache.srv[2]; + } + + cache.created = true; + + return details; +} + +void D3D11DebugManager::RenderText(float x, float y, float size, const char *textfmt, ...) +{ + static char tmpBuf[4096]; + + va_list args; + va_start(args, textfmt); + StringFormat::vsnprintf( tmpBuf, 4095, textfmt, args ); + tmpBuf[4095] = '\0'; + va_end(args); + + // normalize size to 720 (and scale respectively) + // invert y co-ordinates for convenience + RenderTextInternal(x, -y, size*(720.0f/float(GetHeight())), tmpBuf); +} + +void D3D11DebugManager::RenderTextInternal(float x, float y, float size, const char *text) +{ + if(char *t = strchr((char *)text, '\n')) + { + *t = 0; + RenderTextInternal(x, y, size, text); + RenderTextInternal(x, y-18.0f, size, t+1); + *t = '\n'; + return; + } + + if(strlen(text) == 0) + return; + + RDCASSERT(strlen(text) < FONT_MAX_CHARS); + + FontCBuffer data; + + data.TextPosition.x = x*(2.0f/float(GetWidth())); + data.TextPosition.y = y*(2.0f/float(GetHeight())); + + data.FontScreenAspect.x = (float(GetHeight())/float(GetWidth()))*0.5f; // 0.5 = character width / character height + data.FontScreenAspect.y = 1.0f; + + data.CharacterSize.x = 0.5f*(float(FONT_TEX_HEIGHT)/float(FONT_TEX_WIDTH)); + data.CharacterSize.y = 1.0f; + + data.TextSize = size*0.05f; // default arbitrary font size + + data.CharacterOffsetX = 0.75f*(float(FONT_TEX_HEIGHT)/float(FONT_TEX_WIDTH)); + + D3D11_MAPPED_SUBRESOURCE mapped; + + FillCBuffer(m_Font.CBuffer, (float *)&data, sizeof(FontCBuffer)); + + HRESULT hr = m_pImmediateContext->Map(m_Font.CharBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map charbuffer %08x", hr); + return; + } + + unsigned long *texs = (unsigned long *)mapped.pData; + + for(size_t i=0; i < strlen(text); i++) + { + texs[i*4 + 0] = text[i] - ' '; + texs[i*4 + 1] = text[i] - ' '; + texs[i*4 + 2] = text[i] - ' '; + texs[i*4 + 3] = text[i] - ' '; + } + m_pImmediateContext->Unmap(m_Font.CharBuffer, 0); + + ID3D11Buffer *bufs[2] = { m_DebugRender.PosBuffer, m_Font.CharBuffer }; + UINT strides[2] = { 3*sizeof(float), sizeof(long) }; + UINT offsets[2] = { 0, 0 }; + + // can't just clear state because we need to keep things like render targets. + { + m_pImmediateContext->IASetInputLayout(m_Font.Layout); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_pImmediateContext->IASetVertexBuffers(0, 2, bufs, strides, offsets); + + m_pImmediateContext->VSSetShader(m_Font.VS, NULL, 0); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_Font.CBuffer); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + + D3D11_VIEWPORT view; + view.TopLeftX = 0; + view.TopLeftY = 0; + view.Width = (float)GetWidth(); + view.Height = (float)GetHeight(); + view.MinDepth = 0.0f; + view.MaxDepth = 1.0f; + m_pImmediateContext->RSSetViewports(1, &view); + + m_pImmediateContext->PSSetShader(m_Font.PS, NULL, 0); + m_pImmediateContext->PSSetShaderResources(0, 1, &m_Font.Tex); + + ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState }; + m_pImmediateContext->PSSetSamplers(0, 2, samps); + + float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + m_pImmediateContext->OMSetBlendState(m_DebugRender.BlendState, factor, 0xffffffff); + + m_pImmediateContext->Draw((uint32_t)strlen(text)*4, 0); + } +} + +bool D3D11DebugManager::RenderTexture(TextureDisplay cfg) +{ + DebugVertexCBuffer vertexData; + DebugPixelCBufferData pixelData; + + float x = cfg.offx; + float y = cfg.offy; + + vertexData.Position.x = x*(2.0f/float(GetWidth())); + vertexData.Position.y = -y*(2.0f/float(GetHeight())); + + vertexData.ScreenAspect.x = (float(GetHeight())/float(GetWidth())); // 0.5 = character width / character height + vertexData.ScreenAspect.y = 1.0f; + + vertexData.TextureResolution.x = 1.0f/vertexData.ScreenAspect.x; + vertexData.TextureResolution.y = 1.0f; + + if(cfg.rangemax <= cfg.rangemin) cfg.rangemax += 0.00001f; + + pixelData.Channels.x = cfg.Red ? 1.0f : 0.0f; + pixelData.Channels.y = cfg.Green ? 1.0f : 0.0f; + pixelData.Channels.z = cfg.Blue ? 1.0f : 0.0f; + pixelData.Channels.w = cfg.Alpha ? 1.0f : 0.0f; + + pixelData.RangeMinimum = cfg.rangemin; + pixelData.InverseRangeSize = 1.0f/(cfg.rangemax-cfg.rangemin); + + pixelData.WireframeColour.x = cfg.HDRMul; + + pixelData.RawOutput = cfg.rawoutput ? 1 : 0; + + TextureShaderDetails details = GetShaderDetails(cfg.texid, cfg.rawoutput ? true : false); + + if(details.texFmt == DXGI_FORMAT_UNKNOWN) + return false; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + if(details.texFmt == DXGI_FORMAT_A8_UNORM && cfg.scale <= 0.0f) + { + pixelData.Channels.x = pixelData.Channels.y = pixelData.Channels.z = 0.0f; + pixelData.Channels.w = 1.0f; + } + + float tex_x = float(details.texWidth); + float tex_y = float(details.texType == eTexType_1D ? 100 : details.texHeight); + + vertexData.TextureResolution.x *= tex_x/float(GetWidth()); + vertexData.TextureResolution.y *= tex_y/float(GetHeight()); + + pixelData.TextureResolutionPS.x = float(RDCMAX(1U,details.texWidth>>cfg.mip)); + pixelData.TextureResolutionPS.y = float(RDCMAX(1U,details.texHeight>>cfg.mip)); + pixelData.TextureResolutionPS.z = float(RDCMAX(1U,details.texDepth>>cfg.mip)); + + if(details.texArraySize > 1 && details.texType != eTexType_3D) + pixelData.TextureResolutionPS.z = float(details.texArraySize); + + vertexData.Scale = cfg.scale; + pixelData.ScalePS = cfg.scale; + + if(cfg.scale <= 0.0f) + { + float xscale = float(GetWidth())/tex_x; + float yscale = float(GetHeight())/tex_y; + + vertexData.Scale = RDCMIN(xscale, yscale); + + if(yscale > xscale) + { + vertexData.Position.x = 0; + vertexData.Position.y = tex_y*vertexData.Scale/float(GetHeight()) - 1.0f; + } + else + { + vertexData.Position.y = 0; + vertexData.Position.x = 1.0f - tex_x*vertexData.Scale/float(GetWidth()); + } + } + + ID3D11PixelShader *customPS = NULL; + ID3D11Buffer *customBuff = NULL; + + if(cfg.CustomShader != ResourceId()) + { + auto it = WrappedShader::m_ShaderList.find(cfg.CustomShader); + + if(it != WrappedShader::m_ShaderList.end()) + { + auto dxbc = it->second.m_DXBCFile; + + RDCASSERT(dxbc); + RDCASSERT(dxbc->m_Type == D3D11_SHVER_PIXEL_SHADER); + + WrappedID3D11Shader *wrapped = (WrappedID3D11Shader *)m_WrappedDevice->GetResourceManager()->GetLiveResource(cfg.CustomShader); + + customPS = wrapped->GetReal(); + + for(size_t i=0; i < dxbc->m_CBuffers.size(); i++) + { + const DXBC::CBuffer &cbuf = dxbc->m_CBuffers[i]; + if(cbuf.name == "$Globals") + { + float *cbufData = new float[cbuf.descriptor.byteSize/sizeof(float) + 1]; + byte *byteData = (byte *)cbufData; + + for(size_t v=0; v < cbuf.variables.size(); v++) + { + const DXBC::CBufferVariable &var = cbuf.variables[v]; + + if(var.name == "RENDERDOC_TexDim") + { + if(var.type.descriptor.rows == 1 && + var.type.descriptor.cols == 4 && + var.type.descriptor.type == DXBC::VARTYPE_UINT) + { + uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); + + d[0] = details.texWidth; + d[1] = details.texHeight; + d[2] = details.texType == D3D11DebugManager::eTexType_3D ? details.texDepth : details.texArraySize; + d[3] = details.texMips; + } + else + { + RDCWARN("Custom shader: Variable recognised but type wrong, expected uint4: %hs", var.name.c_str()); + } + } + else if(var.name == "RENDERDOC_SelectedMip") + { + if(var.type.descriptor.rows == 1 && + var.type.descriptor.cols == 1 && + var.type.descriptor.type == DXBC::VARTYPE_UINT) + { + uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); + + d[0] = cfg.mip; + } + else + { + RDCWARN("Custom shader: Variable recognised but type wrong, expected uint: %hs", var.name.c_str()); + } + } + else if(var.name == "RENDERDOC_TextureType") + { + if(var.type.descriptor.rows == 1 && + var.type.descriptor.cols == 1 && + var.type.descriptor.type == DXBC::VARTYPE_UINT) + { + uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); + + d[0] = details.texType; + } + else + { + RDCWARN("Custom shader: Variable recognised but type wrong, expected uint: %hs", var.name.c_str()); + } + } + else + { + RDCWARN("Custom shader: Variable not recognised: %hs", var.name.c_str()); + } + } + + customBuff = MakeCBuffer(cbufData, cbuf.descriptor.byteSize); + } + } + } + } + + vertexData.Scale *= 2.0f; // viewport is -1 -> 1 + + pixelData.MipLevel = (float)cfg.mip; + + ID3D11Buffer *bufs[2] = { m_DebugRender.PosBuffer, m_Font.CharBuffer }; + UINT stride = 3*sizeof(float); + UINT offset = 0; + + pixelData.OutputDisplayFormat = RESTYPE_TEX2D; + pixelData.Slice = float(RDCCLAMP(cfg.sliceFace, 0U, details.texArraySize-1)); + + if(details.texType == eTexType_3D) + { + pixelData.OutputDisplayFormat = RESTYPE_TEX3D; + pixelData.Slice = float(cfg.sliceFace)/float(details.texDepth); + } + else if(details.texType == eTexType_1D) + { + pixelData.OutputDisplayFormat = RESTYPE_TEX1D; + } + else if(details.texType == eTexType_Depth) + { + pixelData.OutputDisplayFormat = RESTYPE_DEPTH; + } + else if(details.texType == eTexType_Stencil) + { + pixelData.OutputDisplayFormat = RESTYPE_DEPTH_STENCIL; + } + else if(details.texType == eTexType_DepthMS) + { + pixelData.OutputDisplayFormat = RESTYPE_DEPTH_MS; + } + else if(details.texType == eTexType_StencilMS) + { + pixelData.OutputDisplayFormat = RESTYPE_DEPTH_STENCIL_MS; + } + + if(cfg.overlay == eTexOverlay_NaN) + { + pixelData.OutputDisplayFormat |= TEXDISPLAY_NANS; + } + + if(cfg.overlay == eTexOverlay_Clipping) + { + pixelData.OutputDisplayFormat |= TEXDISPLAY_CLIPPING; + } + + int srvOffset = 0; + + if(IsUIntFormat(details.texFmt)) + { + pixelData.OutputDisplayFormat |= TEXDISPLAY_UINT_TEX; + srvOffset = 10; + } + if(IsIntFormat(details.texFmt)) + { + pixelData.OutputDisplayFormat |= TEXDISPLAY_SINT_TEX; + srvOffset = 20; + } + if(!IsSRGBFormat(details.texFmt)) + { + pixelData.OutputDisplayFormat |= TEXDISPLAY_GAMMA_CURVE; + } + + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + // can't just clear state because we need to keep things like render targets. + { + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_DebugRender.PosBuffer, &stride, &offset); + + m_pImmediateContext->VSSetShader(m_DebugRender.GenericVS, NULL, 0); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + + if(customPS == NULL) + { + m_pImmediateContext->PSSetShader(m_DebugRender.TexDisplayPS, NULL, 0); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + } + else + { + m_pImmediateContext->PSSetShader(customPS, NULL, 0); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &customBuff); + } + + ID3D11UnorderedAccessView *NullUAVs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { 0 }; + UINT UAV_keepcounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 }; + + m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, NullUAVs, UAV_keepcounts); + + m_pImmediateContext->PSSetShaderResources(srvOffset, eTexType_Max, details.srv); + + ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState }; + m_pImmediateContext->PSSetSamplers(0, 2, samps); + + float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + if(cfg.rawoutput) + m_pImmediateContext->OMSetBlendState(NULL, factor, 0xffffffff); + else + m_pImmediateContext->OMSetBlendState(m_DebugRender.BlendState, factor, 0xffffffff); + + m_pImmediateContext->Draw(4, 0); + } + + return true; +} + +void D3D11DebugManager::RenderHighlightBox(float w, float h, float scale) +{ + UINT stride = 3*sizeof(float); + UINT offs = 0; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + float overlayConsts[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + + ID3D11Buffer *vconst = NULL; + ID3D11Buffer *pconst = NULL; + + pconst = MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + const float xpixdim = 2.0f/w; + const float ypixdim = 2.0f/h; + + const float xdim = scale*xpixdim; + const float ydim = scale*ypixdim; + + DebugVertexCBuffer vertCBuffer; + RDCEraseEl(vertCBuffer); + vertCBuffer.Scale = 1.0f; + vertCBuffer.ScreenAspect.x = vertCBuffer.ScreenAspect.y = 1.0f; + + vertCBuffer.Position.x = 1.0f; + vertCBuffer.Position.y = -1.0f; + vertCBuffer.TextureResolution.x = xdim; + vertCBuffer.TextureResolution.y = ydim; + + vconst = MakeCBuffer((float *)&vertCBuffer, sizeof(vertCBuffer)); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_DebugRender.OutlineStripVB, &stride, &offs); + + m_pImmediateContext->VSSetShader(m_DebugRender.GenericVS, NULL, 0); + m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0); + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + + m_pImmediateContext->PSSetConstantBuffers(1, 1, &pconst); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &vconst); + + m_pImmediateContext->Draw(5, 0); + + vertCBuffer.Position.x = 1.0f-xpixdim; + vertCBuffer.Position.y = -1.0f+ypixdim; + vertCBuffer.TextureResolution.x = xdim+xpixdim*2; + vertCBuffer.TextureResolution.y = ydim+ypixdim*2; + + overlayConsts[0] = overlayConsts[1] = overlayConsts[2] = 0.0f; + + vconst = MakeCBuffer((float *)&vertCBuffer, sizeof(vertCBuffer)); + pconst = MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + m_pImmediateContext->VSSetConstantBuffers(0, 1, &vconst); + m_pImmediateContext->PSSetConstantBuffers(1, 1, &pconst); + m_pImmediateContext->Draw(5, 0); +} + +void D3D11DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark) +{ + DebugVertexCBuffer vertexData; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + vertexData.Scale = 2.0f; + vertexData.Position.x = vertexData.Position.y = 0; + + vertexData.ScreenAspect.x = 1.0f; + vertexData.ScreenAspect.y = 1.0f; + + vertexData.TextureResolution.x = 1.0f; + vertexData.TextureResolution.y = 1.0f; + + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + + DebugPixelCBufferData pixelData; + + pixelData.Channels = Vec4f(light.x, light.y, light.z, 0.0f); + pixelData.WireframeColour = dark; + + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + UINT stride = 3*sizeof(float); + UINT offset = 0; + + // can't just clear state because we need to keep things like render targets. + { + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_DebugRender.PosBuffer, &stride, &offset); + + m_pImmediateContext->VSSetShader(m_DebugRender.GenericVS, NULL, 0); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + + m_pImmediateContext->PSSetShader(m_DebugRender.CheckerboardPS, NULL, 0); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + m_pImmediateContext->OMSetBlendState(NULL, factor, 0xffffffff); + + m_pImmediateContext->Draw(4, 0); + } +} + +PostVSData D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID) +{ + auto idx = std::make_pair(frameID, eventID); + if(m_PostVSData.find(idx) != m_PostVSData.end()) + return m_PostVSData[idx]; + + RDCWARN("Post VS Buffers not initialised!"); + PostVSData empty; + RDCEraseEl(empty); + return empty; +} + +PostVSMeshData D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +{ + PostVSMeshData ret; + + PostVSData postvs = GetPostVSBuffers(frameID, eventID); + PostVSData::StageData s = postvs.GetStage(stage); + ret.numVerts = s.numVerts; + ret.topo = (PrimitiveTopology)s.topo; + if(s.buf != NULL) + ret.buf = GetBufferData(s.buf, 0, 0); + else + RDCWARN("No buffer for this stage!"); + + return ret; +} + +void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) +{ + auto idx = std::make_pair(frameID, eventID); + if(m_PostVSData.find(idx) != m_PostVSData.end()) + return; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + ID3D11VertexShader *vs = NULL; + m_pImmediateContext->VSGetShader(&vs, NULL, NULL); + + ID3D11GeometryShader *gs = NULL; + m_pImmediateContext->GSGetShader(&gs, NULL, NULL); + + ID3D11HullShader *hs = NULL; + m_pImmediateContext->HSGetShader(&hs, NULL, NULL); + + ID3D11DomainShader *ds = NULL; + m_pImmediateContext->DSGetShader(&ds, NULL, NULL); + + if(vs) vs->Release(); + if(gs) gs->Release(); + if(hs) hs->Release(); + if(ds) ds->Release(); + + if(!vs) + return; + + D3D11_PRIMITIVE_TOPOLOGY topo; + m_pImmediateContext->IAGetPrimitiveTopology(&topo); + + WrappedID3D11Shader *wrappedVS = (WrappedID3D11Shader *)m_WrappedDevice->GetResourceManager()->GetWrapper(vs); + + if(!wrappedVS) + { + RDCERR("Couldn't find wrapped vertex shader!"); + return; + } + + DXBC::DXBCFile *dxbcVS = wrappedVS->GetDXBC(); + + RDCASSERT(dxbcVS); + + DXBC::DXBCFile *dxbcGS = NULL; + + if(gs) + { + WrappedID3D11Shader *wrappedGS = (WrappedID3D11Shader *)m_WrappedDevice->GetResourceManager()->GetWrapper(gs); + + if(!wrappedGS) + { + RDCERR("Couldn't find wrapped geometry shader!"); + return; + } + + dxbcGS = wrappedGS->GetDXBC(); + + RDCASSERT(dxbcGS); + } + + DXBC::DXBCFile *dxbcDS = NULL; + + if(ds) + { + WrappedID3D11Shader *wrappedDS = (WrappedID3D11Shader *)m_WrappedDevice->GetResourceManager()->GetWrapper(ds); + + if(!wrappedDS) + { + RDCERR("Couldn't find wrapped domain shader!"); + return; + } + + dxbcDS = wrappedDS->GetDXBC(); + + RDCASSERT(dxbcDS); + } + + vector sodecls; + + UINT stride = 0; + UINT posoffset = ~0U; + int numPosComponents = 0; + + ID3D11GeometryShader *streamoutGS = NULL; + + if(!dxbcVS->m_OutputSig.empty()) + { + for(size_t i=0; i < dxbcVS->m_OutputSig.size(); i++) + { + SigParameter &sign = dxbcVS->m_OutputSig[i]; + + D3D11_SO_DECLARATION_ENTRY decl; + + decl.Stream = 0; + decl.OutputSlot = 0; + + decl.SemanticName = sign.semanticName.elems; + decl.SemanticIndex = sign.semanticIndex; + decl.StartComponent = 0; + decl.ComponentCount = sign.compCount&0xff; + + string a = strupper(string(decl.SemanticName)); + + if(a.find("POSITION") != string::npos) + { + // force to 4 components, as we need it, and store its offset + if(a.find("SV_POSITION") != string::npos) + decl.ComponentCount = 4; + numPosComponents = decl.ComponentCount; + posoffset = stride; + } + + stride += decl.ComponentCount * sizeof(float); + sodecls.push_back(decl); + } + + HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput( + (void *)&dxbcVS->m_ShaderBlob[0], + dxbcVS->m_ShaderBlob.size(), + &sodecls[0], + (UINT)sodecls.size(), + &stride, + 1, + D3D11_SO_NO_RASTERIZED_STREAM, + NULL, + &streamoutGS); + + if(FAILED(hr)) + { + RDCERR("Failed to create Geometry Shader + SO %08x", hr); + return; + } + + m_pImmediateContext->GSSetShader(streamoutGS, NULL, 0); + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + + SAFE_RELEASE(streamoutGS); + + UINT offset = 0; + m_pImmediateContext->SOSetTargets( 1, &m_SOBuffer, &offset ); + + m_pImmediateContext->Begin(m_SOStatsQuery); + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + m_pImmediateContext->End(m_SOStatsQuery); + + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + m_pImmediateContext->SOSetTargets(0, NULL, NULL); + + D3D11_QUERY_DATA_SO_STATISTICS numPrims; + + m_pImmediateContext->CopyResource(m_SOStagingBuffer, m_SOBuffer); + + do + { + hr = m_pImmediateContext->GetData(m_SOStatsQuery, &numPrims, sizeof(D3D11_QUERY_DATA_SO_STATISTICS ), 0); + } while(hr == S_FALSE); + + if(numPrims.NumPrimitivesWritten == 0) + { + m_PostVSData[idx] = PostVSData(); + return; + } + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = m_pImmediateContext->Map(m_SOStagingBuffer, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map sobuffer %08x", hr); + return; + } + + D3D11_BUFFER_DESC bufferDesc = + { + stride * (uint32_t)numPrims.NumPrimitivesWritten*3, + D3D11_USAGE_IMMUTABLE, + D3D11_BIND_VERTEX_BUFFER, + 0, + 0, + 0 + }; + + if(bufferDesc.ByteWidth >= m_SOBufferSize) + { + RDCERR("Generated output data too large: %08x", bufferDesc.ByteWidth); + + m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + return; + } + + ID3D11Buffer *vsoutBuffer = NULL; + + // we need to map this data into memory for read anyway, might as well make this VB + // immutable while we're at it. + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = mapped.pData; + initialData.SysMemPitch = bufferDesc.ByteWidth; + initialData.SysMemSlicePitch = bufferDesc.ByteWidth; + + hr = m_WrappedDevice->CreateBuffer( &bufferDesc, &initialData, &vsoutBuffer ); + + if(FAILED(hr)) + { + RDCERR("Failed to create postvs pos buffer %08x", hr); + + m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + return; + } + + byte *byteData = (byte *)mapped.pData; + + float nearp = 0.0f; + float farp = 0.0f; + + Vec4f *pos0 = (Vec4f *)(byteData + posoffset); + + for(UINT64 i=1; numPosComponents == 4 && i < numPrims.NumPrimitivesWritten; i++) + { + ////////////////////////////////////////////////////////////////////////////////// + // derive near/far, assuming a standard perspective matrix + // + // the transformation from from pre-projection {Z,W} to post-projection {Z,W} + // is linear. So we can say Zpost = Zpre*m + c . Here we assume Wpre = 1 + // and we know Wpost = Zpre from the perspective matrix. + // we can then see from the perspective matrix that + // m = F/(F-N) + // c = -(F*N)/(F-N) + // + // with re-arranging and substitution, we then get: + // N = -c/m + // F = c/(1-m) + // + // so if we can derive m and c then we can determine N and F. We can do this with + // two points, and we pick them reasonably distinct on z to reduce floating-point + // error + + Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride); + + if(fabs(pos->w - pos0->w) > 0.01f) + { + Vec2f A(pos0->w, pos0->z); + Vec2f B(pos->w, pos->z); + + float m = (B.y-A.y)/(B.x-A.x); + float c = B.y - B.x*m; + + if(m == 1.0f) continue; + + nearp = -c/m; + farp = c/(1-m); + + break; + } + } + + m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + + m_PostVSData[idx].vsin.topo = topo; + m_PostVSData[idx].vsout.buf = vsoutBuffer; + m_PostVSData[idx].vsout.posOffset = posoffset; + m_PostVSData[idx].vsout.vertStride = stride; + m_PostVSData[idx].vsout.numPrims = (uint32_t)numPrims.NumPrimitivesWritten; + m_PostVSData[idx].vsout.nearPlane = nearp; + m_PostVSData[idx].vsout.farPlane = farp; + + m_PostVSData[idx].vsout.topo = topo; + } + else + { + // empty vertex output signature + m_PostVSData[idx].vsin.topo = topo; + m_PostVSData[idx].vsout.buf = NULL; + m_PostVSData[idx].vsout.posOffset = ~0U; + m_PostVSData[idx].vsout.vertStride = 0; + m_PostVSData[idx].vsout.numPrims = 0; + m_PostVSData[idx].vsout.nearPlane = 0.0f; + m_PostVSData[idx].vsout.farPlane = 0.0f; + + m_PostVSData[idx].vsout.topo = topo; + } + + // streamout expands strips unfortunately + if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) + m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP) + m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + else if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ) + m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ; + else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ) + m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + + switch(m_PostVSData[idx].vsout.topo) + { + case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST: + m_PostVSData[idx].vsout.numVerts = m_PostVSData[idx].vsout.numPrims; break; + case D3D11_PRIMITIVE_TOPOLOGY_LINELIST: + m_PostVSData[idx].vsout.numVerts = m_PostVSData[idx].vsout.numPrims*2; break; + default: + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST: + m_PostVSData[idx].vsout.numVerts = m_PostVSData[idx].vsout.numPrims*3; break; + } + + if(dxbcGS || dxbcDS) + { + stride = 0; + posoffset = ~0U; + numPosComponents = 0; + + DXBC::DXBCFile *lastShader = dxbcGS; + if(dxbcDS) lastShader = dxbcDS; + + sodecls.clear(); + for(size_t i=0; i < lastShader->m_OutputSig.size(); i++) + { + SigParameter &sign = lastShader->m_OutputSig[i]; + + D3D11_SO_DECLARATION_ENTRY decl; + + decl.Stream = 0; + decl.OutputSlot = 0; + + decl.SemanticName = sign.semanticName.elems; + decl.SemanticIndex = sign.semanticIndex; + decl.StartComponent = 0; + decl.ComponentCount = sign.compCount&0xff; + + string a = strupper(string(decl.SemanticName)); + + // force to 4 components, as we need it, and store its offset + if(a.find("POSITION") != string::npos) + { + // force to 4 components, as we need it, and store its offset + if(a.find("SV_POSITION") != string::npos) + decl.ComponentCount = 4; + numPosComponents = decl.ComponentCount; + posoffset = stride; + } + + stride += decl.ComponentCount * sizeof(float); + sodecls.push_back(decl); + } + + streamoutGS = NULL; + + HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput( + (void *)&lastShader->m_ShaderBlob[0], + lastShader->m_ShaderBlob.size(), + &sodecls[0], + (UINT)sodecls.size(), + &stride, + 1, + D3D11_SO_NO_RASTERIZED_STREAM, + NULL, + &streamoutGS); + + if(FAILED(hr)) + { + RDCERR("Failed to create Geometry Shader + SO %08x", hr); + return; + } + + m_pImmediateContext->GSSetShader(streamoutGS, NULL, 0); + m_pImmediateContext->HSSetShader(hs, NULL, 0); + m_pImmediateContext->DSSetShader(ds, NULL, 0); + + SAFE_RELEASE(streamoutGS); + + UINT offset = 0; + m_pImmediateContext->SOSetTargets( 1, &m_SOBuffer, &offset ); + + m_pImmediateContext->Begin(m_SOStatsQuery); + m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + m_pImmediateContext->End(m_SOStatsQuery); + + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + m_pImmediateContext->SOSetTargets(0, NULL, NULL); + + D3D11_QUERY_DATA_SO_STATISTICS numPrims; + + m_pImmediateContext->CopyResource(m_SOStagingBuffer, m_SOBuffer); + + do + { + hr = m_pImmediateContext->GetData(m_SOStatsQuery, &numPrims, sizeof(D3D11_QUERY_DATA_SO_STATISTICS ), 0); + } while(hr == S_FALSE); + + if(numPrims.NumPrimitivesWritten == 0) + { + return; + } + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = m_pImmediateContext->Map(m_SOStagingBuffer, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map sobuffer %08x", hr); + return; + } + + D3D11_BUFFER_DESC bufferDesc = + { + stride * (uint32_t)numPrims.NumPrimitivesWritten*3, + D3D11_USAGE_IMMUTABLE, + D3D11_BIND_VERTEX_BUFFER, + 0, + 0, + 0 + }; + + if(bufferDesc.ByteWidth >= m_SOBufferSize) + { + RDCERR("Generated output data too large: %08x", bufferDesc.ByteWidth); + + m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + return; + } + + ID3D11Buffer *gsoutBuffer = NULL; + + // we need to map this data into memory for read anyway, might as well make this VB + // immutable while we're at it. + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = mapped.pData; + initialData.SysMemPitch = bufferDesc.ByteWidth; + initialData.SysMemSlicePitch = bufferDesc.ByteWidth; + + hr = m_WrappedDevice->CreateBuffer( &bufferDesc, &initialData, &gsoutBuffer ); + + if(FAILED(hr)) + { + RDCERR("Failed to create postvs pos buffer %08x", hr); + + m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + return; + } + + byte *byteData = (byte *)mapped.pData; + + float nearp = 0.0f; + float farp = 0.0f; + + Vec4f *pos0 = (Vec4f *)(byteData + posoffset); + + for(UINT64 i=1; numPosComponents == 4 && i < numPrims.NumPrimitivesWritten; i++) + { + ////////////////////////////////////////////////////////////////////////////////// + // derive near/far, assuming a standard perspective matrix + // + // the transformation from from pre-projection {Z,W} to post-projection {Z,W} + // is linear. So we can say Zpost = Zpre*m + c . Here we assume Wpre = 1 + // and we know Wpost = Zpre from the perspective matrix. + // we can then see from the perspective matrix that + // m = F/(F-N) + // c = -(F*N)/(F-N) + // + // with re-arranging and substitution, we then get: + // N = -c/m + // F = c/(1-m) + // + // so if we can derive m and c then we can determine N and F. We can do this with + // two points, and we pick them reasonably distinct on z to reduce floating-point + // error + + Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride); + + if(fabs(pos->w - pos0->w) > 0.01f) + { + Vec2f A(pos0->w, pos0->z); + Vec2f B(pos->w, pos->z); + + float m = (B.y-A.y)/(B.x-A.x); + float c = B.y - B.x*m; + + if(m == 1.0f) continue; + + nearp = -c/m; + farp = c/(1-m); + + break; + } + } + + m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + + m_PostVSData[idx].gsout.buf = gsoutBuffer; + m_PostVSData[idx].gsout.posOffset = posoffset; + m_PostVSData[idx].gsout.vertStride = stride; + m_PostVSData[idx].gsout.numPrims = (uint32_t)numPrims.NumPrimitivesWritten; + m_PostVSData[idx].gsout.nearPlane = nearp; + m_PostVSData[idx].gsout.farPlane = farp; + + D3D11_PRIMITIVE_TOPOLOGY topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + + if(lastShader == dxbcGS) + { + for(size_t i=0; i < dxbcGS->m_Declarations.size(); i++) + { + if(dxbcGS->m_Declarations[i].declaration == DXBC::OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY) + { + topo = (D3D11_PRIMITIVE_TOPOLOGY)dxbcGS->m_Declarations[i].outTopology; // enums match + break; + } + } + } + else if(lastShader == dxbcDS) + { + for(size_t i=0; i < dxbcDS->m_Declarations.size(); i++) + { + if(dxbcDS->m_Declarations[i].declaration == DXBC::OPCODE_DCL_TESS_DOMAIN) + { + if(dxbcDS->m_Declarations[i].domain == DXBC::DOMAIN_ISOLINE) + topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + else + topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + break; + } + } + } + + m_PostVSData[idx].gsout.topo = topo; + + // streamout expands strips unfortunately + if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) + m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP) + m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + else if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ) + m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ; + else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ) + m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + + switch(m_PostVSData[idx].gsout.topo) + { + case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST: + m_PostVSData[idx].gsout.numVerts = m_PostVSData[idx].gsout.numPrims; break; + case D3D11_PRIMITIVE_TOPOLOGY_LINELIST: + m_PostVSData[idx].gsout.numVerts = m_PostVSData[idx].gsout.numPrims*2; break; + default: + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST: + m_PostVSData[idx].gsout.numVerts = m_PostVSData[idx].gsout.numPrims*3; break; + } + } +} + +void D3D11DebugManager::RenderMesh(int frameID, vector eventID, MeshDisplay cfg) +{ + DebugVertexCBuffer vertexData; + + D3D11PipelineState pipeState = m_WrappedDevice->GetReplay()->GetD3D11PipelineState(); + D3D11RenderState *curRS = m_WrappedDevice->GetImmediateContext()->GetCurrentPipelineState(); + + float aspect = 1.0f; + + // guess the output aspect ratio, for mesh calculation + if(pipeState.m_OM.DepthTarget.Resource != ResourceId()) + { + FetchTexture desc = m_WrappedDevice->GetReplay()->GetTexture(m_ResourceManager->GetLiveID(pipeState.m_OM.DepthTarget.Resource)); + + aspect = float(desc.width)/float(desc.height); + } + else + { + for(int32_t i=0; i < pipeState.m_OM.RenderTargets.count; i++) + { + if(pipeState.m_OM.RenderTargets[i].Resource != ResourceId()) + { + FetchTexture desc = m_WrappedDevice->GetReplay()->GetTexture(m_ResourceManager->GetLiveID(pipeState.m_OM.RenderTargets[i].Resource)); + + aspect = float(desc.width)/float(desc.height); + break; + } + } + } + + Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth())/float(GetHeight())); + + Camera cam; + if(cfg.arcballCamera) + cam.Arcball(cfg.cameraPos.x, Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + else + cam.fpsLook(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + + Matrix4f camMat = cam.GetMatrix(); + Matrix4f guessProjInv; + + vertexData.ModelViewProj = projMat.Mul(camMat); + vertexData.SpriteSize = Vec2f(); + + DebugPixelCBufferData pixelData; + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + m_pImmediateContext->OMSetDepthStencilState(NULL, 0); + m_pImmediateContext->OMSetBlendState(m_WireframeHelpersBS, NULL, 0xffffffff); + + // don't cull in wireframe mesh display + /* + if(pipeState.m_RS.m_State.CullMode != eCull_None && pipeState.m_RS.m_State.FrontCCW) + m_pImmediateContext->RSSetState(m_WireframeHelpersCullCWRS); + else if(pipeState.m_RS.m_State.CullMode != eCull_None && !pipeState.m_RS.m_State.FrontCCW) + m_pImmediateContext->RSSetState(m_WireframeHelpersCullCCWRS); + else + */ + m_pImmediateContext->RSSetState(m_WireframeHelpersRS); + + if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) || + (cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId())) + { + float nearp = 0.1f; + float farp = 1000.0f; + + for(size_t i=0; i < eventID.size(); i++) + { + PostVSData data = GetPostVSBuffers(frameID, eventID[i]); + const PostVSData::StageData &stage = data.GetStage(cfg.type); + + if(stage.buf && stage.nearPlane != stage.farPlane) + { + nearp = stage.nearPlane; + farp = stage.farPlane; + break; + } + } + + // the derivation of the projection matrix might not be right (hell, it could be an + // orthographic projection). But it'll be close enough likely. + Matrix4f guessProj = Matrix4f::Perspective(cfg.fov, + cfg.nearPlane > -FLT_MAX ? cfg.nearPlane : nearp, + cfg.farPlane > -FLT_MAX ? cfg.farPlane : farp, + cfg.aspect > 0.0f ? cfg.aspect : aspect); + + if(cfg.ortho) + { + guessProj = Matrix4f::Orthographic(cfg.nearPlane > -FLT_MAX ? cfg.nearPlane : nearp, + cfg.farPlane > -FLT_MAX ? cfg.farPlane : farp); + } + + guessProjInv = guessProj.Inverse(); + + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); + + { + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericHomogLayout); + + if(eventID.size() > 1) + { + pixelData.WireframeColour = Vec3f(cfg.prevMeshColour.x, cfg.prevMeshColour.y, cfg.prevMeshColour.z); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + } + + for(size_t i=0; i < eventID.size()-1; i++) + { + PostVSData data = GetPostVSBuffers(frameID, eventID[i]); + const PostVSData::StageData &stage = data.GetStage(cfg.type); + + if(stage.buf) + { + if(stage.topo < D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ) + { + m_pImmediateContext->IASetPrimitiveTopology(stage.topo); + + ID3D11Buffer *buf = UNWRAP(WrappedID3D11Buffer, stage.buf); + m_pImmediateContext->IASetVertexBuffers(0, 1, &buf, (UINT *)&stage.vertStride, (UINT *)&stage.posOffset); + m_pImmediateContext->Draw(stage.numVerts, 0); + } + } + } + + pixelData.WireframeColour = Vec3f(cfg.currentMeshColour.x, cfg.currentMeshColour.y, cfg.currentMeshColour.z); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + PostVSData data = GetPostVSBuffers(frameID, eventID.back()); + const PostVSData::StageData &stage = data.GetStage(cfg.type); + if(stage.buf) + { + if(stage.topo < D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ) + { + m_pImmediateContext->IASetPrimitiveTopology(stage.topo); + + ID3D11Buffer *buf = UNWRAP(WrappedID3D11Buffer, stage.buf); + m_pImmediateContext->IASetVertexBuffers(0, 1, &buf, (UINT *)&stage.vertStride, (UINT *)&stage.posOffset); + m_pImmediateContext->Draw(stage.numVerts, 0); + } + } + } + } + else + { + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); + m_pImmediateContext->PSSetShader(m_DebugRender.MeshPS, NULL, 0); + + if(m_PrevMeshInputLayout != curRS->IA.Layout) + { + SAFE_RELEASE(m_MeshDisplayLayout); + + m_PrevMeshInputLayout = curRS->IA.Layout; + + const vector curLayout = m_WrappedDevice->GetLayoutDesc(curRS->IA.Layout); + + vector layoutdesc; + + byte elems = 0; + + int buffers[3] = {0,0,0}; + + for(size_t i=0; i < curLayout.size(); i++) + { + const D3D11_INPUT_ELEMENT_DESC &layout = curLayout[i]; + + if((!_stricmp(layout.SemanticName, "POSITION") || !_stricmp(layout.SemanticName, "SV_Position")) && + layout.SemanticIndex == 0) // need to get name from input config + { + D3D11_INPUT_ELEMENT_DESC el = layout; + el.SemanticName = "pos"; // these are the known values since they match WireframeVS + el.SemanticIndex = 0; + + layoutdesc.push_back(el); + + buffers[0] = layout.InputSlot; + + elems |= 0x1; + } + else if(!_stricmp(layout.SemanticName, "TEXCOORD") && layout.SemanticIndex == 0) + { + D3D11_INPUT_ELEMENT_DESC el = layout; + el.SemanticName = "tex"; // these are the known values since they match WireframeVS + el.SemanticIndex = 0; + + layoutdesc.push_back(el); + + buffers[1] = layout.InputSlot; + + elems |= 0x2; + } + else if(!_stricmp(layout.SemanticName, "COLOR") && layout.SemanticIndex == 0) + { + D3D11_INPUT_ELEMENT_DESC el = layout; + el.SemanticName = "col"; // these are the known values since they match WireframeVS + el.SemanticIndex = 0; + + layoutdesc.push_back(el); + + buffers[2] = layout.InputSlot; + + elems |= 0x4; + } + } + + for(m_MeshDisplayNULLVB = 0; m_MeshDisplayNULLVB < 4; m_MeshDisplayNULLVB++) + { + bool used = false; + + for(int i=0; i < 3; i++) + { + if(elems & (1<CreateInputLayout(&layoutdesc[0], 3, m_DebugRender.MeshVSBytecode, m_DebugRender.MeshVSBytelen, &m_MeshDisplayLayout); + + if(FAILED(hr)) + { + RDCERR("Failed to create rendermesh input layout %08x", hr); + return; + } + } + + if(m_MeshDisplayLayout == NULL) + { + RDCWARN("Couldn't get a mesh display layout"); + return; + } + + m_pImmediateContext->IASetInputLayout(m_MeshDisplayLayout); + ID3D11Buffer *vb = NULL; + UINT dummy = 4; + m_pImmediateContext->IASetVertexBuffers(m_MeshDisplayNULLVB, 1, &vb, &dummy, &dummy); + + // draw solid shaded mode + if(cfg.solidShadeMode != eShade_None) + { + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + + pixelData.OutputDisplayFormat = (int)cfg.solidShadeMode; + pixelData.WireframeColour = Vec3f(0.8f, 0.8f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + if(cfg.solidShadeMode == eShade_Lit) + { + DebugGeometryCBuffer geomData; + + geomData.InvProj = projMat.Inverse(); + + FillCBuffer(m_DebugRender.GenericGSCBuffer, (float *)&geomData, sizeof(DebugGeometryCBuffer)); + m_pImmediateContext->GSSetConstantBuffers(0, 1, &m_DebugRender.GenericGSCBuffer); + + m_pImmediateContext->GSSetShader(m_DebugRender.MeshGS, NULL, 0); + } + + m_WrappedDevice->ReplayLog(frameID, 0, eventID[0], eReplay_OnlyDraw); + + if(cfg.solidShadeMode == eShade_Lit) + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + } + + // draw wireframe mode + if(cfg.solidShadeMode == eShade_None || cfg.wireframeDraw) + { + m_pImmediateContext->RSSetState(m_WireframeHelpersRS); + + m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.LEqualDepthState, 0); + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + m_WrappedDevice->ReplayLog(frameID, 0, eventID[0], eReplay_OnlyDraw); + } + } + + m_pImmediateContext->RSSetState(m_WireframeHelpersRS); + + // set up state for drawing helpers + { + vertexData.ModelViewProj = projMat.Mul(camMat); + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + + m_pImmediateContext->RSSetState(m_SolidHelpersRS); + + m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.NoDepthState, 0); + + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + m_pImmediateContext->VSSetShader(m_DebugRender.WireframeVS, NULL, 0); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); + } + + // axis markers + if(cfg.type == eMeshDataStage_VSIn || + (cfg.type == eMeshDataStage_VSOut && pipeState.m_HS.Shader != ResourceId())) + { + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + UINT strides[] = { sizeof(Vec3f) }; + UINT offsets[] = { 0 }; + + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_AxisHelper, strides, offsets); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + m_pImmediateContext->Draw(2, 0); + + pixelData.WireframeColour = Vec3f(0.0f, 1.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + m_pImmediateContext->Draw(2, 2); + + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + m_pImmediateContext->Draw(2, 4); + } + + if(cfg.showVerts) + { + // if data is from post transform, it will be in clipspace + if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) || + (cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId())) + { + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericHomogLayout); + } + else + { + vertexData.ModelViewProj = projMat.Mul(camMat); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + } + + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + + pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = S_OK; + + hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failde to map m_TriHighlightHelper %08x", hr); + return; + } + + memcpy(mapped.pData, cfg.hilightVerts, sizeof(Vec4f)*3); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + UINT strides[] = { sizeof(Vec4f) }; + UINT offsets[] = { 0 }; + + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_TriHighlightHelper, (UINT *)&strides, (UINT *)&offsets); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + m_pImmediateContext->Draw(3, 0); + + FloatVector vertSprite[4] = { + cfg.hilightVerts[0], + cfg.hilightVerts[0], + cfg.hilightVerts[0], + cfg.hilightVerts[0] + }; + + hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failde to map m_TriHighlightHelper %08x", hr); + return; + } + + memcpy(mapped.pData, vertSprite, sizeof(vertSprite)); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + float scale = 800.0f/float(GetHeight()); + float asp = float(GetWidth())/float(GetHeight()); + + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); + vertexData.SpriteSize = Vec2f(scale/asp, scale); + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_pImmediateContext->Draw(4, 0); + + if(cfg.type != eMeshDataStage_VSIn) + m_pImmediateContext->VSSetShader(m_DebugRender.WireframeVS, NULL, 0); + } + + // 'fake' helper frustum + if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) || + (cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId())) + { + UINT strides[] = { sizeof(Vec3f) }; + UINT offsets[] = { 0 }; + + vertexData.SpriteSize = Vec2f(); + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_FrustumHelper, (UINT *)&strides, (UINT *)&offsets); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + pixelData.WireframeColour = Vec3f(0.5f, 0.5f, 0.5f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->Draw(24, 0); + } +} diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h new file mode 100644 index 0000000000..f4be7980f6 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -0,0 +1,471 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +using std::pair; + +#include "replay/renderdoc.h" + +#include "driver/d3d11/shaders/dxbc_debug.h" + +class Camera; +class Vec3f; + +class WrappedID3D11Device; +class WrappedID3D11DeviceContext; + +class D3D11ResourceManager; + +namespace ShaderDebug { struct GlobalState; } + +struct GPUTimer +{ + ID3D11Query *before; + ID3D11Query *after; + FetchDrawcall *drawcall; +}; + +struct PostVSData +{ + struct StageData + { + ID3D11Buffer *buf; + D3D11_PRIMITIVE_TOPOLOGY topo; + + uint32_t numVerts; + uint32_t numPrims; + uint32_t posOffset; + uint32_t vertStride; + + float nearPlane; + float farPlane; + } vsin, vsout, gsout; + + PostVSData() + { + RDCEraseEl(vsin); + RDCEraseEl(vsout); + RDCEraseEl(gsout); + } + + const StageData &GetStage(MeshDataStage type) + { + if(type == eMeshDataStage_VSOut) + return vsout; + else if(type == eMeshDataStage_GSOut) + return gsout; + else + RDCERR("Unexpected mesh data stage!"); + + return vsin; + } +}; + +class D3D11DebugManager +{ + public: + D3D11DebugManager(WrappedID3D11Device *wrapper); + ~D3D11DebugManager(); + + uint64_t MakeOutputWindow(void *w, bool depth); + void DestroyOutputWindow(uint64_t id); + bool CheckResizeOutputWindow(uint64_t id); + void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); + void ClearOutputWindowColour(uint64_t id, float col[4]); + void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil); + void BindOutputWindow(uint64_t id, bool depth); + bool IsOutputWindowVisible(uint64_t id); + void FlipOutputWindow(uint64_t id); + + void SetOutputDimensions(int w, int h) { m_width = w; m_height = h; } + int GetWidth() { return m_width; } + int GetHeight() { return m_height; } + + void InitPostVSBuffers(uint32_t frameID, uint32_t eventID); + PostVSData GetPostVSBuffers(uint32_t frameID, uint32_t eventID); + PostVSMeshData GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + + uint32_t GetStructCount(ID3D11UnorderedAccessView *uav); + vector GetBufferData(ID3D11Buffer *buff, uint32_t offset, uint32_t len); + vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); + + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize); + + void FillCBufferVariables(const vector &invars, vector &outvars, + bool flattenVec4s, const vector &data); + + bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval); + bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram); + + void CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Texture2D *srcArray); + void CopyTex2DMSToArray(ID3D11Texture2D *destArray, ID3D11Texture2D *srcMS); + + void TimeDrawcalls(rdctype::array &arr); + + bool SaveTexture(ResourceId tex, uint32_t saveMip, wstring path); + + void RenderText(float x, float y, float size, const char *textfmt, ...); + void RenderMesh(int frameID, vector eventID, MeshDisplay cfg); + + ID3D11Buffer *MakeCBuffer(float *data, size_t size); + + string GetShaderBlob(const char *source, const char *entry, const uint32_t compileFlags, const char *profile, ID3DBlob **srcblob); + ID3D11VertexShader *MakeVShader(const char *source, const char *entry, const char *profile, + int numInputDescs = 0, + D3D11_INPUT_ELEMENT_DESC *inputs = NULL, ID3D11InputLayout **ret = NULL, vector *blob = NULL); + ID3D11GeometryShader *MakeGShader(const char *source, const char *entry, const char *profile); + ID3D11PixelShader *MakePShader(const char *source, const char *entry, const char *profile); + ID3D11ComputeShader *MakeCShader(const char *source, const char *entry, const char *profile); + + void BuildShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); + + ID3D11Buffer *MakeCBuffer(UINT size); + + bool RenderTexture(TextureDisplay cfg); + + void RenderCheckerboard(Vec3f light, Vec3f dark); + + void RenderHighlightBox(float w, float h, float scale); + + ShaderDebugTrace DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); + ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y); + ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]); + + ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip); + + // don't need to differentiate arrays as we treat everything + // as an array (potentially with only one element). + enum TextureType + { + eTexType_1D = 1, + eTexType_2D, + eTexType_3D, + eTexType_Depth, + eTexType_Stencil, + eTexType_DepthMS, + eTexType_StencilMS, + eTexType_Cube, + eTexType_Max + }; + + struct TextureShaderDetails + { + TextureShaderDetails() + { + texFmt = DXGI_FORMAT_UNKNOWN; + texWidth = 0; + texHeight = 0; + texDepth = 0; + texMips = 0; + texArraySize = 0; + + sampleCount = 1; + sampleQuality = 0; + + texType = eTexType_2D; + + srvResource = NULL; + previewCopy = NULL; + + RDCEraseEl(srv); + } + + DXGI_FORMAT texFmt; + UINT texWidth; + UINT texHeight; + UINT texDepth; + UINT texMips; + UINT texArraySize; + + UINT sampleCount; + UINT sampleQuality; + + TextureType texType; + + ID3D11Resource *srvResource; + ID3D11Resource *previewCopy; + + ID3D11ShaderResourceView *srv[eTexType_Max]; + }; + + TextureShaderDetails GetShaderDetails(ResourceId id, bool rawOutput); + private: + struct CacheElem + { + CacheElem(ResourceId id_, bool raw_) + : created(false), id(id_), raw(raw_), srvResource(NULL) + { + srv[0] = srv[1] = srv[2] = NULL; + } + + void Release() + { + SAFE_RELEASE(srvResource); + SAFE_RELEASE(srv[0]); + SAFE_RELEASE(srv[1]); + SAFE_RELEASE(srv[2]); + } + + bool created; + ResourceId id; + bool raw; + ID3D11Resource *srvResource; + ID3D11ShaderResourceView *srv[3]; + }; + + static const int NUM_CACHED_SRVS = 64; + + std::list m_ShaderItemCache; + + CacheElem &GetCachedElem(ResourceId id, bool raw); + + int m_width, m_height; + + WrappedID3D11Device *m_WrappedDevice; + WrappedID3D11DeviceContext *m_WrappedContext; + + D3D11ResourceManager *m_ResourceManager; + + ID3D11Device *m_pDevice; + ID3D11DeviceContext *m_pImmediateContext; + + IDXGIFactory *m_pFactory; + + struct OutputWindow + { + HWND wnd; + IDXGISwapChain* swap; + ID3D11RenderTargetView* rtv; + ID3D11DepthStencilView* dsv; + + WrappedID3D11Device *dev; + + void MakeRTV(); + void MakeDSV(); + + int width, height; + }; + + uint64_t m_OutputWindowID; + map m_OutputWindows; + + static const uint32_t m_ShaderCacheVersion = 2; + bool m_ShaderCacheDirty, m_CacheShaders; + map m_ShaderCache; + + static const int m_SOBufferSize = 16*1024*1024; + ID3D11Buffer *m_SOBuffer; + ID3D11Buffer *m_SOStagingBuffer; + ID3D11Query *m_SOStatsQuery; + // -> data + map, PostVSData> m_PostVSData; + + ID3D11Texture2D *m_OverlayRenderTex; + ResourceId m_OverlayResourceId; + + ID3D11Texture2D* m_CustomShaderTex; + ID3D11RenderTargetView* m_CustomShaderRTV; + ResourceId m_CustomShaderResourceId; + + ID3D11BlendState *m_WireframeHelpersBS; + ID3D11RasterizerState *m_WireframeHelpersRS, *m_WireframeHelpersCullCCWRS, *m_WireframeHelpersCullCWRS; + ID3D11RasterizerState *m_SolidHelpersRS; + + // this gets updated to pull the elements we want out of the buffers + ID3D11InputLayout *m_MeshDisplayLayout; + int m_MeshDisplayNULLVB; + + // whenever this changes (just a dumb pointer, not ref-owned) + ID3D11InputLayout *m_PrevMeshInputLayout; + + ID3D11Buffer *m_AxisHelper; + ID3D11Buffer *m_FrustumHelper; + ID3D11Buffer *m_TriHighlightHelper; + + bool InitStreamOut(); + void ShutdownStreamOut(); + + // font/text rendering + bool InitFontRendering(); + void ShutdownFontRendering(); + + void RenderTextInternal(float x, float y, float size, const char *text); + + void CreateCustomShaderTex(uint32_t w, uint32_t h); + + static const int FONT_TEX_WIDTH = 4096; + static const int FONT_TEX_HEIGHT = 48; + static const int FONT_MAX_CHARS = 256; + + static const uint32_t STAGE_BUFFER_BYTE_SIZE = 4*1024*1024; + + struct FontData + { + FontData() { RDCEraseMem(this, sizeof(FontData)); } + ~FontData() + { + SAFE_RELEASE(Layout); + SAFE_RELEASE(Tex); + SAFE_RELEASE(CBuffer); + SAFE_RELEASE(CharBuffer); + SAFE_RELEASE(VS); + SAFE_RELEASE(PS); + } + + ID3D11InputLayout *Layout; + ID3D11ShaderResourceView *Tex; + ID3D11Buffer *CBuffer; + ID3D11Buffer *CharBuffer; + ID3D11VertexShader *VS; + ID3D11PixelShader *PS; + } m_Font; + + struct DebugRenderData + { + DebugRenderData() { RDCEraseMem(this, sizeof(DebugRenderData)); } + ~DebugRenderData() + { + SAFE_RELEASE(StageBuffer); + + SAFE_RELEASE(PosBuffer); + SAFE_RELEASE(OutlineStripVB); + SAFE_RELEASE(RastState); + SAFE_RELEASE(BlendState); + SAFE_RELEASE(PointSampState); + SAFE_RELEASE(LinearSampState); + SAFE_RELEASE(NoDepthState); + SAFE_RELEASE(LEqualDepthState); + + SAFE_RELEASE(GenericLayout); + SAFE_RELEASE(GenericHomogLayout); + SAFE_RELEASE(GenericVSCBuffer); + SAFE_RELEASE(GenericGSCBuffer); + SAFE_RELEASE(GenericPSCBuffer); + SAFE_RELEASE(GenericVS); + SAFE_RELEASE(TexDisplayPS); + SAFE_RELEASE(CheckerboardPS); + SAFE_RELEASE(MeshVS); + SAFE_RELEASE(MeshGS); + SAFE_RELEASE(MeshPS); + SAFE_RELEASE(WireframeVS); + SAFE_RELEASE(WireframeHomogVS); + SAFE_RELEASE(WireframePS); + SAFE_RELEASE(OverlayPS); + + SAFE_RELEASE(tileResultBuff); + SAFE_RELEASE(resultBuff); + SAFE_RELEASE(resultStageBuff); + + for(int i=0; i < 3; i++) + { + SAFE_RELEASE(tileResultUAV[i]); + SAFE_RELEASE(resultUAV[i]); + SAFE_RELEASE(tileResultSRV[i]); + } + + for(int i=0; i < ARRAY_COUNT(TileMinMaxCS); i++) + { + for(int j=0; j < 3; j++) + { + SAFE_RELEASE(TileMinMaxCS[i][j]); + SAFE_RELEASE(HistogramCS[i][j]); + + if(i == 0) + SAFE_RELEASE(ResultMinMaxCS[j]); + } + } + + SAFE_RELEASE(histogramBuff); + SAFE_RELEASE(histogramStageBuff); + + SAFE_RELEASE(histogramUAV); + + SAFE_DELETE_ARRAY(MeshVSBytecode); + + SAFE_RELEASE(PickPixelRT); + SAFE_RELEASE(PickPixelStageTex); + + for(int i=0; i < ARRAY_COUNT(PublicCBuffers); i++) + { + SAFE_RELEASE(PublicCBuffers[i]); + } + } + + ID3D11Buffer *StageBuffer; + + ID3D11Buffer *PosBuffer, *OutlineStripVB; + ID3D11RasterizerState *RastState; + ID3D11SamplerState *PointSampState, *LinearSampState; + ID3D11BlendState *BlendState; + ID3D11DepthStencilState *NoDepthState, *LEqualDepthState; + + ID3D11InputLayout *GenericLayout, *GenericHomogLayout; + ID3D11Buffer *GenericVSCBuffer; + ID3D11Buffer *GenericGSCBuffer; + ID3D11Buffer *GenericPSCBuffer; + ID3D11Buffer *PublicCBuffers[20]; + ID3D11VertexShader *GenericVS, *WireframeVS, *MeshVS, *WireframeHomogVS, *FullscreenVS; + ID3D11GeometryShader *MeshGS; + ID3D11PixelShader *TexDisplayPS, *OverlayPS, *WireframePS, *MeshPS, *CheckerboardPS; + ID3D11PixelShader *CopyMSToArrayPS, *CopyArrayToMSPS; + ID3D11PixelShader *FloatCopyMSToArrayPS, *FloatCopyArrayToMSPS; + ID3D11PixelShader *DepthCopyMSToArrayPS, *DepthCopyArrayToMSPS; + + ID3D11Buffer *tileResultBuff, *resultBuff, *resultStageBuff; + ID3D11UnorderedAccessView *tileResultUAV[3], *resultUAV[3]; + ID3D11ShaderResourceView *tileResultSRV[3]; + ID3D11ComputeShader *TileMinMaxCS[eTexType_Max][3]; // uint, sint, float + ID3D11ComputeShader *HistogramCS[eTexType_Max][3]; // uint, sint, float + ID3D11ComputeShader *ResultMinMaxCS[3]; + ID3D11Buffer *histogramBuff, *histogramStageBuff; + ID3D11UnorderedAccessView *histogramUAV; + + byte *MeshVSBytecode; + uint32_t MeshVSBytelen; + + int publicCBufIdx; + + ID3D11RenderTargetView *PickPixelRT; + ID3D11Texture2D *PickPixelStageTex; + } m_DebugRender; + + bool InitDebugRendering(); + + ShaderDebug::State CreateShaderDebugState(ShaderDebugTrace &trace, int quadIdx, DXBC::DXBCFile *dxbc, vector *cbufData); + void CreateShaderGlobalState(ShaderDebug::GlobalState &global, uint32_t UAVStartSlot, ID3D11UnorderedAccessView **UAVs, ID3D11ShaderResourceView **SRVs); + void FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, + const vector &invars, vector &outvars, + const vector &data); + friend struct ShaderDebugState; + + void FillTimers(uint32_t frameID, uint32_t &eventStart, rdctype::array &draws, vector &timers, int &reuseIdx); + + void FillCBuffer(ID3D11Buffer *buf, float *data, size_t size); +}; \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp new file mode 100644 index 0000000000..69ff40fda5 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -0,0 +1,3141 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "core/core.h" + +#include "common/string_utils.h" + +#include "maths/formatpacking.h" + +#include + +#include "driver/dxgi/dxgi_wrapped.h" +#include "driver/d3d11/d3d11_device.h" +#include "driver/d3d11/d3d11_resources.h" +#include "driver/d3d11/d3d11_renderstate.h" +#include "driver/d3d11/d3d11_context.h" + +#include "3rdparty/jpeg-compressor/jpge.h" + +const char *D3D11ChunkNames[] = +{ + "ID3D11Device::Initialisation", + "ID3D11Resource::SetDebugName", + "ID3D11Resource::Release", + "IDXGISwapChain::GetBuffer", + "ID3D11Device::CreateTexture1D", + "ID3D11Device::CreateTexture2D", + "ID3D11Device::CreateTexture3D", + "ID3D11Device::CreateBuffer", + "ID3D11Device::CreateVertexShader", + "ID3D11Device::CreateHullShader", + "ID3D11Device::CreateDomainShader", + "ID3D11Device::CreateGeometryShader", + "ID3D11Device::CreateGeometryShaderWithStreamOut", + "ID3D11Device::CreatePixelShader", + "ID3D11Device::CreateComputeShader", + "ID3D11ClassLinkage::GetClassInstance", + "ID3D11ClassLinkage::CreateClassInstance", + "ID3D11Device::CreateClassLinkage", + "ID3D11Device::CreateShaderResourceView", + "ID3D11Device::CreateRenderTargetView", + "ID3D11Device::CreateDepthStencilView", + "ID3D11Device::CreateUnorderedAccessView", + "ID3D11Device::CreateInputLayout", + "ID3D11Device::CreateBlendState", + "ID3D11Device::CreateDepthStencilState", + "ID3D11Device::CreateRasterizerState", + "ID3D11Device::CreateSamplerState", + "ID3D11Device::CreateQuery", + "ID3D11Device::CreatePredicate", + "ID3D11Device::CreateCounter", + "ID3D11Device::CreateDeferredContext", + "ID3D11Device::SetExceptionMode", + "ID3D11Device::OpenSharedResource", + + "Capture", + + "ID3D11DeviceContext::IASetInputLayout", + "ID3D11DeviceContext::IASetVertexBuffers", + "ID3D11DeviceContext::IASetIndexBuffer", + "ID3D11DeviceContext::IASetPrimitiveTopology", + + "ID3D11DeviceContext::VSSetConstantBuffers", + "ID3D11DeviceContext::VSSetShaderResources", + "ID3D11DeviceContext::VSSetSamplers", + "ID3D11DeviceContext::VSSetShader", + + "ID3D11DeviceContext::HSSetConstantBuffers", + "ID3D11DeviceContext::HSSetShaderResources", + "ID3D11DeviceContext::HSSetSamplers", + "ID3D11DeviceContext::HSSetShader", + + "ID3D11DeviceContext::DSSetConstantBuffers", + "ID3D11DeviceContext::DSSetShaderResources", + "ID3D11DeviceContext::DSSetSamplers", + "ID3D11DeviceContext::DSSetShader", + + "ID3D11DeviceContext::GSSetConstantBuffers", + "ID3D11DeviceContext::GSSetShaderResources", + "ID3D11DeviceContext::GSSetSamplers", + "ID3D11DeviceContext::GSSetShader", + + "ID3D11DeviceContext::SOSetTargets", + + "ID3D11DeviceContext::PSSetConstantBuffers", + "ID3D11DeviceContext::PSSetShaderResources", + "ID3D11DeviceContext::PSSetSamplers", + "ID3D11DeviceContext::PSSetShader", + + "ID3D11DeviceContext::CSSetConstantBuffers", + "ID3D11DeviceContext::CSSetShaderResources", + "ID3D11DeviceContext::CSSetUnorderedAccessViews", + "ID3D11DeviceContext::CSSetSamplers", + "ID3D11DeviceContext::CSSetShader", + + "ID3D11DeviceContext::RSSetViewports", + "ID3D11DeviceContext::RSSetScissors", + "ID3D11DeviceContext::RSSetState", + + "ID3D11DeviceContext::OMSetRenderTargets", + "ID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews", + "ID3D11DeviceContext::OMSetBlendState", + "ID3D11DeviceContext::OMSetDepthStencilState", + + "ID3D11DeviceContext::DrawIndexedInstanced", + "ID3D11DeviceContext::DrawInstanced", + "ID3D11DeviceContext::DrawIndexed", + "ID3D11DeviceContext::Draw", + "ID3D11DeviceContext::DrawAuto", + "ID3D11DeviceContext::DrawIndexedInstancedIndirect", + "ID3D11DeviceContext::DrawInstancedIndirect", + + "ID3D11DeviceContext::Map", + "ID3D11DeviceContext::Unmap", + + "ID3D11DeviceContext::CopySubresourceRegion", + "ID3D11DeviceContext::CopyResource", + "ID3D11DeviceContext::UpdateSubresource", + "ID3D11DeviceContext::CopyStructureCount", + "ID3D11DeviceContext::ResolveSubresource", + "ID3D11DeviceContext::GenerateMips", + + "ID3D11DeviceContext::ClearDepthStencilView", + "ID3D11DeviceContext::ClearRenderTargetView", + "ID3D11DeviceContext::ClearUnorderedAccessViewInt", + "ID3D11DeviceContext::ClearUnorderedAccessViewFloat", + "ID3D11DeviceContext::ClearState", + + "ID3D11DeviceContext::ExecuteCommandList", + "ID3D11DeviceContext::Dispatch", + "ID3D11DeviceContext::DispatchIndirect", + "ID3D11DeviceContext::FinishCommandlist", + "ID3D11DeviceContext::Flush", + + "ID3D11DeviceContext::SetPredication", + "ID3D11DeviceContext::SetResourceMinLOD", + + "ID3D11DeviceContext::Begin", + "ID3D11DeviceContext::End", + + "ID3D11Device1::CreateRasterizerState1", + "ID3D11Device1::CreateBlendState1", + + "ID3D11DeviceContext1::CopySubresourceRegion1", + "ID3D11DeviceContext1::UpdateSubresource1", + "ID3D11DeviceContext1::ClearView", + + "ID3D11DeviceContext1::VSSetConstantBuffers1", + "ID3D11DeviceContext1::HSSetConstantBuffers1", + "ID3D11DeviceContext1::DSSetConstantBuffers1", + "ID3D11DeviceContext1::GSSetConstantBuffers1", + "ID3D11DeviceContext1::PSSetConstantBuffers1", + "ID3D11DeviceContext1::CSSetConstantBuffers1", + + "D3DPERF_PushMarker", + "D3DPERF_SetMarker", + "D3DPERF_PopMarker", + + "DebugMessageList", + + "ContextBegin", + "ContextEnd", +}; + +WRAPPED_POOL_INST(WrappedID3D11Device); + +WrappedID3D11Device *WrappedID3D11Device::m_pCurrentWrappedDevice = NULL; + +D3D11InitParams::D3D11InitParams() +{ + SerialiseVersion = D3D11_SERIALISE_VERSION; + DriverType = D3D_DRIVER_TYPE_UNKNOWN; + Flags = 0; + SDKVersion = D3D11_SDK_VERSION; + NumFeatureLevels = 0; + RDCEraseEl(FeatureLevels); +} + +ReplayCreateStatus D3D11InitParams::Serialise() +{ + SERIALISE_ELEMENT(uint32_t, ver, D3D11_SERIALISE_VERSION); SerialiseVersion = ver; + + if(ver != D3D11_SERIALISE_VERSION) + { + RDCERR("Incompatible D3D11 serialise version, expected %d got %d", D3D11_SERIALISE_VERSION, ver); + return eReplayCreate_APIIncompatibleVersion; + } + + SERIALISE_ELEMENT(D3D_DRIVER_TYPE, driverType, DriverType); DriverType = driverType; + SERIALISE_ELEMENT(uint32_t, flags, Flags); Flags = flags; + SERIALISE_ELEMENT(uint32_t, sdk, SDKVersion); SDKVersion = sdk; + SERIALISE_ELEMENT(uint32_t, numlevels, NumFeatureLevels); NumFeatureLevels = numlevels; + m_pSerialiser->Serialise("FeatureLevels", FeatureLevels); + + return eReplayCreate_Success; +} + +void WrappedID3D11Device::SetLogFile(const wchar_t *logfile) +{ +#if defined(RELEASE) + const bool debugSerialiser = false; +#else + const bool debugSerialiser = true; +#endif + + m_pSerialiser = new Serialiser(logfile, Serialiser::READING, debugSerialiser); + m_pSerialiser->SetChunkNameLookup(&GetChunkName); + m_pImmediateContext->SetSerialiser(m_pSerialiser); +} + +WrappedID3D11Device::WrappedID3D11Device(ID3D11Device* realDevice, D3D11InitParams *params) + : m_RefCounter(realDevice, false), m_SoftRefCounter(NULL, false), m_pDevice(realDevice) +{ + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D11Device)); + + m_pDevice1 = NULL; + m_pDevice->QueryInterface(__uuidof(ID3D11Device1), (void **)&m_pDevice1); + + m_Replay.SetDevice(this); + + m_DebugManager = NULL; + m_ResourceManager = new D3D11ResourceManager(this); + + // refcounters implicitly construct with one reference, but we don't start with any soft + // references. + m_SoftRefCounter.Release(); + m_InternalRefcount = 0; + m_Alive = true; + + m_DummyInfo.m_pDevice = this; + + m_FrameCounter = 0; + m_FailedFrame = 0; + m_FailedReason = CaptureSucceeded; + m_Failures = 0; + + m_SwapChain = NULL; + + m_FrameTimer.Restart(); + + m_TotalTime = m_AvgFrametime = m_MinFrametime = m_MaxFrametime = 0.0; + + m_CurFileSize = 0; + +#if defined(RELEASE) + const bool debugSerialiser = false; +#else + const bool debugSerialiser = true; +#endif + + if(RenderDoc::Inst().IsReplayApp()) + { + m_State = READING; + m_pSerialiser = NULL; + m_pDebugSerialiser = NULL; + + TrackedResource::SetReplayResourceIDs(); + } + else + { + m_State = WRITING_IDLE; + m_pSerialiser = new Serialiser(NULL, Serialiser::WRITING, debugSerialiser); + +#ifdef DEBUG_TEXT_SERIALISER + m_pDebugSerialiser = new Serialiser(L"./debuglog.txt", Serialiser::DEBUGWRITING, true); +#else + m_pDebugSerialiser = NULL; +#endif + } + + if(m_pSerialiser) + m_pSerialiser->SetChunkNameLookup(&GetChunkName); + + // create a temporary and grab its resource ID + m_ResourceID = TrackedResource().GetResourceID(); + + m_DeviceRecord = NULL; + + if(!RenderDoc::Inst().IsReplayApp()) + { + m_DeviceRecord = GetResourceManager()->AddResourceRecord(m_ResourceID); + m_DeviceRecord->DataInSerialiser = false; + m_DeviceRecord->SpecialResource = true; + m_DeviceRecord->Length = 0; + m_DeviceRecord->NumSubResources = 0; + m_DeviceRecord->SubResources = NULL; + } + + ID3D11DeviceContext *context = NULL; + realDevice->GetImmediateContext(&context); + + m_pImmediateContext = new WrappedID3D11DeviceContext(this, context, m_pSerialiser, m_pDebugSerialiser); + + SAFE_RELEASE(context); + + realDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&m_pInfoQueue); + + if(m_pInfoQueue) + { + m_pInfoQueue->SetMuteDebugOutput(true); + + UINT size = m_pInfoQueue->GetStorageFilterStackSize(); + + while(size > 1) + { + m_pInfoQueue->ClearStorageFilter(); + size = m_pInfoQueue->GetStorageFilterStackSize(); + } + + size = m_pInfoQueue->GetRetrievalFilterStackSize(); + + while(size > 1) + { + m_pInfoQueue->ClearRetrievalFilter(); + size = m_pInfoQueue->GetRetrievalFilterStackSize(); + } + + m_pInfoQueue->ClearStoredMessages(); + + if(RenderDoc::Inst().IsReplayApp()) + m_pInfoQueue->SetMuteDebugOutput(false); + } + else + { + RDCDEBUG("Couldn't get ID3D11InfoQueue."); + } + + m_InitParams = params; + + SetContextFilter(ResourceId(), 0, 0); + + // ATI workaround - these dlls can get unloaded and cause a crash. + + if(GetModuleHandleA("aticfx32.dll")) + LoadLibraryA("aticfx32.dll"); + if(GetModuleHandleA("atiuxpag.dll")) + LoadLibraryA("atiuxpag.dll"); + if(GetModuleHandleA("atidxx32.dll")) + LoadLibraryA("atidxx32.dll"); + + if(GetModuleHandleA("aticfx64.dll")) + LoadLibraryA("aticfx64.dll"); + if(GetModuleHandleA("atiuxp64.dll")) + LoadLibraryA("atiuxp64.dll"); + if(GetModuleHandleA("atidxx64.dll")) + LoadLibraryA("atidxx64.dll"); + + ////////////////////////////////////////////////////////////////////////// + // Compile time asserts + + RDCCOMPILE_ASSERT(ARRAY_COUNT(D3D11ChunkNames) == NUM_D3D11_CHUNKS-FIRST_CHUNK_ID, "Not right number of chunk names"); +} + +WrappedID3D11Device::~WrappedID3D11Device() +{ + SAFE_DELETE(m_InitParams); + + if(m_pCurrentWrappedDevice == this) + m_pCurrentWrappedDevice = NULL; + + for(auto it = m_CachedStateObjects.begin(); it != m_CachedStateObjects.end(); ++it) + if(*it) + (*it)->Release(); + + m_CachedStateObjects.clear(); + + SAFE_RELEASE(m_pDevice1); + + SAFE_RELEASE(m_pImmediateContext); + + for(auto it = m_SwapChains.begin(); it != m_SwapChains.end(); ++it) + SAFE_RELEASE(it->second); + + SAFE_DELETE(m_DebugManager); + + if(m_DeviceRecord) + { + RDCASSERT(m_DeviceRecord->GetRefCount() == 1); + m_DeviceRecord->Delete(GetResourceManager()); + } + + m_ResourceManager->Shutdown(); + + SAFE_DELETE(m_ResourceManager); + + SAFE_RELEASE(m_pInfoQueue); + SAFE_RELEASE(m_pDevice); + + SAFE_DELETE(m_pSerialiser); + SAFE_DELETE(m_pDebugSerialiser); + + for(auto it=m_LayoutDXBC.begin(); it != m_LayoutDXBC.end(); ++it) + SAFE_DELETE(it->second); + m_LayoutDXBC.clear(); + m_LayoutDescs.clear(); + + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); +} + +void WrappedID3D11Device::CheckForDeath() +{ + if(!m_Alive) return; + + if(m_RefCounter.GetRefCount() == 0) + { + RDCASSERT(m_SoftRefCounter.GetRefCount() >= m_InternalRefcount); + + if(m_SoftRefCounter.GetRefCount() <= m_InternalRefcount || m_State < WRITING) // MEGA HACK + { + m_Alive = false; + delete this; + } + } +} + +ULONG STDMETHODCALLTYPE DummyID3D11InfoQueue::AddRef() +{ + m_pDevice->AddRef(); + return 1; +} + +ULONG STDMETHODCALLTYPE DummyID3D11InfoQueue::Release() +{ + m_pDevice->Release(); + return 1; +} + +HRESULT WrappedID3D11Device::QueryInterface(REFIID riid, void **ppvObject) +{ + // DEFINE_GUID(IID_IDirect3DDevice9, 0xd0223b96, 0xbf7a, 0x43fd, 0x92, 0xbd, 0xa4, 0x3b, 0xd, 0x82, 0xb9, 0xeb); + static const GUID IDirect3DDevice9_uuid = { 0xd0223b96, 0xbf7a, 0x43fd, { 0x92, 0xbd, 0xa4, 0x3b, 0xd, 0x82, 0xb9, 0xeb } }; + + //DEFINE_GUID(IID_ID3D11Device2,0x9d06dffa,0xd1e5,0x4d07,0x83,0xa8,0x1b,0xb1,0x23,0xf2,0xf8,0x41); + static const GUID ID3D11Device2_uuid = { 0x9d06dffa, 0xd1e5, 0x4d07, { 0x83, 0xa8, 0x1b, 0xb1, 0x23, 0xf2, 0xf8, 0x41 } }; + + //1fbad429-66ab-41cc-9617-667ac10e4459 + static const GUID ID3D11ShaderTraceFactory_uuid = { 0x1fbad429, 0x66ab, 0x41cc, { 0x96, 0x17, 0x66, 0x7a, 0xc1, 0x0e, 0x44, 0x59 } }; + + if(riid == __uuidof(IDXGIDevice)) + { + m_pDevice->QueryInterface(riid, ppvObject); + + IDXGIDevice *real = (IDXGIDevice *)(*ppvObject); + *ppvObject = new WrappedIDXGIDevice(real, this); + return S_OK; + } + else if(riid == __uuidof(IDXGIDevice1)) + { + m_pDevice->QueryInterface(riid, ppvObject); + + IDXGIDevice1 *real = (IDXGIDevice1 *)(*ppvObject); + *ppvObject = new WrappedIDXGIDevice1(real, this); + return S_OK; + } + else if(riid == __uuidof(ID3D11Device)) + { + AddRef(); + *ppvObject = (ID3D11Device *)this; + return S_OK; + } + else if(riid == __uuidof(ID3D10Device)) + { + RDCWARN("Trying to get ID3D10Device - not supported."); + *ppvObject = NULL; + return E_NOINTERFACE; + } + else if(riid == IDirect3DDevice9_uuid) + { + RDCWARN("Trying to get IDirect3DDevice9 - not supported."); + *ppvObject = NULL; + return E_NOINTERFACE; + } + else if(riid == __uuidof(ID3D11Device1)) + { + AddRef(); + *ppvObject = (ID3D11Device1 *)this; + return S_OK; + } + else if(riid == ID3D11Device2_uuid) + { + RDCWARN("Trying to get ID3D11Device2. DX11.2 not supported at this time."); + *ppvObject = NULL; + return E_NOINTERFACE; + } + else if(riid == __uuidof(ID3D11ShaderTraceFactory)) + { + RDCWARN("Trying to get ID3D11ShaderTraceFactory. Not supported at this time."); + *ppvObject = NULL; + return E_NOINTERFACE; + } + else if(riid == __uuidof(ID3D11InfoQueue)) + { + RDCWARN("Returning a dumy ID3D11InfoQueue that does nothing. This ID3D11InfoQueue will not work!"); + *ppvObject = (ID3D11InfoQueue *)&m_DummyInfo; + m_DummyInfo.AddRef(); + return S_OK; + } + else + { + string guid = ToStr::Get(riid); + RDCWARN("Querying ID3D11Device for interface: %hs", guid.c_str()); + } + + return m_RefCounter.QueryInterface(riid, ppvObject); +} + +#if defined(ENABLE_NVIDIA_PERFKIT) +#define NVPM_INITGUID +#include STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, inc\\NvPmApi.h)) + +NvPmApi *nvAPI = NULL; +#endif + +#if defined(ENABLE_NVIDIA_PERFKIT) +int enumFunc(NVPMCounterID id, const char *name) +{ + RDCLOG("(% 4d): %hs", id, name); + + return NVPM_OK; +} +#endif + +const char *WrappedID3D11Device::GetChunkName(uint32_t idx) +{ + if(idx < FIRST_CHUNK_ID || idx >= NUM_D3D11_CHUNKS) + return ""; + return D3D11ChunkNames[idx-FIRST_CHUNK_ID]; +} + +void WrappedID3D11Device::LazyInit() +{ + if(m_DebugManager == NULL) + { + m_DebugManager = new D3D11DebugManager(this); + +#if defined(ENABLE_NVIDIA_PERFKIT) + + HMODULE nvapi = LoadLibraryA(STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, bin\\win7_x86\\NvPmApi.Core.dll))); + if(nvapi == NULL) + { + RDCERR("Couldn't load perfkit"); + return; + } + + NVPMGetExportTable_Pfn NVPMGetExportTable = (NVPMGetExportTable_Pfn)GetProcAddress(nvapi, "NVPMGetExportTable"); + if(NVPMGetExportTable == NULL) + { + RDCERR("Couldn't Get Symbol 'NVPMGetExportTable'"); + return; + } + + NVPMRESULT nvResult = NVPMGetExportTable(&ETID_NvPmApi, (void **)&nvAPI); + if(nvResult != NVPM_OK) + { + RDCERR("Couldn't NVPMGetExportTable"); + return; + } + + nvResult = nvAPI->Init(); + + if(nvResult != NVPM_OK) + { + RDCERR("Couldn't nvAPI->Init"); + return; + } + + NVPMContext context(0); + nvResult = nvAPI->CreateContextFromD3D11Device(m_pDevice, &context); + + if(nvResult != NVPM_OK) + { + RDCERR("Couldn't nvAPI->CreateContextFromD3D11Device"); + return; + } + + nvAPI->EnumCountersByContext(context, &enumFunc); + + nvAPI->DestroyContext(context); + nvAPI->Shutdown(); + nvAPI = NULL; + FreeLibrary(nvapi); +#endif + } +} + +vector WrappedID3D11Device::GetDebugMessages() +{ + vector ret; + + if(!m_pInfoQueue) + return ret; + + UINT64 numMessages = m_pInfoQueue->GetNumStoredMessagesAllowedByRetrievalFilter(); + + for(UINT64 i=0; i < m_pInfoQueue->GetNumStoredMessagesAllowedByRetrievalFilter(); i++) + { + SIZE_T len = 0; + m_pInfoQueue->GetMessage(i, NULL, &len); + + char *msgbuf = new char[len]; + D3D11_MESSAGE *message = (D3D11_MESSAGE *)msgbuf; + + m_pInfoQueue->GetMessage(i, message, &len); + + DebugMessage msg; + msg.category = eDbgCategory_Miscellaneous; + msg.severity = eDbgSeverity_Error; + + switch(message->Category) + { + case D3D11_MESSAGE_CATEGORY_APPLICATION_DEFINED: + msg.category = eDbgCategory_Application_Defined; + break; + case D3D11_MESSAGE_CATEGORY_MISCELLANEOUS: + msg.category = eDbgCategory_Miscellaneous; + break; + case D3D11_MESSAGE_CATEGORY_INITIALIZATION: + msg.category = eDbgCategory_Initialization; + break; + case D3D11_MESSAGE_CATEGORY_CLEANUP: + msg.category = eDbgCategory_Cleanup; + break; + case D3D11_MESSAGE_CATEGORY_COMPILATION: + msg.category = eDbgCategory_Compilation; + break; + case D3D11_MESSAGE_CATEGORY_STATE_CREATION: + msg.category = eDbgCategory_State_Creation; + break; + case D3D11_MESSAGE_CATEGORY_STATE_SETTING: + msg.category = eDbgCategory_State_Setting; + break; + case D3D11_MESSAGE_CATEGORY_STATE_GETTING: + msg.category = eDbgCategory_State_Getting; + break; + case D3D11_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: + msg.category = eDbgCategory_Resource_Manipulation; + break; + case D3D11_MESSAGE_CATEGORY_EXECUTION: + msg.category = eDbgCategory_Execution; + break; + case D3D11_MESSAGE_CATEGORY_SHADER: + msg.category = eDbgCategory_Shaders; + break; + default: + RDCWARN("Unexpected message category: %d", message->Category); + break; + } + + switch(message->Severity) + { + case D3D11_MESSAGE_SEVERITY_CORRUPTION: + msg.severity = eDbgSeverity_Corruption; + break; + case D3D11_MESSAGE_SEVERITY_ERROR: + msg.severity = eDbgSeverity_Error; + break; + case D3D11_MESSAGE_SEVERITY_WARNING: + msg.severity = eDbgSeverity_Warning; + break; + case D3D11_MESSAGE_SEVERITY_INFO: + msg.severity = eDbgSeverity_Info; + break; + case D3D11_MESSAGE_SEVERITY_MESSAGE: + msg.severity = eDbgSeverity_Info; + break; + default: + RDCWARN("Unexpected message severity: %d", message->Severity); + break; + } + + msg.messageID = (uint32_t)message->ID; + msg.description = string(message->pDescription); + + ret.push_back(msg); + + SAFE_DELETE_ARRAY(msgbuf); + } + + // Docs are fuzzy on the thread safety of the info queue, but I'm going to assume it should only + // ever be accessed on one thread since it's tied to the device & immediate context. + // There doesn't seem to be a way to lock it for access and without that there's no way to know + // that a new message won't be added between the time you retrieve the last one and clearing the + // queue. There is also no way to pop a message that I can see, which would presumably be the + // best way if its member functions are thread safe themselves (if the queue is protected internally). + RDCASSERT(numMessages == m_pInfoQueue->GetNumStoredMessagesAllowedByRetrievalFilter()); + + m_pInfoQueue->ClearStoredMessages(); + + return ret; +} + +void WrappedID3D11Device::ProcessChunk(uint64_t offset, D3D11ChunkType context) +{ + switch(context) + { + case DEVICE_INIT: + { + SERIALISE_ELEMENT(ResourceId, immContextId, ResourceId()); + + // add a reference for the resource manager - normally it takes ownership of the resource on creation and releases it + // to destruction, but we want to control our immediate context ourselves. + m_pImmediateContext->AddRef(); + m_ResourceManager->AddLiveResource(immContextId, m_pImmediateContext); + break; + } + case SET_RESOURCE_NAME: + Serialise_SetResourceName(0x0, ""); + break; + case RELEASE_RESOURCE: + Serialise_ReleaseResource(0x0); + break; + case CREATE_SWAP_BUFFER: + Serialise_SetSwapChainTexture(0x0, 0x0, 0, 0x0); + break; + case CREATE_TEXTURE_1D: + Serialise_CreateTexture1D(0x0, 0x0, 0x0); + break; + case CREATE_TEXTURE_2D: + Serialise_CreateTexture2D(0x0, 0x0, 0x0); + break; + case CREATE_TEXTURE_3D: + Serialise_CreateTexture3D(0x0, 0x0, 0x0); + break; + case CREATE_BUFFER: + Serialise_CreateBuffer(0x0, 0x0, 0x0); + break; + case CREATE_VERTEX_SHADER: + Serialise_CreateVertexShader(0x0, 0, 0x0, 0x0); + break; + case CREATE_HULL_SHADER: + Serialise_CreateHullShader(0x0, 0, 0x0, 0x0); + break; + case CREATE_DOMAIN_SHADER: + Serialise_CreateDomainShader(0x0, 0, 0x0, 0x0); + break; + case CREATE_GEOMETRY_SHADER: + Serialise_CreateGeometryShader(0x0, 0, 0x0, 0x0); + break; + case CREATE_GEOMETRY_SHADER_WITH_SO: + Serialise_CreateGeometryShaderWithStreamOutput(0x0, 0, 0x0, 0, 0x0, 0, 0, 0x0, 0x0); + break; + case CREATE_PIXEL_SHADER: + Serialise_CreatePixelShader(0x0, 0, 0x0, 0x0); + break; + case CREATE_COMPUTE_SHADER: + Serialise_CreateComputeShader(0x0, 0, 0x0, 0x0); + break; + case GET_CLASS_INSTANCE: + Serialise_GetClassInstance(0x0, 0, 0x0, 0x0); + break; + case CREATE_CLASS_INSTANCE: + Serialise_CreateClassInstance(0x0, 0, 0, 0, 0, 0x0, 0x0); + break; + case CREATE_CLASS_LINKAGE: + Serialise_CreateClassLinkage(0x0); + break; + case CREATE_SRV: + Serialise_CreateShaderResourceView(0x0, 0x0, 0x0); + break; + case CREATE_RTV: + Serialise_CreateRenderTargetView(0x0, 0x0, 0x0); + break; + case CREATE_DSV: + Serialise_CreateDepthStencilView(0x0, 0x0, 0x0); + break; + case CREATE_UAV: + Serialise_CreateUnorderedAccessView(0x0, 0x0, 0x0); + break; + case CREATE_INPUT_LAYOUT: + Serialise_CreateInputLayout(0x0, 0, 0x0, 0, 0x0); + break; + case CREATE_BLEND_STATE: + Serialise_CreateBlendState(0x0, 0x0); + break; + case CREATE_BLEND_STATE1: + Serialise_CreateBlendState1(0x0, 0x0); + break; + case CREATE_DEPTHSTENCIL_STATE: + Serialise_CreateDepthStencilState(0x0, 0x0); + break; + case CREATE_RASTER_STATE: + Serialise_CreateRasterizerState(0x0, 0x0); + break; + case CREATE_RASTER_STATE1: + Serialise_CreateRasterizerState1(0x0, 0x0); + break; + case CREATE_SAMPLER_STATE: + Serialise_CreateSamplerState(0x0, 0x0); + break; + case CREATE_QUERY: + Serialise_CreateQuery(0x0, 0x0); + break; + case CREATE_PREDICATE: + Serialise_CreatePredicate(0x0, 0x0); + break; + case CREATE_COUNTER: + Serialise_CreateCounter(0x0, 0x0); + break; + case CREATE_DEFERRED_CONTEXT: + Serialise_CreateDeferredContext(0, 0x0); + break; + case SET_EXCEPTION_MODE: + Serialise_SetExceptionMode(0); + break; + case OPEN_SHARED_RESOURCE: + { + IID nul; + Serialise_OpenSharedResource(0, nul, NULL); + break; + } + case CAPTURE_SCOPE: + Serialise_CaptureScope(offset); + break; + default: + // ignore system chunks + if(context == INITIAL_CONTENTS) + Serialise_InitialState(NULL); + else if(context < FIRST_CHUNK_ID) + m_pSerialiser->SkipCurrentChunk(); + else + m_pImmediateContext->ProcessChunk(offset, context, true); + break; + } +} + +void WrappedID3D11Device::Serialise_CaptureScope(uint64_t offset) +{ + SERIALISE_ELEMENT(uint32_t, FrameNumber, m_FrameCounter); + + if(m_State >= WRITING) + { + GetResourceManager()->Serialise_InitialContentsNeeded(m_pSerialiser); + } + else + { + FetchFrameRecord record; + record.frameInfo.fileOffset = offset; + record.frameInfo.firstEvent = m_pImmediateContext->GetEventID(); + record.frameInfo.frameNumber = FrameNumber; + record.frameInfo.immContextId = GetResourceManager()->GetOriginalID(m_pImmediateContext->GetResourceID()); + m_FrameRecord.push_back(record); + + GetResourceManager()->CreateInitialContents(m_pSerialiser); + } +} + +void WrappedID3D11Device::ReadLogInitialisation() +{ + uint64_t lastFrame = 0; + uint64_t firstFrame = 0; + + LazyInit(); + + m_pSerialiser->SetDebugText(true); + + m_pSerialiser->Rewind(); + + while(!m_pSerialiser->AtEnd()) + { + m_pSerialiser->SkipToChunk(CAPTURE_SCOPE); + + // found a capture chunk + if(!m_pSerialiser->AtEnd()) + { + lastFrame = m_pSerialiser->GetOffset(); + if(firstFrame == 0) + firstFrame = m_pSerialiser->GetOffset(); + + // skip this chunk + m_pSerialiser->PushContext(NULL, CAPTURE_SCOPE, false); + m_pSerialiser->SkipCurrentChunk(); + m_pSerialiser->PopContext(NULL, CAPTURE_SCOPE); + } + } + + m_pSerialiser->Rewind(); + + int chunkIdx = 0; + + struct chunkinfo + { + chunkinfo() : count(0), total(0.0) {} + int count; + double total; + }; + + map chunkInfos; + + SCOPED_TIMER("chunk initialisation"); + + while(1) + { + PerformanceTimer timer; + + uint64_t offset = m_pSerialiser->GetOffset(); + + D3D11ChunkType context = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); + + chunkIdx++; + + ProcessChunk(offset, context); + + m_pSerialiser->PopContext(NULL, context); + + RenderDoc::Inst().SetProgress(FileInitialRead, float(m_pSerialiser->GetOffset())/float(m_pSerialiser->GetSize())); + + if(context == CAPTURE_SCOPE) + { + m_pImmediateContext->ReplayLog(READING, 0, 0, false); + + if(m_pSerialiser->GetOffset() > lastFrame) + break; + } + + chunkInfos[context].total += timer.GetMilliseconds(); + chunkInfos[context].count++; + + if(m_pSerialiser->AtEnd()) + { + break; + } + } + + for(auto it=chunkInfos.begin(); it != chunkInfos.end(); ++it) + { + RDCDEBUG("%hs: %.3f total time in %d chunks - %.3f average", + GetChunkName(it->first), it->second.total, it->second.count, + it->second.total/double(it->second.count)); + } + + RDCDEBUG("Allocating %llu persistant bytes of memory for the log.", m_pSerialiser->GetSize() - firstFrame); + + m_pSerialiser->SetDebugText(false); + + m_pSerialiser->SetBase(firstFrame); +} + +bool WrappedID3D11Device::Prepare_InitialState(ID3D11DeviceChild *res) +{ + ResourceType type = IdentifyTypeByPtr(res); + ResourceId Id = GetIDForResource(res); + + RDCASSERT(m_State >= WRITING); + + { + RDCDEBUG("Prepare_InitialState(%llu)", Id); + + if(type == Resource_Buffer) + RDCDEBUG(" .. buffer"); + else if(type == Resource_UnorderedAccessView) + RDCDEBUG(" .. UAV"); + else if(type == Resource_Texture1D || + type == Resource_Texture2D || + type == Resource_Texture3D) + { + if(type == Resource_Texture1D) + RDCDEBUG(" .. tex1d"); + else if(type == Resource_Texture2D) + RDCDEBUG(" .. tex2d"); + else if(type == Resource_Texture3D) + RDCDEBUG(" .. tex3d"); + } + else + RDCERR(" .. other!"); + } + + if(type == Resource_UnorderedAccessView) + { + WrappedID3D11UnorderedAccessView *uav = (WrappedID3D11UnorderedAccessView *)res; + + D3D11_UNORDERED_ACCESS_VIEW_DESC udesc; + uav->GetDesc(&udesc); + + if(udesc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER && + (udesc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_COUNTER|D3D11_BUFFER_UAV_FLAG_APPEND)) != 0) + { + ID3D11Buffer *stage = NULL; + + D3D11_BUFFER_DESC desc; + desc.BindFlags = 0; + desc.ByteWidth = 16; + desc.MiscFlags = 0; + desc.StructureByteStride = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + HRESULT hr = m_pDevice->CreateBuffer(&desc, NULL, &stage); + + if(FAILED(hr) || stage == NULL) + { + RDCERR("Failed to create staging buffer for UAV initial contents %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyStructureCount(stage, 0, UNWRAP(WrappedID3D11UnorderedAccessView, uav)); + + m_ResourceManager->SetInitialContents(Id, stage, 0); + } + } + } + else if(type == Resource_Buffer) + { + WrappedID3D11Buffer *buf = (WrappedID3D11Buffer *)res; + D3D11ResourceRecord *record = m_ResourceManager->GetResourceRecord(Id); + + ID3D11Buffer *stage = NULL; + + D3D11_BUFFER_DESC desc; + desc.BindFlags = 0; + desc.ByteWidth = record->Length; + desc.MiscFlags = 0; + desc.StructureByteStride = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + HRESULT hr = m_pDevice->CreateBuffer(&desc, NULL, &stage); + + if(FAILED(hr) || stage == NULL) + { + RDCERR("Failed to create staging buffer for buffer initial contents %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyResource(stage, UNWRAP(WrappedID3D11Buffer, buf)); + + m_ResourceManager->SetInitialContents(Id, stage, 0); + } + } + else if(type == Resource_Texture1D) + { + WrappedID3D11Texture1D *tex1D = (WrappedID3D11Texture1D *)res; + D3D11ResourceRecord *record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_TEXTURE1D_DESC desc; + tex1D->GetDesc(&desc); + + UINT numSubresources = desc.MipLevels*desc.ArraySize; + + D3D11_TEXTURE1D_DESC stageDesc = desc; + ID3D11Texture1D *stage = NULL; + + stageDesc.MiscFlags = 0; + stageDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stageDesc.BindFlags = 0; + stageDesc.Usage = D3D11_USAGE_STAGING; + + HRESULT hr = m_pDevice->CreateTexture1D(&stageDesc, NULL, &stage); + + if(FAILED(hr)) + { + RDCERR("Failed to create initial tex1D %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyResource(stage, UNWRAP(WrappedID3D11Texture1D, tex1D)); + + m_ResourceManager->SetInitialContents(Id, stage, 0); + } + } + else if(type == Resource_Texture2D) + { + WrappedID3D11Texture2D *tex2D = (WrappedID3D11Texture2D *)res; + D3D11ResourceRecord *record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_TEXTURE2D_DESC desc; + tex2D->GetDesc(&desc); + + UINT numSubresources = desc.MipLevels*desc.ArraySize; + + bool multisampled = desc.SampleDesc.Count > 1 || desc.SampleDesc.Quality > 0; + + D3D11_TEXTURE2D_DESC stageDesc = desc; + ID3D11Texture2D *stage = NULL; + + stageDesc.MiscFlags = 0; + stageDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stageDesc.BindFlags = 0; + stageDesc.Usage = D3D11_USAGE_STAGING; + + // expand out each sample into an array slice. Hope + // that this doesn't blow over the array size limit + // (that would be pretty insane) + if(multisampled) + { + stageDesc.SampleDesc.Count = 1; + stageDesc.SampleDesc.Quality = 0; + stageDesc.ArraySize *= desc.SampleDesc.Count; + } + + HRESULT hr = m_pDevice->CreateTexture2D(&stageDesc, NULL, &stage); + + if(FAILED(hr)) + { + RDCERR("Failed to create initial tex2D %08x", hr); + } + else + { + IDXGIKeyedMutex *mutex = NULL; + + if(desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) + { + HRESULT hr = UNWRAP(WrappedID3D11Texture2D, tex2D)->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)&mutex); + + if(SUCCEEDED(hr) && mutex) + { + // complete guess but let's try and acquire key 0 so we can cop this texture out. + mutex->AcquireSync(0, 10); + + // if it failed, give up. Otherwise we can release the sync below + if(FAILED(hr)) + SAFE_RELEASE(mutex); + } + else + { + SAFE_RELEASE(mutex); + } + } + + if(multisampled) + m_DebugManager->CopyTex2DMSToArray(stage, UNWRAP(WrappedID3D11Texture2D, tex2D)); + else + m_pImmediateContext->GetReal()->CopyResource(stage, UNWRAP(WrappedID3D11Texture2D, tex2D)); + + m_pImmediateContext->GetReal()->Flush(); + + if(mutex) + { + mutex->ReleaseSync(0); + + SAFE_RELEASE(mutex); + } + + m_ResourceManager->SetInitialContents(Id, stage, 0); + } + } + else if(type == Resource_Texture3D) + { + WrappedID3D11Texture3D *tex3D = (WrappedID3D11Texture3D *)res; + D3D11ResourceRecord *record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_TEXTURE3D_DESC desc; + tex3D->GetDesc(&desc); + + UINT numSubresources = desc.MipLevels; + + D3D11_TEXTURE3D_DESC stageDesc = desc; + ID3D11Texture3D *stage = NULL; + + stageDesc.MiscFlags = 0; + stageDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stageDesc.BindFlags = 0; + stageDesc.Usage = D3D11_USAGE_STAGING; + + HRESULT hr = m_pDevice->CreateTexture3D(&stageDesc, NULL, &stage); + + if(FAILED(hr)) + { + RDCERR("Failed to create initial tex3D %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyResource(stage, UNWRAP(WrappedID3D11Texture3D, tex3D)); + + m_ResourceManager->SetInitialContents(Id, stage, 0); + } + } + + return true; +} + +bool WrappedID3D11Device::Serialise_InitialState(ID3D11DeviceChild *res) +{ + ResourceType type = Resource_Unknown; + ResourceId Id = ResourceId(); + + if(m_State >= WRITING) + { + type = IdentifyTypeByPtr(res); + Id = GetIDForResource(res); + + if(type != Resource_Buffer) + { + m_pSerialiser->Serialise("type", type); + m_pSerialiser->Serialise("Id", Id); + } + } + else + { + m_pSerialiser->Serialise("type", type); + m_pSerialiser->Serialise("Id", Id); + } + + { + RDCDEBUG("Serialise_InitialState(%llu)", Id); + + if(type == Resource_Buffer) + RDCDEBUG(" .. buffer"); + else if(type == Resource_UnorderedAccessView) + RDCDEBUG(" .. UAV"); + else if(type == Resource_Texture1D || + type == Resource_Texture2D || + type == Resource_Texture3D) + { + if(type == Resource_Texture1D) + RDCDEBUG(" .. tex1d"); + else if(type == Resource_Texture2D) + RDCDEBUG(" .. tex2d"); + else if(type == Resource_Texture3D) + RDCDEBUG(" .. tex3d"); + } + else + RDCERR(" .. other!"); + } + + if(type == Resource_UnorderedAccessView) + { + WrappedID3D11UnorderedAccessView *uav = (WrappedID3D11UnorderedAccessView *)res; + if(m_State < WRITING) + { + if(m_ResourceManager->HasLiveResource(Id)) + { + uav = (WrappedID3D11UnorderedAccessView *)m_ResourceManager->GetLiveResource(Id); + } + else + { + uav = NULL; + SERIALISE_ELEMENT(uint32_t, initCount, 0); + return true; + } + } + + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + uav->GetDesc(&desc); + + if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER && + (desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_COUNTER|D3D11_BUFFER_UAV_FLAG_APPEND)) != 0) + { + if(m_State >= WRITING) + { + ID3D11Buffer *stage = (ID3D11Buffer *)m_ResourceManager->GetInitialContents(Id); + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = m_pImmediateContext->GetReal()->Map(stage, 0, D3D11_MAP_READ, 0, &mapped); + + uint32_t countData = 0; + + if(FAILED(hr)) + { + RDCERR("Failed to map while getting initial states %08x", hr); + } + else + { + countData = *((uint32_t *)mapped.pData); + + m_pImmediateContext->GetReal()->Unmap(stage, 0); + } + + SERIALISE_ELEMENT(uint32_t, count, countData); + } + else + { + SERIALISE_ELEMENT(uint32_t, initCount, 0); + + m_ResourceManager->SetInitialContents(Id, NULL, initCount); + } + } + else + { + SERIALISE_ELEMENT(uint32_t, initCount, 0); + } + } + else if(type == Resource_Buffer) + { + if(m_State >= WRITING) + { + WrappedID3D11Buffer *buf = (WrappedID3D11Buffer *)res; + D3D11ResourceRecord *record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_BUFFER_DESC desc; + desc.BindFlags = 0; + desc.ByteWidth = record->Length; + desc.MiscFlags = 0; + desc.StructureByteStride = 0; + + ID3D11Buffer *stage = (ID3D11Buffer *)m_ResourceManager->GetInitialContents(Id); + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = m_pImmediateContext->GetReal()->Map(stage, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map while getting initial states %08x", hr); + } + else + { + RDCASSERT(record->DataInSerialiser); + + MapIntercept intercept; + intercept.SetD3D(mapped); + intercept.Init(buf, record->GetDataPtr()); + intercept.CopyFromD3D(); + + m_pImmediateContext->GetReal()->Unmap(stage, 0); + } + } + } + else if(type == Resource_Texture1D) + { + WrappedID3D11Texture1D *tex1D = (WrappedID3D11Texture1D *)res; + if(m_State < WRITING) + tex1D = (WrappedID3D11Texture1D *)m_ResourceManager->GetLiveResource(Id); + + D3D11ResourceRecord *record = NULL; + if(m_State >= WRITING) + record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_TEXTURE1D_DESC desc; + tex1D->GetDesc(&desc); + + SERIALISE_ELEMENT(uint32_t, numSubresources, desc.MipLevels*desc.ArraySize); + + { + if(m_State < WRITING) + { + ID3D11Texture1D *contents = (ID3D11Texture1D *)m_ResourceManager->GetInitialContents(Id); + + RDCASSERT(!contents); + } + + byte *inmemBuffer = NULL; + D3D11_SUBRESOURCE_DATA *subData = NULL; + + if(m_State >= WRITING) + { + inmemBuffer = new byte[GetByteSize(desc.Width, 1, 1, desc.Format, 0)]; + } + else + { + subData = new D3D11_SUBRESOURCE_DATA[numSubresources]; + } + + ID3D11Texture1D *stage = (ID3D11Texture1D *)m_ResourceManager->GetInitialContents(Id); + + for(UINT sub = 0; sub < numSubresources; sub++) + { + UINT mip = GetMipForSubresource(tex1D, sub); + + if(m_State >= WRITING) + { + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->GetReal()->Map(stage, sub, D3D11_MAP_READ, 0, &mapped); + + size_t dstPitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + + if(FAILED(hr)) + { + RDCERR("Failed to map in initial states %08x", hr); + } + else + { + uint32_t rowsPerLine = 1; + + byte *dst = inmemBuffer; + byte *src = (byte *)mapped.pData; + + memcpy(inmemBuffer, mapped.pData, dstPitch); + } + + size_t len = dstPitch; + m_pSerialiser->SerialiseBuffer("", inmemBuffer, len); + + if(SUCCEEDED(hr)) + m_pImmediateContext->GetReal()->Unmap(stage, 0); + } + else + { + byte *data = NULL; + size_t len = 0; + m_pSerialiser->SerialiseBuffer("", data, len); + + subData[sub].pSysMem = data; + subData[sub].SysMemPitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + subData[sub].SysMemSlicePitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + } + } + + SAFE_DELETE_ARRAY(inmemBuffer); + + if(m_State < WRITING) + { + // We don't need to bind this, but IMMUTABLE requires at least one + // BindFlags. + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.MiscFlags = 0; + + ID3D11Texture1D *contents = NULL; + HRESULT hr = m_pDevice->CreateTexture1D(&desc, subData, &contents); + + if(FAILED(hr) || contents == NULL) + { + RDCERR("Failed to create staging resource for Texture1D initial contents %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(Id, contents, 0); + } + + for(UINT sub = 0; sub < numSubresources; sub++) + SAFE_DELETE_ARRAY(subData[sub].pSysMem); + SAFE_DELETE_ARRAY(subData); + } + } + } + else if(type == Resource_Texture2D) + { + WrappedID3D11Texture2D *tex2D = (WrappedID3D11Texture2D *)res; + if(m_State < WRITING) + tex2D = (WrappedID3D11Texture2D *)m_ResourceManager->GetLiveResource(Id); + + D3D11ResourceRecord *record = NULL; + if(m_State >= WRITING) + record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_TEXTURE2D_DESC desc; + tex2D->GetDesc(&desc); + + SERIALISE_ELEMENT(uint32_t, numSubresources, desc.MipLevels*desc.ArraySize); + + bool bigrt = ((desc.BindFlags & D3D11_BIND_RENDER_TARGET) != 0 || + (desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) != 0 || + (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) != 0) && (desc.Width > 64 && desc.Height > 64); + + if(bigrt && m_ResourceManager->ReadBeforeWrite(Id)) + bigrt = false; + + bool multisampled = desc.SampleDesc.Count > 1 || desc.SampleDesc.Quality > 0; + + if(multisampled) + numSubresources *= desc.SampleDesc.Count; + + SERIALISE_ELEMENT(bool, omitted, bigrt && !RenderDoc::Inst().GetCaptureOptions().SaveAllInitials); + + if(omitted) + { + if(m_State >= WRITING) + { + RDCWARN("Not serialising texture 2D initial state. ID %llu", Id); + if(bigrt) + RDCWARN("Detected Write before Read of this target - assuming initial contents are unneeded.\n" \ + "Capture again with Save All Initials if this is wrong"); + } + } + else + { + if(m_State < WRITING) + { + ID3D11Texture2D *contents = (ID3D11Texture2D *)m_ResourceManager->GetInitialContents(Id); + + RDCASSERT(!contents); + } + + byte *inmemBuffer = NULL; + D3D11_SUBRESOURCE_DATA *subData = NULL; + + if(m_State >= WRITING) + { + inmemBuffer = new byte[GetByteSize(desc.Width, desc.Height, 1, desc.Format, 0)]; + } + else + { + subData = new D3D11_SUBRESOURCE_DATA[numSubresources]; + } + + ID3D11Texture2D *stage = (ID3D11Texture2D *)m_ResourceManager->GetInitialContents(Id); + + for(UINT sub = 0; sub < numSubresources; sub++) + { + UINT mip = GetMipForSubresource(tex2D, sub); + + if(m_State >= WRITING) + { + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->GetReal()->Map(stage, sub, D3D11_MAP_READ, 0, &mapped); + + size_t dstPitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + size_t len = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + + uint32_t rowsPerLine = 1; + if(IsBlockFormat(desc.Format)) + rowsPerLine = 4; + + if(FAILED(hr)) + { + RDCERR("Failed to map in initial states %08x", hr); + } + else + { + byte *dst = inmemBuffer; + byte *src = (byte *)mapped.pData; + for(uint32_t row=0; row < desc.Height>>mip; row += rowsPerLine) + { + memcpy(dst, src, dstPitch); + dst += dstPitch; + src += mapped.RowPitch; + } + } + + m_pSerialiser->SerialiseBuffer("", inmemBuffer, len); + + m_pImmediateContext->GetReal()->Unmap(stage, sub); + } + else + { + byte *data = NULL; + size_t len = 0; + m_pSerialiser->SerialiseBuffer("", data, len); + + subData[sub].pSysMem = data; + subData[sub].SysMemPitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + subData[sub].SysMemSlicePitch = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + } + } + + SAFE_DELETE_ARRAY(inmemBuffer); + + if(m_State < WRITING) + { + // We don't need to bind this, but IMMUTABLE requires at least one + // BindFlags. + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + switch(desc.Format) + { + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + desc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + break; + case DXGI_FORMAT_D32_FLOAT: + desc.Format = DXGI_FORMAT_R32_FLOAT; + break; + case DXGI_FORMAT_D24_UNORM_S8_UINT: + desc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + break; + case DXGI_FORMAT_D16_UNORM: + desc.Format = DXGI_FORMAT_R16_FLOAT; + break; + default: + break; + } + + D3D11_TEXTURE2D_DESC initialDesc = desc; + // if multisampled, need to upload subData into an array with slices for each sample. + if(multisampled) + { + initialDesc.SampleDesc.Count = 1; + initialDesc.SampleDesc.Quality = 0; + initialDesc.ArraySize *= desc.SampleDesc.Count; + } + + initialDesc.Usage = D3D11_USAGE_IMMUTABLE; + + ID3D11Texture2D *contents = NULL; + HRESULT hr = m_pDevice->CreateTexture2D(&initialDesc, subData, &contents); + + if(FAILED(hr) || contents == NULL) + { + RDCERR("Failed to create staging resource for Texture2D initial contents %08x", hr); + } + else + { + // if multisampled, contents is actually an array with slices for each sample. + // need to copy back out to a real multisampled resource + if(multisampled) + { + desc.BindFlags = IsDepthFormat(desc.Format) ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET; + + if(IsDepthFormat(desc.Format)) + desc.Format = GetDepthTypedFormat(desc.Format); + + ID3D11Texture2D *contentsMS = NULL; + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &contentsMS); + + m_DebugManager->CopyArrayToTex2DMS(contentsMS, contents); + + SAFE_RELEASE(contents); + contents = contentsMS; + } + + m_ResourceManager->SetInitialContents(Id, contents, 0); + } + + for(UINT sub = 0; sub < numSubresources; sub++) + SAFE_DELETE_ARRAY(subData[sub].pSysMem); + SAFE_DELETE_ARRAY(subData); + } + } + } + else if(type == Resource_Texture3D) + { + WrappedID3D11Texture3D *tex3D = (WrappedID3D11Texture3D *)res; + if(m_State < WRITING) + tex3D = (WrappedID3D11Texture3D *)m_ResourceManager->GetLiveResource(Id); + + D3D11ResourceRecord *record = NULL; + if(m_State >= WRITING) + record = m_ResourceManager->GetResourceRecord(Id); + + D3D11_TEXTURE3D_DESC desc; + tex3D->GetDesc(&desc); + + SERIALISE_ELEMENT(uint32_t, numSubresources, desc.MipLevels); + + { + if(m_State < WRITING) + { + ID3D11Texture3D *contents = (ID3D11Texture3D *)m_ResourceManager->GetInitialContents(Id); + + RDCASSERT(!contents); + } + + byte *inmemBuffer = NULL; + D3D11_SUBRESOURCE_DATA *subData = NULL; + + if(m_State >= WRITING) + { + inmemBuffer = new byte[GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, 0)]; + } + else + { + subData = new D3D11_SUBRESOURCE_DATA[numSubresources]; + } + + ID3D11Texture3D *stage = (ID3D11Texture3D *)m_ResourceManager->GetInitialContents(Id); + + for(UINT sub = 0; sub < numSubresources; sub++) + { + UINT mip = GetMipForSubresource(tex3D, sub); + + if(m_State >= WRITING) + { + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->GetReal()->Map(stage, sub, D3D11_MAP_READ, 0, &mapped); + + size_t dstPitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + size_t dstSlicePitch = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + + uint32_t rowsPerLine = 1; + if(IsBlockFormat(desc.Format)) + rowsPerLine = 4; + + if(FAILED(hr)) + { + RDCERR("Failed to map in initial states %08x", hr); + } + else + { + byte *dst = inmemBuffer; + byte *src = (byte *)mapped.pData; + + for(uint32_t slice=0; slice < RDCMAX(1U,desc.Depth>>mip); slice++) + { + byte *sliceDst = dst; + byte *sliceSrc = src; + + for(uint32_t row=0; row < RDCMAX(1U,desc.Height>>mip); row += rowsPerLine) + { + memcpy(sliceDst, sliceSrc, dstPitch); + sliceDst += dstPitch; + sliceSrc += mapped.RowPitch; + } + + dst += dstSlicePitch; + src += mapped.DepthPitch; + } + } + + size_t len = dstSlicePitch*desc.Depth; + m_pSerialiser->SerialiseBuffer("", inmemBuffer, len); + + m_pImmediateContext->GetReal()->Unmap(stage, 0); + } + else + { + byte *data = NULL; + size_t len = 0; + m_pSerialiser->SerialiseBuffer("", data, len); + + subData[sub].pSysMem = data; + subData[sub].SysMemPitch = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + subData[sub].SysMemSlicePitch = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + } + } + + SAFE_DELETE_ARRAY(inmemBuffer); + + if(m_State < WRITING) + { + // We don't need to bind this, but IMMUTABLE requires at least one + // BindFlags. + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.MiscFlags = 0; + + ID3D11Texture3D *contents = NULL; + HRESULT hr = m_pDevice->CreateTexture3D(&desc, subData, &contents); + + if(FAILED(hr) || contents == NULL) + { + RDCERR("Failed to create staging resource for Texture3D initial contents %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(Id, contents, 0); + } + + for(UINT sub = 0; sub < numSubresources; sub++) + SAFE_DELETE_ARRAY(subData[sub].pSysMem); + SAFE_DELETE_ARRAY(subData); + } + } + } + else + { + RDCERR("Trying to serialise initial state of unsupported resource type"); + } + + return true; +} + +void WrappedID3D11Device::Create_InitialState(ResourceId id, ID3D11DeviceChild *live, bool hasData) +{ + ResourceType type = IdentifyTypeByPtr(live); + + { + RDCDEBUG("Create_InitialState(%llu)", id); + + if(type == Resource_Buffer) + RDCDEBUG(" .. buffer"); + else if(type == Resource_UnorderedAccessView) + RDCDEBUG(" .. UAV"); + else if(type == Resource_Texture1D || + type == Resource_Texture2D || + type == Resource_Texture3D) + { + if(type == Resource_Texture1D) + RDCDEBUG(" .. tex1d"); + else if(type == Resource_Texture2D) + RDCDEBUG(" .. tex2d"); + else if(type == Resource_Texture3D) + RDCDEBUG(" .. tex3d"); + } + else + RDCERR(" .. other!"); + } + + if(type == Resource_UnorderedAccessView) + { + WrappedID3D11UnorderedAccessView *uav = (WrappedID3D11UnorderedAccessView *)live; + + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + uav->GetDesc(&desc); + + if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER && + (desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_COUNTER|D3D11_BUFFER_UAV_FLAG_APPEND)) != 0) + { + ID3D11Buffer *stage = NULL; + + D3D11_BUFFER_DESC desc; + desc.BindFlags = 0; + desc.ByteWidth = 16; + desc.MiscFlags = 0; + desc.StructureByteStride = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + HRESULT hr = m_pDevice->CreateBuffer(&desc, NULL, &stage); + + if(FAILED(hr) || stage == NULL) + { + RDCERR("Failed to create staging resource for UAV initial contents %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyStructureCount(stage, 0, UNWRAP(WrappedID3D11UnorderedAccessView, uav)); + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = m_pImmediateContext->GetReal()->Map(stage, 0, D3D11_MAP_READ, 0, &mapped); + + uint32_t countData = 0; + + if(FAILED(hr)) + { + RDCERR("Failed to map while creating initial states %08x", hr); + } + else + { + countData = *((uint32_t *)mapped.pData); + + m_pImmediateContext->GetReal()->Unmap(stage, 0); + } + + m_ResourceManager->SetInitialContents(id, NULL, countData); + + SAFE_RELEASE(stage); + } + } + } + else if(type == Resource_Texture1D) + { + WrappedID3D11Texture1D *tex1D = (WrappedID3D11Texture1D *)live; + + D3D11_TEXTURE1D_DESC desc; + tex1D->GetDesc(&desc); + + if(!hasData && desc.MipLevels == 1 && (desc.BindFlags & D3D11_BIND_RENDER_TARGET)) + { + D3D11_RENDER_TARGET_VIEW_DESC rdesc; + rdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; + rdesc.Format = GetTypedFormat(desc.Format); + rdesc.Texture1D.MipSlice = 0; + + ID3D11RenderTargetView *initContents = NULL; + + HRESULT hr = m_pDevice->CreateRenderTargetView(UNWRAP(WrappedID3D11Texture1D, tex1D), &rdesc, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create fast-clear RTV while creating initial states %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(id, initContents, 1); + } + } + else if(!hasData && desc.MipLevels == 1 && (desc.BindFlags & D3D11_BIND_DEPTH_STENCIL)) + { + D3D11_DEPTH_STENCIL_VIEW_DESC ddesc; + ddesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1D; + ddesc.Format = GetDepthTypedFormat(desc.Format); + ddesc.Texture1D.MipSlice = 0; + ddesc.Flags = 0; + + ID3D11DepthStencilView *initContents = NULL; + + HRESULT hr = m_pDevice->CreateDepthStencilView(UNWRAP(WrappedID3D11Texture1D, tex1D), &ddesc, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create fast-clear DSV while creating initial states %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(id, initContents, 2); + } + } + else if(desc.Usage != D3D11_USAGE_IMMUTABLE) + { + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = 0; + if(IsDepthFormat(desc.Format)) + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + desc.MiscFlags &= ~D3D11_RESOURCE_MISC_GENERATE_MIPS; + + ID3D11Texture1D *initContents = NULL; + + HRESULT hr = m_pDevice->CreateTexture1D(&desc, NULL, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create tex3D while creating initial states %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyResource(initContents, UNWRAP(WrappedID3D11Texture1D, tex1D)); + + m_ResourceManager->SetInitialContents(id, initContents, 0); + } + } + } + else if(type == Resource_Texture2D) + { + WrappedID3D11Texture2D *tex2D = (WrappedID3D11Texture2D *)live; + + D3D11_TEXTURE2D_DESC desc; + tex2D->GetDesc(&desc); + + bool isMS = (desc.SampleDesc.Count > 1 || desc.SampleDesc.Quality > 0); + + if(!hasData && desc.MipLevels == 1 && (desc.BindFlags & D3D11_BIND_RENDER_TARGET)) + { + D3D11_RENDER_TARGET_VIEW_DESC rdesc; + rdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rdesc.Format = GetTypedFormat(desc.Format); + rdesc.Texture2D.MipSlice = 0; + + if(isMS) rdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + + ID3D11RenderTargetView *initContents = NULL; + + HRESULT hr = m_pDevice->CreateRenderTargetView(UNWRAP(WrappedID3D11Texture2D, tex2D), &rdesc, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create fast-clear RTV while creating initial states %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(id, initContents, 1); + } + } + else if(!hasData && desc.MipLevels == 1 && (desc.BindFlags & D3D11_BIND_DEPTH_STENCIL)) + { + D3D11_DEPTH_STENCIL_VIEW_DESC ddesc; + ddesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + ddesc.Format = GetDepthTypedFormat(desc.Format); + ddesc.Texture1D.MipSlice = 0; + ddesc.Flags = 0; + + if(isMS) ddesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + + ID3D11DepthStencilView *initContents = NULL; + + HRESULT hr = m_pDevice->CreateDepthStencilView(UNWRAP(WrappedID3D11Texture2D, tex2D), &ddesc, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create fast-clear DSV while creating initial states %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(id, initContents, 2); + } + } + else if(desc.Usage != D3D11_USAGE_IMMUTABLE) + { + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = isMS ? D3D11_BIND_SHADER_RESOURCE : 0; + if(IsDepthFormat(desc.Format)) + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + desc.MiscFlags &= ~D3D11_RESOURCE_MISC_GENERATE_MIPS; + + ID3D11Texture2D *initContents = NULL; + + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create tex2D while creating initial states %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyResource(initContents, UNWRAP(WrappedID3D11Texture2D, tex2D)); + + m_ResourceManager->SetInitialContents(id, initContents, 0); + } + } + } + else if(type == Resource_Texture3D) + { + WrappedID3D11Texture3D *tex3D = (WrappedID3D11Texture3D *)live; + + D3D11_TEXTURE3D_DESC desc; + tex3D->GetDesc(&desc); + + if(!hasData && desc.MipLevels == 1 && (desc.BindFlags & D3D11_BIND_RENDER_TARGET)) + { + D3D11_RENDER_TARGET_VIEW_DESC rdesc; + rdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rdesc.Format = GetTypedFormat(desc.Format); + rdesc.Texture3D.FirstWSlice = 0; + rdesc.Texture3D.MipSlice = 0; + rdesc.Texture3D.WSize = desc.Depth; + + ID3D11RenderTargetView *initContents = NULL; + + HRESULT hr = m_pDevice->CreateRenderTargetView(UNWRAP(WrappedID3D11Texture3D, tex3D), &rdesc, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create fast-clear RTV while creating initial states %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(id, initContents, 1); + } + } + else if(!hasData && desc.Usage != D3D11_USAGE_IMMUTABLE) + { + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = 0; + desc.MiscFlags &= ~D3D11_RESOURCE_MISC_GENERATE_MIPS; + + ID3D11Texture3D *initContents = NULL; + + HRESULT hr = m_pDevice->CreateTexture3D(&desc, NULL, &initContents); + + if(FAILED(hr)) + { + RDCERR("Failed to create tex3D while creating initial states %08x", hr); + } + else + { + m_pImmediateContext->GetReal()->CopyResource(initContents, UNWRAP(WrappedID3D11Texture3D, tex3D)); + + m_ResourceManager->SetInitialContents(id, initContents, 0); + } + } + } +} + +void WrappedID3D11Device::Apply_InitialState(ID3D11DeviceChild *live, ID3D11DeviceChild *initial, uint32_t count) +{ + ResourceType type = IdentifyTypeByPtr(live); + + if(type == Resource_UnorderedAccessView) + { + ID3D11UnorderedAccessView *uav = (ID3D11UnorderedAccessView *)live; + + m_pImmediateContext->CSSetUnorderedAccessViews(0, 1, &uav, &count); + } + else + { + if(count == 1) + { + float emptyCol[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + m_pImmediateContext->GetReal()->ClearRenderTargetView((ID3D11RenderTargetView *)initial, emptyCol); + } + else if(count == 2) + { + m_pImmediateContext->GetReal()->ClearDepthStencilView((ID3D11DepthStencilView *)initial, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); + } + else + { + ID3D11Resource *liveResource = (ID3D11Resource *)m_ResourceManager->UnwrapResource(live); + ID3D11Resource *initialResource = (ID3D11Resource *)initial; + + m_pImmediateContext->GetReal()->CopyResource(liveResource, initialResource); + } + } +} + +void WrappedID3D11Device::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ + m_ReplayDefCtx = id; + m_FirstDefEv = firstDefEv; + m_LastDefEv = lastDefEv; +} + +void WrappedID3D11Device::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType) +{ + RDCASSERT(frameID < (uint32_t)m_FrameRecord.size()); + + uint64_t offs = m_FrameRecord[frameID].frameInfo.fileOffset; + + m_pSerialiser->SetOffset(offs); + + bool partial = true; + + if(startEventID == 0 && (replayType == eReplay_WithoutDraw || replayType == eReplay_Full)) + { + startEventID = m_FrameRecord[frameID].frameInfo.firstEvent; + partial = false; + } + + D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); + + RDCASSERT(header == CAPTURE_SCOPE); + + m_pSerialiser->SkipCurrentChunk(); + + m_pSerialiser->PopContext(NULL, header); + + if(!partial) + { + GetResourceManager()->ApplyInitialContents(); + GetResourceManager()->ReleaseInFrameResources(); + } + + if(m_ReplayDefCtx == ResourceId()) + { + if(replayType == eReplay_Full) + m_pImmediateContext->ReplayLog(EXECUTING, startEventID, endEventID, partial); + else if(replayType == eReplay_WithoutDraw) + m_pImmediateContext->ReplayLog(EXECUTING, startEventID, RDCMAX(1U,endEventID)-1, partial); + else if(replayType == eReplay_OnlyDraw) + m_pImmediateContext->ReplayLog(EXECUTING, endEventID, endEventID, partial); + else + RDCFATAL("Unexpected replay type"); + } + else + { + if(replayType == eReplay_Full || replayType == eReplay_WithoutDraw) + { + m_pImmediateContext->ReplayLog(EXECUTING, startEventID, endEventID, partial); + } + + m_pSerialiser->SetOffset(offs); + + D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); + m_pSerialiser->SkipCurrentChunk(); + m_pSerialiser->PopContext(NULL, header); + + m_pImmediateContext->ReplayFakeContext(m_ReplayDefCtx); + + if(replayType == eReplay_Full) + { + m_pImmediateContext->ClearState(); + + m_pImmediateContext->ReplayLog(EXECUTING, m_FirstDefEv, m_LastDefEv, true); + } + else if(replayType == eReplay_WithoutDraw && m_LastDefEv-1 >= m_FirstDefEv) + { + m_pImmediateContext->ClearState(); + + m_pImmediateContext->ReplayLog(EXECUTING, m_FirstDefEv, RDCMAX(m_LastDefEv,1U)-1, true); + } + else if(replayType == eReplay_OnlyDraw) + { + m_pImmediateContext->ReplayLog(EXECUTING, m_LastDefEv, m_LastDefEv, true); + } + + m_pImmediateContext->ReplayFakeContext(ResourceId()); + } +} + +void WrappedID3D11Device::ReleaseSwapchainResources(IDXGISwapChain *swap) +{ + if(swap) + { + DXGI_SWAP_CHAIN_DESC desc; + swap->GetDesc(&desc); + + Keyboard::RemoveInputWindow(desc.OutputWindow); + } + + auto it = m_SwapChains.find(swap); + if(it != m_SwapChains.end()) + { + SAFE_RELEASE(it->second); + m_SwapChains.erase(it); + } + + if(swap == m_SwapChain) + { + if(m_SwapChains.empty()) + m_SwapChain = NULL; + else + m_SwapChain = m_SwapChains.begin()->first; + } +} + +bool WrappedID3D11Device::Serialise_SetSwapChainTexture(IDXGISwapChain *swap, DXGI_SWAP_CHAIN_DESC *swapDesc, UINT buffer, ID3D11Texture2D *pTex) +{ + SERIALISE_ELEMENT(DXGI_FORMAT, swapFormat, swapDesc->BufferDesc.Format); + SERIALISE_ELEMENT(uint32_t, BuffNum, buffer); + SERIALISE_ELEMENT(ResourceId, pTexture, GetIDForResource(pTex)); + + if(m_State >= WRITING) + { + D3D11_TEXTURE2D_DESC desc; + + pTex->GetDesc(&desc); + + SERIALISE_ELEMENT(D3D11_TEXTURE2D_DESC, Descriptor, desc); + } + else + { + ID3D11Texture2D *fakeBB; + + SERIALISE_ELEMENT(D3D11_TEXTURE2D_DESC, Descriptor, D3D11_TEXTURE2D_DESC()); + + D3D11_TEXTURE2D_DESC realDescriptor = Descriptor; + + // DXGI swap chain back buffers can be freely cast as a special-case. + // translate the format to a typeless format to allow for this. + // the original type will be stored in the texture below + Descriptor.Format = GetTypelessFormat(Descriptor.Format); + + HRESULT hr = m_pDevice->CreateTexture2D(&Descriptor, NULL, &fakeBB); + + if(FAILED(hr)) + { + RDCERR("Failed to create fake back buffer, HRESULT: 0x%08x", hr); + } + else + { + WrappedID3D11Texture2D *wrapped = new WrappedID3D11Texture2D(fakeBB, this, TEXDISPLAY_INDIRECT_VIEW); + fakeBB = wrapped; + + wrapped->m_RealDescriptor = new D3D11_TEXTURE2D_DESC(realDescriptor); + + SetDebugName(fakeBB, "Serialised Swap Chain Buffer"); + + GetResourceManager()->AddLiveResource(pTexture, fakeBB); + } + } + + return true; +} + +void WrappedID3D11Device::SetSwapChainTexture(IDXGISwapChain *swap, DXGI_SWAP_CHAIN_DESC *swapDesc, UINT buffer, ID3D11Texture2D *pTex) +{ + D3D11_TEXTURE2D_DESC desc; + pTex->GetDesc(&desc); + + ResourceId id = GetIDForResource(pTex); + + LazyInit(); + + // there shouldn't be a resource record for this texture as it wasn't created via + // CreateTexture2D + RDCASSERT(id != ResourceId() && !GetResourceManager()->HasResourceRecord(id)); + + if(m_State >= WRITING) + { + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->DataInSerialiser = false; + record->SpecialResource = true; + record->Length = 0; + record->NumSubResources = 0; + record->SubResources = NULL; + + SCOPED_LOCK(m_D3DLock); + + SCOPED_SERIALISE_CONTEXT(CREATE_SWAP_BUFFER); + + Serialise_SetSwapChainTexture(swap, swapDesc, buffer, pTex); + + record->AddChunk(scope.Get()); + } + + if(buffer == 0 && m_State >= WRITING) + { + ID3D11RenderTargetView *rtv = NULL; + HRESULT hr = m_pDevice->CreateRenderTargetView(UNWRAP(WrappedID3D11Texture2D, pTex), NULL, &rtv); + + if(FAILED(hr)) + RDCERR("Couldn't create RTV for swapchain tex %08x", hr); + + m_SwapChains[swap] = rtv; + } + + if(swap) + { + DXGI_SWAP_CHAIN_DESC desc; + swap->GetDesc(&desc); + + Keyboard::AddInputWindow(desc.OutputWindow); + } + + if(m_SwapChain == NULL) + { + m_SwapChain = swap; + + GetDebugManager()->SetOutputDimensions(desc.Width, desc.Height); + } +} + +void WrappedID3D11Device::SetMarker(uint32_t col, const wchar_t *name) +{ + if(m_pCurrentWrappedDevice == NULL) + return; + + m_pCurrentWrappedDevice->m_pImmediateContext->ThreadSafe_SetMarker(col, name); +} + +int WrappedID3D11Device::BeginEvent(uint32_t col, const wchar_t *name) +{ + if(m_pCurrentWrappedDevice == NULL) + return 0; + + return m_pCurrentWrappedDevice->m_pImmediateContext->ThreadSafe_BeginEvent(col, name); +} + +int WrappedID3D11Device::EndEvent() +{ + if(m_pCurrentWrappedDevice == NULL) + return 0; + + return m_pCurrentWrappedDevice->m_pImmediateContext->ThreadSafe_EndEvent(); +} + +HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UINT Flags) +{ + if((Flags & DXGI_PRESENT_TEST) != 0) + return S_OK; + + RenderDoc::Inst().SetCurrentDriver(RDC_D3D11); + m_pCurrentWrappedDevice = this; + + if(m_State == WRITING_IDLE) + RenderDoc::Inst().Tick(); + + m_pImmediateContext->EndFrame(); + + m_FrameCounter++; // first present becomes frame #1, this function is at the end of the frame + + m_pImmediateContext->BeginFrame(); + + if(m_State == WRITING_IDLE) + { + D3D11RenderState old = *m_pImmediateContext->GetCurrentPipelineState(); + + m_FrameTimes.push_back(m_FrameTimer.GetMilliseconds()); + m_TotalTime += m_FrameTimes.back(); + m_FrameTimer.Restart(); + + // update every second + if(m_TotalTime > 1000.0) + { + m_MinFrametime = 10000.0; + m_MaxFrametime = 0.0; + m_AvgFrametime = 0.0; + + m_TotalTime = 0.0; + + for(size_t i=0; i < m_FrameTimes.size(); i++) + { + m_AvgFrametime += m_FrameTimes[i]; + if(m_FrameTimes[i] < m_MinFrametime) + m_MinFrametime = m_FrameTimes[i]; + if(m_FrameTimes[i] > m_MaxFrametime) + m_MaxFrametime = m_FrameTimes[i]; + } + + m_AvgFrametime /= double(m_FrameTimes.size()); + + m_FrameTimes.clear(); + } + + ID3D11RenderTargetView *rtv = m_SwapChains[swap]; + + m_pImmediateContext->GetReal()->OMSetRenderTargets(1, &rtv, NULL); + + int w = GetDebugManager()->GetWidth(); + int h = GetDebugManager()->GetHeight(); + + DXGI_SWAP_CHAIN_DESC swapDesc = {0}; + swap->GetDesc(&swapDesc); + GetDebugManager()->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height); + + if(swap == m_SwapChain) + { + GetDebugManager()->RenderText(0.0f, 0.0f, 1.0f, "Frame: %d. F12/PrtScr to capture. %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)", + m_FrameCounter, m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime); + size_t i=0; + for(i=0; i < m_FrameRecord.size(); i++) + GetDebugManager()->RenderText(0.0f, (float)(i+1)*18.0f, 1.0f, "Captured frame %d.\n", m_FrameRecord[i].frameInfo.frameNumber); + + if(m_FailedFrame > 0) + { + const char *reasonString = "Unknown reason"; + switch(m_FailedReason) + { + case CaptureFailed_UncappedCmdlist: reasonString = "Uncapped command list"; break; + case CaptureFailed_UncappedUnmap: reasonString = "Uncapped Map()/Unmap()"; break; + default: break; + } + + GetDebugManager()->RenderText(0.0f, (float)(++i)*18.0f, 1.0f, "Failed capture at frame %d:\n", m_FailedFrame); + GetDebugManager()->RenderText(0.0f, (float)(++i)*18.0f, 1.0f, " %hs\n", reasonString); + } + +#if !defined(RELEASE) + GetDebugManager()->RenderText(0.0f, float(++i)*18.0f, 1.0f, "%llu chunks - %.2f MB", Chunk::NumLiveChunks(), float(Chunk::TotalMem())/1024.0f/1024.0f); +#endif + } + else + { + GetDebugManager()->RenderText(0.0f, 0.0f, 1.0f, "Inactive swapchain, F11 to cycle"); + } + + GetDebugManager()->SetOutputDimensions(w, h); + + old.ApplyState(m_pImmediateContext); + + if(RenderDoc::Inst().ShouldFocusToggle()) + { + IDXGISwapChain *s = m_SwapChain; + m_SwapChain = NULL; + + for(auto it=m_SwapChains.begin(); it!=m_SwapChains.end(); ++it) + { + auto next = it; next++; + if(it->first == s) + { + if(next != m_SwapChains.end()) + m_SwapChain = next->first; + else + m_SwapChain = m_SwapChains.begin()->first; + break; + } + } + + if(m_SwapChain == NULL) + m_SwapChain = swap; + + DXGI_SWAP_CHAIN_DESC swapDesc = {0}; + m_SwapChain->GetDesc(&swapDesc); + GetDebugManager()->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height); + } + } + + if(swap != m_SwapChain) + { + return S_OK; + } + + // kill any current capture + if(m_State == WRITING_CAPFRAME) + { + CaptureFailReason reason; + + if(m_pImmediateContext->HasSuccessfulCapture(reason)) + { + SCOPED_LOCK(m_D3DLock); + + RDCLOG("Finished capture, Frame %u", m_FrameCounter); + + m_Failures = 0; + m_FailedFrame = 0; + m_FailedReason = CaptureSucceeded; + + m_pImmediateContext->EndCaptureFrame(); + m_pImmediateContext->FinishCapture(); + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + { + context->FinishCapture(); + } + else + { + RDCERR("NULL deferred context in resource record!"); + } + } + + const uint32_t maxSize = 1024; + + byte *thpixels = NULL; + uint32_t thwidth = 0; + uint32_t thheight = 0; + + { + ID3D11RenderTargetView *rtv = m_SwapChains[swap]; + + ID3D11Resource *res = NULL; + + rtv->GetResource(&res); res->Release(); + + ID3D11Texture2D *tex = (ID3D11Texture2D *)res; + + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + bool msaa = (desc.SampleDesc.Count > 1) || (desc.SampleDesc.Quality > 0); + + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + ID3D11Texture2D *stagingTex = NULL; + + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &stagingTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to create thumbnail. %08x", hr); + } + else + { + if(msaa) + { + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + + ID3D11Texture2D *resolveTex = NULL; + + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &resolveTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create resolve texture to create thumbnail. %08x", hr); + tex = NULL; + } + else + { + m_pImmediateContext->GetReal()->ResolveSubresource(resolveTex, 0, tex, 0, desc.Format); + m_pImmediateContext->GetReal()->CopyResource(stagingTex, resolveTex); + resolveTex->Release(); + } + } + else + { + m_pImmediateContext->GetReal()->CopyResource(stagingTex, tex); + } + + if(tex) + { + ResourceFormat fmt = MakeResourceFormat(desc.Format); + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = m_pImmediateContext->GetReal()->Map(stagingTex, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Couldn't map staging texture to create thumbnail. %08x", hr); + } + else + { + byte *data = (byte *)mapped.pData; + + float aspect = float(desc.Width)/float(desc.Height); + + thwidth = RDCMIN(maxSize, desc.Width); + thwidth &= ~0x7; // align down to multiple of 8 + thheight = uint32_t(float(thwidth)/aspect); + + thpixels = new byte[3*thwidth*thheight]; + + float widthf = float(desc.Width); + float heightf = float(desc.Height); + + uint32_t stride = fmt.compByteWidth*fmt.compCount; + + bool buf1010102 = false; + bool bufBGRA = false; + + if(fmt.special && fmt.specialFormat == eSpecial_R10G10B10A2) + { + stride = 4; + buf1010102 = true; + } + if(fmt.special && fmt.specialFormat == eSpecial_B8G8R8A8) + { + stride = 4; + bufBGRA = true; + } + + byte *dst = thpixels; + + for(uint32_t y=0; y < thheight; y++) + { + for(uint32_t x=0; x < thwidth; x++) + { + float xf = float(x)/float(thwidth); + float yf = float(y)/float(thheight); + + byte *src = &data[ stride*uint32_t(xf*widthf) + mapped.RowPitch*uint32_t(yf*heightf) ]; + + if(buf1010102) + { + uint32_t *src1010102 = (uint32_t *)src; + Vec4f unorm = ConvertFromR10G10B10A2(*src1010102); + dst[0] = (byte)(unorm.x*255.0f); + dst[1] = (byte)(unorm.y*255.0f); + dst[2] = (byte)(unorm.z*255.0f); + } + else if(bufBGRA) + { + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + } + else + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + + dst += 3; + } + } + + m_pImmediateContext->GetReal()->Unmap(stagingTex, 0); + } + } + + stagingTex->Release(); + } + + } + + byte *jpgbuf = NULL; + int len = thwidth*thheight; + + { + jpgbuf = new byte[len]; + + jpge::params p; + + p.m_quality = 40; + + bool success = jpge::compress_image_to_jpeg_file_in_memory(jpgbuf, len, thwidth, thheight, 3, thpixels, p); + + if(!success) + { + RDCERR("Failed to compress to jpg"); + SAFE_DELETE_ARRAY(jpgbuf); + thwidth = 0; + thheight = 0; + } + } + + Serialiser *m_pFileSerialiser = RenderDoc::Inst().OpenWriteSerialiser(m_FrameCounter, m_InitParams, jpgbuf, len, thwidth, thheight); + + SAFE_DELETE_ARRAY(jpgbuf); + SAFE_DELETE(thpixels); + + { + SCOPED_SERIALISE_CONTEXT(DEVICE_INIT); + + SERIALISE_ELEMENT(ResourceId, immContextId, m_pImmediateContext->GetResourceID()); + + m_pFileSerialiser->Insert(scope.Get(true)); + } + + RDCDEBUG("Inserting Resource Serialisers"); + + GetResourceManager()->InsertReferencedChunks(m_pFileSerialiser); + + GetResourceManager()->InsertInitialContentsChunks(m_pSerialiser, m_pFileSerialiser); + + RDCDEBUG("Creating Capture Scope"); + + { + SCOPED_SERIALISE_CONTEXT(CAPTURE_SCOPE); + + Serialise_CaptureScope(0); + + m_pFileSerialiser->Insert(scope.Get(true)); + } + + { + RDCDEBUG("Getting Resource Record"); + + D3D11ResourceRecord *record = m_ResourceManager->GetResourceRecord(m_pImmediateContext->GetResourceID()); + + RDCDEBUG("Accumulating context resource list"); + + map recordlist; + record->Insert(recordlist); + + RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size()); + + for(auto it = recordlist.begin(); it != recordlist.end(); ++it) + m_pFileSerialiser->Insert(it->second); + + RDCDEBUG("Done"); + } + + m_CurFileSize += m_pFileSerialiser->FlushToDisk(); + + SAFE_DELETE(m_pFileSerialiser); + + RenderDoc::Inst().SuccessfullyWrittenLog(); + + m_State = WRITING_IDLE; + + m_pImmediateContext->CleanupCapture(); + + m_pImmediateContext->FreeCaptureData(); + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + context->CleanupCapture(); + else + RDCERR("NULL deferred context in resource record!"); + } + + GetResourceManager()->MarkUnwrittenResources(); + + GetResourceManager()->ClearReferencedResources(); + } + else + { + RDCLOG("Failed to capture, frame %u", m_FrameCounter); + + m_Failures++; + + { + D3D11RenderState old = *m_pImmediateContext->GetCurrentPipelineState(); + + ID3D11RenderTargetView *rtv = m_SwapChains[swap]; + + if(rtv) + { + m_pImmediateContext->GetReal()->OMSetRenderTargets(1, &rtv, NULL); + + int w = GetDebugManager()->GetWidth(); + int h = GetDebugManager()->GetHeight(); + + DXGI_SWAP_CHAIN_DESC swapDesc = {0}; + swap->GetDesc(&swapDesc); + GetDebugManager()->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height); + + const char *reasonString = "Unknown reason"; + switch(reason) + { + case CaptureFailed_UncappedCmdlist: reasonString = "Uncapped command list"; break; + case CaptureFailed_UncappedUnmap: reasonString = "Uncapped Map()/Unmap()"; break; + default: break; + } + + GetDebugManager()->RenderText(0.0f, 0.0f, 1.0f, "Failed to capture frame %u: %hs", m_FrameCounter, reasonString); + + GetDebugManager()->SetOutputDimensions(w, h); + } + + old.ApplyState(m_pImmediateContext); + } + + m_FrameRecord.back().frameInfo.frameNumber = m_FrameCounter+1; + + m_pImmediateContext->CleanupCapture(); + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + context->CleanupCapture(); + else + RDCERR("NULL deferred context in resource record!"); + } + + GetResourceManager()->ClearReferencedResources(); + + if(m_Failures > 5) // failed too many times + { + m_pImmediateContext->FinishCapture(); + + m_FrameRecord.pop_back(); + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + { + context->FinishCapture(); + } + else + { + RDCERR("NULL deferred context in resource record!"); + } + } + + m_pImmediateContext->FreeCaptureData(); + + m_FailedFrame = m_FrameCounter; + m_FailedReason = reason; + + m_State = WRITING_IDLE; + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + context->CleanupCapture(); + else + RDCERR("NULL deferred context in resource record!"); + } + + GetResourceManager()->MarkUnwrittenResources(); + } + else + { + GetResourceManager()->MarkResourceFrameReferenced(m_ResourceID, eFrameRef_Write); + GetResourceManager()->PrepareInitialContents(); + + m_pImmediateContext->AttemptCapture(); + m_pImmediateContext->BeginCaptureFrame(); + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + { + context->AttemptCapture(); + } + else + { + RDCERR("NULL deferred context in resource record!"); + } + } + } + + if(m_pInfoQueue) + m_pInfoQueue->ClearStoredMessages(); + } + } + + if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE) + { + SCOPED_LOCK(m_D3DLock); + + m_State = WRITING_CAPFRAME; + + m_Failures = 0; + m_FailedFrame = 0; + m_FailedReason = CaptureSucceeded; + + FetchFrameRecord record; + record.frameInfo.frameNumber = m_FrameCounter+1; + m_FrameRecord.push_back(record); + + GetResourceManager()->ClearReferencedResources(); + + GetResourceManager()->MarkResourceFrameReferenced(m_ResourceID, eFrameRef_Write); + + m_pImmediateContext->AttemptCapture(); + m_pImmediateContext->BeginCaptureFrame(); + + for(auto it = m_DeferredContexts.begin(); it != m_DeferredContexts.end(); ++it) + { + WrappedID3D11DeviceContext *context = *it; + + if(context) + { + context->AttemptCapture(); + } + else + { + RDCERR("NULL deferred context in resource record!"); + } + } + + GetResourceManager()->PrepareInitialContents(); + + if(m_pInfoQueue) + m_pInfoQueue->ClearStoredMessages(); + + RDCLOG("Starting capture, frame %u", m_FrameCounter); + } + + return S_OK; +} + +void WrappedID3D11Device::AddDeferredContext(WrappedID3D11DeviceContext *defctx) +{ + RDCASSERT(m_DeferredContexts.find(defctx) == m_DeferredContexts.end()); + m_DeferredContexts.insert(defctx); +} + +void WrappedID3D11Device::RemoveDeferredContext(WrappedID3D11DeviceContext *defctx) +{ + RDCASSERT(m_DeferredContexts.find(defctx) != m_DeferredContexts.end()); + m_DeferredContexts.erase(defctx); +} + +bool WrappedID3D11Device::Serialise_SetResourceName(ID3D11DeviceChild *res, const char *nm) +{ + SERIALISE_ELEMENT(ResourceId, resource, GetIDForResource(res)); + string name = nm ? nm : ""; + m_pSerialiser->Serialise("name", name); + + if(m_State < WRITING && GetResourceManager()->HasLiveResource(resource)) + { + ID3D11DeviceChild *r = GetResourceManager()->GetLiveResource(resource); + + SetDebugName(r, name.c_str()); + } + + return true; +} + +void WrappedID3D11Device::SetResourceName(ID3D11DeviceChild *res, const char *name) +{ + if(m_State >= WRITING) + { + ResourceId idx = GetIDForResource(res); + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(idx); + + if(record == NULL) + record = m_DeviceRecord; + + RDCASSERT(idx != ResourceId()); + + SCOPED_LOCK(m_D3DLock); + { + SCOPED_SERIALISE_CONTEXT(SET_RESOURCE_NAME); + + Serialise_SetResourceName(res, name); + + record->AddChunk(scope.Get()); + } + } +} + +bool WrappedID3D11Device::Serialise_ReleaseResource(ID3D11DeviceChild *res) +{ + ResourceType resourceType = Resource_Unknown; + ResourceId resource = GetIDForResource(res); + + if(m_State >= WRITING) + { + resourceType = IdentifyTypeByPtr(res); + } + + if(m_State == WRITING_IDLE || m_State < WRITING) + { + SERIALISE_ELEMENT(ResourceId, serRes, GetIDForResource(res)); + SERIALISE_ELEMENT(ResourceType, serType, resourceType); + + resourceType = serType; + resource = serRes; + } + + if(m_State >= WRITING) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(resource); + if(record) + record->Delete(m_ResourceManager); + + switch(resourceType) + { + case Resource_RenderTargetView: + { + WrappedID3D11RenderTargetView* view = (WrappedID3D11RenderTargetView *)res; + + D3D11ResourceRecord *viewRecord = view->GetResourceRecord(); + if(viewRecord) + viewRecord->Delete(m_ResourceManager); + break; + } + case Resource_ShaderResourceView: + { + WrappedID3D11ShaderResourceView* view = (WrappedID3D11ShaderResourceView *)res; + + D3D11ResourceRecord *viewRecord = view->GetResourceRecord(); + if(viewRecord) + viewRecord->Delete(m_ResourceManager); + break; + } + case Resource_DepthStencilView: + { + WrappedID3D11DepthStencilView* view = (WrappedID3D11DepthStencilView *)res; + + D3D11ResourceRecord *viewRecord = view->GetResourceRecord(); + if(viewRecord) + viewRecord->Delete(m_ResourceManager); + break; + } + case Resource_UnorderedAccessView: + { + WrappedID3D11UnorderedAccessView* view = (WrappedID3D11UnorderedAccessView *)res; + + D3D11ResourceRecord *viewRecord = view->GetResourceRecord(); + if(viewRecord) + viewRecord->Delete(m_ResourceManager); + break; + } + } + } + if(m_State < WRITING && GetResourceManager()->HasLiveResource(resource)) + { + ID3D11DeviceChild *res = GetResourceManager()->GetLiveResource(resource); + GetResourceManager()->EraseLiveResource(resource); + SAFE_RELEASE(res); + } + + return true; +} + +void WrappedID3D11Device::ReleaseResource(ID3D11DeviceChild *res) +{ + ResourceId idx = GetIDForResource(res); + + // wrapped resources get released all the time, we don't want to + // try and slerp in a resource release. Just the explicit ones + if(m_State < WRITING) + { + if(GetResourceManager()->HasLiveResource(idx)) + GetResourceManager()->EraseLiveResource(idx); + return; + } + + SCOPED_LOCK(m_D3DLock); + + ResourceType type = IdentifyTypeByPtr(res); + + D3D11ResourceRecord *record = m_DeviceRecord; + + bool removegpu = true; + + if(m_State == WRITING_IDLE) + { + if(type == Resource_ShaderResourceView || + type == Resource_DepthStencilView || + type == Resource_UnorderedAccessView || + type == Resource_RenderTargetView || + type == Resource_Buffer || + type == Resource_Texture1D || + type == Resource_Texture2D || + type == Resource_Texture3D || + type == Resource_CommandList) + { + if(type == Resource_ShaderResourceView || + type == Resource_DepthStencilView || + type == Resource_UnorderedAccessView || + type == Resource_RenderTargetView + ) + { + ID3D11View *view = (ID3D11View *)res; + ID3D11Resource *viewRes = NULL; + view->GetResource(&viewRes); + idx = GetIDForResource(viewRes); + SAFE_RELEASE(viewRes); + + removegpu = false; + } + + record = GetResourceManager()->GetResourceRecord(idx); + RDCASSERT(record); + + if(record->SpecialResource) + { + record = m_DeviceRecord; + } + else if(record->GetRefCount() == 1) + { + // we're about to decrement this chunk out of existance! + // don't hold onto the record to add the chunk. + record = NULL; + } + } + } + + if(removegpu) + GetResourceManager()->MarkCleanResource(idx); + + if(type == Resource_DeviceContext) + { + RemoveDeferredContext((WrappedID3D11DeviceContext *)res); + } + + bool serialiseRelease = true; + + WrappedID3D11CommandList *cmdList = (WrappedID3D11CommandList *)res; + + // don't serialise releases of counters or queries since we ignore them. + // Also don't serialise releases of command lists that weren't captured, + // since their creation won't be in the log either. + if(type == Resource_Counter || type == Resource_Query || + (type == Resource_CommandList && !cmdList->IsCaptured()) + ) + serialiseRelease = false; + + if(type == Resource_CommandList && !cmdList->IsCaptured()) + { + record = GetResourceManager()->GetResourceRecord(idx); + if(record) + record->Delete(GetResourceManager()); + } + + if(serialiseRelease) + { + if(m_State == WRITING_CAPFRAME) + { + Serialise_ReleaseResource(res); + } + else + { + SCOPED_SERIALISE_CONTEXT(RELEASE_RESOURCE); + Serialise_ReleaseResource(res); + + if(record) + { + record->AddChunk(scope.Get()); + } + } + + if(record == NULL) + { + // if record is NULL then we just deleted a reference-less resource. + // That means it is not used and can be safely discarded, so just + // throw away the serialiser contents + m_pSerialiser->Rewind(); + } + } +} + +WrappedID3D11DeviceContext *WrappedID3D11Device::GetDeferredContext( size_t idx ) +{ + auto it = m_DeferredContexts.begin(); + + for(size_t i=0; i < idx; i++) + { + ++it; + if(it == m_DeferredContexts.end()) + return NULL; + } + + return *it; +} diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h new file mode 100644 index 0000000000..c6859de31e --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -0,0 +1,641 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +#include "common/threading.h" +#include "common/timing.h" + +#include "core/core.h" +#include "replay/renderdoc.h" + +#include + +#include "d3d11_manager.h" +#include "d3d11_replay.h" +#include "d3d11_debug.h" + +#include +using std::map; + +enum TextureDisplayType +{ + TEXDISPLAY_UNKNOWN = 0, + TEXDISPLAY_SRV_COMPATIBLE, + TEXDISPLAY_DEPTH_TARGET, + TEXDISPLAY_INDIRECT_VIEW, +}; + +struct D3D11InitParams : public RDCInitParams +{ + D3D11InitParams(); + ReplayCreateStatus Serialise(); + + D3D_DRIVER_TYPE DriverType; + UINT Flags; + UINT SDKVersion; + UINT NumFeatureLevels; + D3D_FEATURE_LEVEL FeatureLevels[16]; + + static const uint32_t D3D11_SERIALISE_VERSION = 0x0000004; + + // version number internal to d3d11 stream + uint32_t SerialiseVersion; +}; + +class WrappedID3D11Device; + +// give every impression of working but do nothing. +// Just allow the user to call functions so that they don't +// have to check for E_NOINTERFACE when they expect an infoqueue to be there +struct DummyID3D11InfoQueue : public ID3D11InfoQueue +{ + WrappedID3D11Device *m_pDevice; + + DummyID3D11InfoQueue() {} + + ////////////////////////////// + // implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { return E_NOINTERFACE; } + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + ////////////////////////////// + // implement ID3D11InfoQueue + virtual HRESULT STDMETHODCALLTYPE SetMessageCountLimit(UINT64 MessageCountLimit) { return S_OK; } + virtual void STDMETHODCALLTYPE ClearStoredMessages() { } + virtual HRESULT STDMETHODCALLTYPE GetMessage(UINT64 MessageIndex, D3D11_MESSAGE *pMessage, SIZE_T *pMessageByteLength) { return S_OK; } + virtual UINT64 STDMETHODCALLTYPE GetNumMessagesAllowedByStorageFilter() { return 0; } + virtual UINT64 STDMETHODCALLTYPE GetNumMessagesDeniedByStorageFilter() { return 0; } + virtual UINT64 STDMETHODCALLTYPE GetNumStoredMessages() { return 0; } + virtual UINT64 STDMETHODCALLTYPE GetNumStoredMessagesAllowedByRetrievalFilter() { return 0; } + virtual UINT64 STDMETHODCALLTYPE GetNumMessagesDiscardedByMessageCountLimit() { return 0; } + virtual UINT64 STDMETHODCALLTYPE GetMessageCountLimit() { return 0; } + virtual HRESULT STDMETHODCALLTYPE AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *pFilter) { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE GetStorageFilter(D3D11_INFO_QUEUE_FILTER *pFilter, SIZE_T *pFilterByteLength) { return S_OK; } + virtual void STDMETHODCALLTYPE ClearStorageFilter() { } + virtual HRESULT STDMETHODCALLTYPE PushEmptyStorageFilter() { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE PushCopyOfStorageFilter() { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE PushStorageFilter(D3D11_INFO_QUEUE_FILTER *pFilter) { return S_OK; } + virtual void STDMETHODCALLTYPE PopStorageFilter() { } + virtual UINT STDMETHODCALLTYPE GetStorageFilterStackSize() { return 0; } + virtual HRESULT STDMETHODCALLTYPE AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *pFilter) { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *pFilter, SIZE_T *pFilterByteLength) { return S_OK; } + virtual void STDMETHODCALLTYPE ClearRetrievalFilter() { } + virtual HRESULT STDMETHODCALLTYPE PushEmptyRetrievalFilter() { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE PushCopyOfRetrievalFilter() { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *pFilter) { return S_OK; } + virtual void STDMETHODCALLTYPE PopRetrievalFilter() { } + virtual UINT STDMETHODCALLTYPE GetRetrievalFilterStackSize() { return 0; } + virtual HRESULT STDMETHODCALLTYPE AddMessage(D3D11_MESSAGE_CATEGORY Category, D3D11_MESSAGE_SEVERITY Severity, D3D11_MESSAGE_ID ID, LPCSTR pDescription) { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE AddApplicationMessage(D3D11_MESSAGE_SEVERITY Severity, LPCSTR pDescription) { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE SetBreakOnCategory(D3D11_MESSAGE_CATEGORY Category, BOOL bEnable) { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY Severity, BOOL bEnable) { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE SetBreakOnID(D3D11_MESSAGE_ID ID, BOOL bEnable) { return S_OK; } + virtual BOOL STDMETHODCALLTYPE GetBreakOnCategory(D3D11_MESSAGE_CATEGORY Category) { return FALSE; } + virtual BOOL STDMETHODCALLTYPE GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY Severity) { return FALSE; } + virtual BOOL STDMETHODCALLTYPE GetBreakOnID(D3D11_MESSAGE_ID ID) { return FALSE; } + virtual void STDMETHODCALLTYPE SetMuteDebugOutput(BOOL bMute) { } + virtual BOOL STDMETHODCALLTYPE GetMuteDebugOutput() { return TRUE; } +}; + +class WrappedID3D11ClassLinkage; +enum CaptureFailReason; + +class WrappedID3D11Device : public ID3D11Device1 +{ +private: + // since enumeration creates a lot of devices, save + // large-scale init until some point that we know we're the real device + void LazyInit(); + + D3D11Replay m_Replay; + + DummyID3D11InfoQueue m_DummyInfo; + + unsigned int m_InternalRefcount; + RefCounter m_RefCounter; + RefCounter m_SoftRefCounter; + bool m_Alive; + + D3D11DebugManager *m_DebugManager; + D3D11ResourceManager *m_ResourceManager; + + RDCInitParams *m_InitParams; + + ID3D11Device* m_pDevice; + ID3D11Device1* m_pDevice1; + ID3D11InfoQueue *m_pInfoQueue; + WrappedID3D11DeviceContext* m_pImmediateContext; + + // ensure all calls in via the D3D wrapped interface are thread safe + // protects wrapped resource creation and serialiser access + Threading::CriticalSection m_D3DLock; + + ResourceId m_ResourceID; + D3D11ResourceRecord *m_DeviceRecord; + + Serialiser *m_pSerialiser; + Serialiser *m_pDebugSerialiser; + LogState m_State; + + set m_CachedStateObjects; + set m_DeferredContexts; + map > m_LayoutDescs; + map m_LayoutDXBC; + + ResourceId m_ReplayDefCtx; + uint32_t m_FirstDefEv; + uint32_t m_LastDefEv; + + static WrappedID3D11Device *m_pCurrentWrappedDevice; + + IDXGISwapChain *m_SwapChain; + map m_SwapChains; + + uint32_t m_FrameCounter; + uint32_t m_FailedFrame; + CaptureFailReason m_FailedReason; + uint32_t m_Failures; + + uint64_t m_CurFileSize; + + PerformanceTimer m_FrameTimer; + vector m_FrameTimes; + double m_TotalTime, m_AvgFrametime, m_MinFrametime, m_MaxFrametime; + + vector m_FrameRecord; +public: + static const int AllocPoolCount = 4; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Device, AllocPoolCount); + + WrappedID3D11Device(ID3D11Device* realDevice, D3D11InitParams *params); + void SetLogFile(const wchar_t *logfile); + virtual ~WrappedID3D11Device(); + + //////////////////////////////////////////////////////////////// + // non wrapping interface + + ID3D11Device *GetReal() { return m_pDevice; } + static const char *GetChunkName(uint32_t idx); + D3D11DebugManager *GetDebugManager() { LazyInit(); return m_DebugManager; } + D3D11ResourceManager *GetResourceManager() { return m_ResourceManager; } + + D3D11Replay *GetReplay() { return &m_Replay; } + + WrappedID3D11DeviceContext *GetImmediateContext() { return m_pImmediateContext; } + size_t GetNumDeferredContexts() { return m_DeferredContexts.size(); } + void AddDeferredContext(WrappedID3D11DeviceContext *defctx); + void RemoveDeferredContext(WrappedID3D11DeviceContext *defctx); + WrappedID3D11DeviceContext *GetDeferredContext(size_t idx); + + Serialiser *GetSerialiser() { return m_pSerialiser; } + + ResourceId GetResourceID() { return m_ResourceID; } + + vector &GetFrameRecord() { return m_FrameRecord; } + + vector GetDebugMessages(); + const vector &GetLayoutDesc(ID3D11InputLayout *layout) { return m_LayoutDescs[layout]; } + ShaderReflection *GetLayoutDXBC(ID3D11InputLayout *layout) { return m_LayoutDXBC[layout]; } + + void ReleaseSwapchainResources(IDXGISwapChain *swap); + + void Serialise_CaptureScope(uint64_t offset); + + //////////////////////////////////////////////////////////////// + // log replaying + + bool Prepare_InitialState(ID3D11DeviceChild *res); + bool Serialise_InitialState(ID3D11DeviceChild *res); + void Create_InitialState(ResourceId id, ID3D11DeviceChild *live, bool hasData); + void Apply_InitialState(ID3D11DeviceChild *live, ID3D11DeviceChild *initial, uint32_t count); + + void ReadLogInitialisation(); + void ProcessChunk(uint64_t offset, D3D11ChunkType context); + void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); + void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); + + //////////////////////////////////////////////////////////////// + // 'fake' interfaces + + // Resource + IMPLEMENT_FUNCTION_SERIALISED(void, SetResourceName(ID3D11DeviceChild *res, const char *name)); + IMPLEMENT_FUNCTION_SERIALISED(void, ReleaseResource(ID3D11DeviceChild *res)); + + // Class Linkage + IMPLEMENT_FUNCTION_SERIALISED(ID3D11ClassInstance*, CreateClassInstance(LPCSTR pClassTypeName, + UINT ConstantBufferOffset, UINT ConstantVectorOffset, + UINT TextureOffset, UINT SamplerOffset, + WrappedID3D11ClassLinkage *linkage, ID3D11ClassInstance *inst)); + + IMPLEMENT_FUNCTION_SERIALISED(ID3D11ClassInstance*, GetClassInstance(LPCSTR pClassInstanceName, UINT InstanceIndex, + WrappedID3D11ClassLinkage *linkage, ID3D11ClassInstance *inst)); + + // Swap Chain + IMPLEMENT_FUNCTION_SERIALISED(void, SetSwapChainTexture(IDXGISwapChain *swap, DXGI_SWAP_CHAIN_DESC *desc, UINT buffer, ID3D11Texture2D *pTex)); + HRESULT Present(IDXGISwapChain *swap, UINT SyncInterval, UINT Flags); + + void InternalRef() { InterlockedIncrement(&m_InternalRefcount); } + void InternalRelease() { InterlockedDecrement(&m_InternalRefcount); } + + void SoftRef() { m_SoftRefCounter.AddRef(); } + void SoftRelease() { m_SoftRefCounter.Release(); CheckForDeath(); } + void CheckForDeath(); + + //////////////////////////////////////////////////////////////// + // Functions for D3D9 hooks to call into (D3DPERF api) + + static void SetMarker(uint32_t col, const wchar_t *name); + static int BeginEvent(uint32_t col, const wchar_t *name); + static int EndEvent(); + + ////////////////////////////// + // implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return m_RefCounter.AddRef(); } + ULONG STDMETHODCALLTYPE Release() { unsigned int ret = m_RefCounter.Release(); CheckForDeath(); return ret; } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + + ////////////////////////////// + // implement ID3D11Device + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateBuffer( + /* [annotation] */ + __in const D3D11_BUFFER_DESC *pDesc, + /* [annotation] */ + __in_opt const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Buffer **ppBuffer)); + + template + TextureDisplayType DispTypeForTexture(TexDesc &Descriptor); + + vector Serialise_CreateTextureData(ID3D11Resource *tex, ResourceId id, const D3D11_SUBRESOURCE_DATA *data, + UINT w, UINT h, UINT d, DXGI_FORMAT fmt, UINT mips, UINT arr, bool HasData); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateTexture1D( + /* [annotation] */ + __in const D3D11_TEXTURE1D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture1D **ppTexture1D)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateTexture2D( + /* [annotation] */ + __in const D3D11_TEXTURE2D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture2D **ppTexture2D)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateTexture3D( + /* [annotation] */ + __in const D3D11_TEXTURE3D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture3D **ppTexture3D)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateShaderResourceView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11ShaderResourceView **ppSRView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateUnorderedAccessView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11UnorderedAccessView **ppUAView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateRenderTargetView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_RENDER_TARGET_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11RenderTargetView **ppRTView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateDepthStencilView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11DepthStencilView **ppDepthStencilView)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateInputLayout( + /* [annotation] */ + __in_ecount(NumElements) const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT ) UINT NumElements, + /* [annotation] */ + __in const void *pShaderBytecodeWithInputSignature, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __out_opt ID3D11InputLayout **ppInputLayout)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateVertexShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11VertexShader **ppVertexShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateGeometryShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11GeometryShader **ppGeometryShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateGeometryShaderWithStreamOutput( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_ecount_opt(NumEntries) const D3D11_SO_DECLARATION_ENTRY *pSODeclaration, + /* [annotation] */ + __in_range( 0, D3D11_SO_STREAM_COUNT * D3D11_SO_OUTPUT_COMPONENT_COUNT ) UINT NumEntries, + /* [annotation] */ + __in_ecount_opt(NumStrides) const UINT *pBufferStrides, + /* [annotation] */ + __in_range( 0, D3D11_SO_BUFFER_SLOT_COUNT ) UINT NumStrides, + /* [annotation] */ + __in UINT RasterizedStream, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11GeometryShader **ppGeometryShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreatePixelShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11PixelShader **ppPixelShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateHullShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11HullShader **ppHullShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateDomainShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11DomainShader **ppDomainShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateComputeShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11ComputeShader **ppComputeShader)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateClassLinkage( + /* [annotation] */ + __out ID3D11ClassLinkage **ppLinkage)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateBlendState( + /* [annotation] */ + __in const D3D11_BLEND_DESC *pBlendStateDesc, + /* [annotation] */ + __out_opt ID3D11BlendState **ppBlendState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateDepthStencilState( + /* [annotation] */ + __in const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc, + /* [annotation] */ + __out_opt ID3D11DepthStencilState **ppDepthStencilState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateRasterizerState( + /* [annotation] */ + __in const D3D11_RASTERIZER_DESC *pRasterizerDesc, + /* [annotation] */ + __out_opt ID3D11RasterizerState **ppRasterizerState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateSamplerState( + /* [annotation] */ + __in const D3D11_SAMPLER_DESC *pSamplerDesc, + /* [annotation] */ + __out_opt ID3D11SamplerState **ppSamplerState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateQuery( + /* [annotation] */ + __in const D3D11_QUERY_DESC *pQueryDesc, + /* [annotation] */ + __out_opt ID3D11Query **ppQuery)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreatePredicate( + /* [annotation] */ + __in const D3D11_QUERY_DESC *pPredicateDesc, + /* [annotation] */ + __out_opt ID3D11Predicate **ppPredicate)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateCounter( + /* [annotation] */ + __in const D3D11_COUNTER_DESC *pCounterDesc, + /* [annotation] */ + __out_opt ID3D11Counter **ppCounter)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateDeferredContext( + UINT ContextFlags, + /* [annotation] */ + __out_opt ID3D11DeviceContext **ppDeferredContext)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, OpenSharedResource( + /* [annotation] */ + __in HANDLE hResource, + /* [annotation] */ + __in REFIID ReturnedInterface, + /* [annotation] */ + __out_opt void **ppResource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CheckFormatSupport( + /* [annotation] */ + __in DXGI_FORMAT Format, + /* [annotation] */ + __out UINT *pFormatSupport)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CheckMultisampleQualityLevels( + /* [annotation] */ + __in DXGI_FORMAT Format, + /* [annotation] */ + __in UINT SampleCount, + /* [annotation] */ + __out UINT *pNumQualityLevels)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CheckCounterInfo( + /* [annotation] */ + __out D3D11_COUNTER_INFO *pCounterInfo)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CheckCounter( + /* [annotation] */ + __in const D3D11_COUNTER_DESC *pDesc, + /* [annotation] */ + __out D3D11_COUNTER_TYPE *pType, + /* [annotation] */ + __out UINT *pActiveCounters, + /* [annotation] */ + __out_ecount_opt(*pNameLength) LPSTR szName, + /* [annotation] */ + __inout_opt UINT *pNameLength, + /* [annotation] */ + __out_ecount_opt(*pUnitsLength) LPSTR szUnits, + /* [annotation] */ + __inout_opt UINT *pUnitsLength, + /* [annotation] */ + __out_ecount_opt(*pDescriptionLength) LPSTR szDescription, + /* [annotation] */ + __inout_opt UINT *pDescriptionLength)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CheckFeatureSupport( + D3D11_FEATURE Feature, + /* [annotation] */ + __out_bcount(FeatureSupportDataSize) void *pFeatureSupportData, + UINT FeatureSupportDataSize)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, GetPrivateData( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __inout UINT *pDataSize, + /* [annotation] */ + __out_bcount_opt(*pDataSize) void *pData)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, SetPrivateData( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __in UINT DataSize, + /* [annotation] */ + __in_bcount_opt(DataSize) const void *pData)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, SetPrivateDataInterface( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __in_opt const IUnknown *pData)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual D3D_FEATURE_LEVEL STDMETHODCALLTYPE, GetFeatureLevel( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual UINT STDMETHODCALLTYPE, GetCreationFlags( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, GetDeviceRemovedReason( void)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GetImmediateContext( + /* [annotation] */ + __out ID3D11DeviceContext **ppImmediateContext)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, SetExceptionMode( + UINT RaiseFlags)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual UINT STDMETHODCALLTYPE, GetExceptionMode( void)); + + + ////////////////////////////// + // implement ID3D11Device + + IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, GetImmediateContext1(ID3D11DeviceContext1 **ppImmediateContext)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateDeferredContext1( + UINT ContextFlags, + /* [annotation] */ + _Out_opt_ ID3D11DeviceContext1 **ppDeferredContext)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateBlendState1( + /* [annotation] */ + _In_ const D3D11_BLEND_DESC1 *pBlendStateDesc, + /* [annotation] */ + _Out_opt_ ID3D11BlendState1 **ppBlendState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateRasterizerState1( + /* [annotation] */ + _In_ const D3D11_RASTERIZER_DESC1 *pRasterizerDesc, + /* [annotation] */ + _Out_opt_ ID3D11RasterizerState1 **ppRasterizerState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreateDeviceContextState( + UINT Flags, + /* [annotation] */ + _In_reads_( FeatureLevels ) const D3D_FEATURE_LEVEL *pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + REFIID EmulatedInterface, + /* [annotation] */ + _Out_opt_ D3D_FEATURE_LEVEL *pChosenFeatureLevel, + /* [annotation] */ + _Out_opt_ ID3DDeviceContextState **ppContextState)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, OpenSharedResource1( + /* [annotation] */ + _In_ HANDLE hResource, + /* [annotation] */ + _In_ REFIID returnedInterface, + /* [annotation] */ + _Out_ void **ppResource)); + + IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, OpenSharedResourceByName( + /* [annotation] */ + _In_ LPCWSTR lpName, + /* [annotation] */ + _In_ DWORD dwDesiredAccess, + /* [annotation] */ + _In_ REFIID returnedInterface, + /* [annotation] */ + _Out_ void **ppResource)); + +}; diff --git a/renderdoc/driver/d3d11/d3d11_device1_wrap.cpp b/renderdoc/driver/d3d11/d3d11_device1_wrap.cpp new file mode 100644 index 0000000000..df04954b23 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_device1_wrap.cpp @@ -0,0 +1,232 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "d3d11_device.h" +#include "d3d11_resources.h" +#include "d3d11_context.h" + +void WrappedID3D11Device::GetImmediateContext1(ID3D11DeviceContext1 **ppImmediateContext) +{ + if(m_pDevice1 == NULL) return; + + if(ppImmediateContext) + { + m_pImmediateContext->AddRef(); + *ppImmediateContext = (ID3D11DeviceContext1 *)m_pImmediateContext; + } +} + +HRESULT WrappedID3D11Device::CreateDeferredContext1(UINT ContextFlags, ID3D11DeviceContext1 **ppDeferredContext) +{ + if(m_pDevice1 == NULL) return E_NOINTERFACE; + if(ppDeferredContext == NULL) return m_pDevice1->CreateDeferredContext1(ContextFlags, NULL); + + ID3D11DeviceContext *defCtx = NULL; + HRESULT ret = CreateDeferredContext(ContextFlags, &defCtx); + + if(SUCCEEDED(ret)) + { + WrappedID3D11DeviceContext *wrapped = (WrappedID3D11DeviceContext *)defCtx; + *ppDeferredContext = (ID3D11DeviceContext1 *)wrapped; + } + else + { + SAFE_RELEASE(defCtx); + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateBlendState1(const D3D11_BLEND_DESC1 *pBlendStateDesc, ID3D11BlendState1 **ppBlendState) +{ + SERIALISE_ELEMENT_PTR(D3D11_BLEND_DESC1, Descriptor, pBlendStateDesc); + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(*ppBlendState)); + + if(m_State == READING) + { + ID3D11BlendState1 *ret = NULL; + HRESULT hr = E_NOINTERFACE; + + if(m_pDevice1) + m_pDevice1->CreateBlendState1(&Descriptor, &ret); + else + RDCERR("Replaying a D3D11.1 device without D3D11.1 available"); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11BlendState1(ret, this); + + GetResourceManager()->AddLiveResource(State, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateBlendState1(const D3D11_BLEND_DESC1 *pBlendStateDesc, ID3D11BlendState1 **ppBlendState) +{ + if(m_pDevice1 == NULL) return E_NOINTERFACE; + if(ppBlendState == NULL) return m_pDevice1->CreateBlendState1(pBlendStateDesc, NULL); + + ID3D11BlendState1 *real = NULL; + HRESULT ret = m_pDevice1->CreateBlendState1(pBlendStateDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + // duplicate states can be returned, if Create is called with a previous descriptor + if(GetResourceManager()->HasWrapper(real)) + { + real->Release(); + *ppBlendState = (ID3D11BlendState1 *)GetResourceManager()->GetWrapper(real); + (*ppBlendState)->AddRef(); + return ret; + } + + ID3D11BlendState1 *wrapped = new WrappedID3D11BlendState1(real, this); + + if(RenderDoc::Inst().GetCaptureOptions().CacheStateObjects) + { + RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end()); + wrapped->AddRef(); + InternalRef(); + m_CachedStateObjects.insert(wrapped); + } + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_BLEND_STATE1); + Serialise_CreateBlendState1(pBlendStateDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppBlendState = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateRasterizerState1(const D3D11_RASTERIZER_DESC1 *pRasterizerDesc, ID3D11RasterizerState1 **ppRasterizerState) +{ + SERIALISE_ELEMENT_PTR(D3D11_RASTERIZER_DESC1, Descriptor, pRasterizerDesc); + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(*ppRasterizerState)); + + if(m_State == READING) + { + ID3D11RasterizerState1 *ret = NULL; + HRESULT hr = E_NOINTERFACE; + + if(m_pDevice1) + m_pDevice1->CreateRasterizerState1(&Descriptor, &ret); + else + RDCERR("Replaying a D3D11.1 device without D3D11.1 available"); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11RasterizerState1(ret, this); + + GetResourceManager()->AddLiveResource(State, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateRasterizerState1(const D3D11_RASTERIZER_DESC1 *pRasterizerDesc, ID3D11RasterizerState1 **ppRasterizerState) +{ + if(m_pDevice1 == NULL) return E_NOINTERFACE; + if(ppRasterizerState == NULL) return m_pDevice1->CreateRasterizerState1(pRasterizerDesc, NULL); + + ID3D11RasterizerState1 *real = NULL; + HRESULT ret = m_pDevice1->CreateRasterizerState1(pRasterizerDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + // duplicate states can be returned, if Create is called with a previous descriptor + if(GetResourceManager()->HasWrapper(real)) + { + real->Release(); + *ppRasterizerState = (ID3D11RasterizerState1 *)GetResourceManager()->GetWrapper(real); + (*ppRasterizerState)->AddRef(); + return ret; + } + + ID3D11RasterizerState1 *wrapped = new WrappedID3D11RasterizerState1(real, this); + + if(RenderDoc::Inst().GetCaptureOptions().CacheStateObjects) + { + RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end()); + wrapped->AddRef(); + InternalRef(); + m_CachedStateObjects.insert(wrapped); + } + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_RASTER_STATE1); + Serialise_CreateRasterizerState1(pRasterizerDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppRasterizerState = wrapped; + } + + return ret; +} + +HRESULT WrappedID3D11Device::CreateDeviceContextState(UINT Flags, const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, REFIID EmulatedInterface, + D3D_FEATURE_LEVEL *pChosenFeatureLevel, ID3DDeviceContextState **ppContextState) +{ + if(m_pDevice1 == NULL) return E_NOINTERFACE; + RDCUNIMPLEMENTED("Not wrapping CreateDeviceContextState"); + return m_pDevice1->CreateDeviceContextState(Flags, pFeatureLevels, FeatureLevels, SDKVersion, EmulatedInterface, pChosenFeatureLevel, ppContextState); +} + +HRESULT WrappedID3D11Device::OpenSharedResource1(HANDLE hResource, REFIID returnedInterface, void **ppResource) +{ + if(m_pDevice1 == NULL) return E_NOINTERFACE; + RDCUNIMPLEMENTED("Not wrapping OpenSharedResource1"); + return m_pDevice1->OpenSharedResource1(hResource, returnedInterface, ppResource); +} + +HRESULT WrappedID3D11Device::OpenSharedResourceByName(LPCWSTR lpName, DWORD dwDesiredAccess, REFIID returnedInterface, void **ppResource) +{ + if(m_pDevice1 == NULL) return E_NOINTERFACE; + RDCUNIMPLEMENTED("Not wrapping OpenSharedResourceByName"); + return m_pDevice1->OpenSharedResourceByName(lpName, dwDesiredAccess, returnedInterface, ppResource); +} diff --git a/renderdoc/driver/d3d11/d3d11_device_wrap.cpp b/renderdoc/driver/d3d11/d3d11_device_wrap.cpp new file mode 100644 index 0000000000..04e8c3b454 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_device_wrap.cpp @@ -0,0 +1,3081 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/d3d11/d3d11_device.h" +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_resources.h" + +bool WrappedID3D11Device::Serialise_CreateBuffer( + /* [annotation] */ + __in const D3D11_BUFFER_DESC *pDesc, + /* [annotation] */ + __in_opt const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Buffer **ppBuffer) +{ + D3D11_SUBRESOURCE_DATA fakeData; + RDCEraseEl(fakeData); + + SERIALISE_ELEMENT_PTR(D3D11_BUFFER_DESC, Descriptor, pDesc); + if(pInitialData == NULL && m_State >= WRITING) + { + fakeData.pSysMem = new char[Descriptor.ByteWidth]; + fakeData.SysMemPitch = fakeData.SysMemSlicePitch = Descriptor.ByteWidth; + memset((void *)fakeData.pSysMem, 0xfe, Descriptor.ByteWidth); + pInitialData = &fakeData; + } + + SERIALISE_ELEMENT_BUF(byte *, InitialData, pInitialData->pSysMem, Descriptor.ByteWidth); + + uint64_t offs = m_pSerialiser->GetOffset()-Descriptor.ByteWidth; + + RDCASSERT((offs%16)==0); + + SERIALISE_ELEMENT(uint32_t, MemPitch, pInitialData->SysMemPitch); + SERIALISE_ELEMENT(uint32_t, MemSlicePitch, pInitialData->SysMemSlicePitch); + SERIALISE_ELEMENT(ResourceId, pBuffer, GetIDForResource(*ppBuffer)); + + if(m_State >= WRITING) + { + RDCASSERT(GetResourceManager()->GetResourceRecord(pBuffer) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(pBuffer); + record->SetDataOffset(offs); + record->DataInSerialiser = true; + record->Length = Descriptor.ByteWidth; + } + + if(m_State == READING) + { + ID3D11Buffer *ret; + + HRESULT hr = S_OK; + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = InitialData; + data.SysMemPitch = MemPitch; + data.SysMemSlicePitch = MemSlicePitch; + hr = m_pDevice->CreateBuffer(&Descriptor, &data, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Buffer(ret, Descriptor.ByteWidth, this); + + GetResourceManager()->AddLiveResource(pBuffer, ret); + } + + if(Descriptor.Usage != D3D11_USAGE_IMMUTABLE) + { + ID3D11Buffer *stage = NULL; + + D3D11_BUFFER_DESC desc; + desc.ByteWidth = Descriptor.ByteWidth; + desc.MiscFlags = 0; + desc.StructureByteStride = 0; + // We don't need to bind this, but IMMUTABLE requires at least one + // BindFlags. + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_IMMUTABLE; + + data.SysMemPitch = Descriptor.ByteWidth; + data.SysMemSlicePitch = Descriptor.ByteWidth; + hr = m_pDevice->CreateBuffer(&desc, &data, &stage); + + if(FAILED(hr) || stage == NULL) + { + RDCERR("Failed to create staging buffer for buffer initial contents %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(pBuffer, stage, 0); + } + } + + SAFE_DELETE_ARRAY(InitialData); + } + + char *arr = (char *)fakeData.pSysMem; + SAFE_DELETE_ARRAY(arr); + + return true; +} + +HRESULT WrappedID3D11Device::CreateBuffer( + /* [annotation] */ + __in const D3D11_BUFFER_DESC *pDesc, + /* [annotation] */ + __in_opt const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Buffer **ppBuffer) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppBuffer == NULL) return m_pDevice->CreateBuffer(pDesc, pInitialData, NULL); + + ID3D11Buffer *real = NULL; + ID3D11Buffer *wrapped = NULL; + HRESULT ret = m_pDevice->CreateBuffer(pDesc, pInitialData, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Buffer(real, pDesc ? pDesc->ByteWidth : 0, this); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(CREATE_BUFFER); + Serialise_CreateBuffer(pDesc, pInitialData, &wrapped); + + chunk = scope.Get(); + } + + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(wrapped)); + RDCASSERT(record); + record->AddChunk(chunk); + record->SetDataPtr(chunk->GetData()); + } + + *ppBuffer = wrapped; + } + + return ret; +} + +vector WrappedID3D11Device::Serialise_CreateTextureData(ID3D11Resource *tex, ResourceId id, const D3D11_SUBRESOURCE_DATA *data, + UINT w, UINT h, UINT d, DXGI_FORMAT fmt, + UINT mips, UINT arr, bool HasData) +{ + UINT numSubresources = mips; + UINT numMips = mips; + + if(mips == 0) + numSubresources = numMips = CalcNumMips(w, h, d); + + numSubresources *= arr; + + vector descs; + if(m_State == READING && HasData) + { + descs.resize(numSubresources); + } + + byte *scratch = NULL; + + for(UINT i=0; i < numSubresources; i++) + { + int mip = i%numMips; + + UINT subresourceSize = GetByteSize(w, h, d, fmt, mip); + + RDCASSERT(subresourceSize > 0); + + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(id); + + if(m_State >= WRITING) + { + if(i == 0) + { + RDCASSERT(record == NULL); + + record = GetResourceManager()->AddResourceRecord(id); + record->Length = 1; + + if(HasData) + record->DataInSerialiser = true; + + record->NumSubResources = numSubresources; + record->SubResources = new ResourceRecord*[record->NumSubResources]; + for(UINT s=0; s < numSubresources; s++) + record->SubResources[s] = new D3D11ResourceRecord(ResourceId()); + } + + RDCASSERT(record != NULL); + + record->SubResources[i]->Length = subresourceSize; + } + + if(!HasData) + continue; + + if(scratch == NULL && m_State >= WRITING) + scratch = new byte[subresourceSize]; + + if(m_State >= WRITING) + { + MapIntercept intercept; + intercept.SetD3D(data[i]); + + D3D11_RESOURCE_DIMENSION dim; + tex->GetType(&dim); + + if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + intercept.Init((ID3D11Texture1D *)tex, i, scratch); + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + intercept.Init((ID3D11Texture2D *)tex, i, scratch); + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) + intercept.Init((ID3D11Texture3D *)tex, i, scratch); + else + RDCERR("Unexpected resource type!"); + + intercept.CopyFromD3D(); + } + + SERIALISE_ELEMENT_BUF(byte *, buf, scratch, subresourceSize); + + if(m_State >= WRITING) + { + RDCASSERT(record); + + record->SubResources[i]->SetDataOffset(m_pSerialiser->GetOffset()-subresourceSize); + } + + if(m_State == READING) + { + descs[i].pSysMem = buf; + descs[i].SysMemPitch = GetByteSize(w, 1, 1, fmt, mip); + descs[i].SysMemSlicePitch = GetByteSize(w, h, 1, fmt, mip); + } + } + + if(scratch) + SAFE_DELETE_ARRAY(scratch); + + return descs; +} + +template +TextureDisplayType WrappedID3D11Device::DispTypeForTexture(TexDesc &Descriptor) +{ + TextureDisplayType dispType = TEXDISPLAY_SRV_COMPATIBLE; + + if(Descriptor.Usage == D3D11_USAGE_STAGING) + { + dispType = TEXDISPLAY_INDIRECT_VIEW; + } + else if(IsDepthFormat(Descriptor.Format) || (Descriptor.BindFlags & D3D11_BIND_DEPTH_STENCIL)) + { + dispType = TEXDISPLAY_DEPTH_TARGET; + } + else + { + // diverging from perfect reproduction here + Descriptor.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + + return dispType; +} + +bool WrappedID3D11Device::Serialise_CreateTexture1D( + /* [annotation] */ + __in const D3D11_TEXTURE1D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture1D **ppTexture1D) +{ + SERIALISE_ELEMENT_PTR(D3D11_TEXTURE1D_DESC, Descriptor, pDesc); + SERIALISE_ELEMENT(ResourceId, pTexture, GetIDForResource(*ppTexture1D)); + + SERIALISE_ELEMENT(bool, HasInitialData, pInitialData != NULL); + + vector descs = Serialise_CreateTextureData(ppTexture1D ? *ppTexture1D : NULL, pTexture, pInitialData, + Descriptor.Width, 1, 1, Descriptor.Format, + Descriptor.MipLevels, Descriptor.ArraySize, HasInitialData); + + if(m_State == READING) + { + ID3D11Texture1D *ret; + HRESULT hr = S_OK; + + TextureDisplayType dispType = DispTypeForTexture(Descriptor); + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + if(HasInitialData) + hr = m_pDevice->CreateTexture1D(&Descriptor, &descs[0], &ret); + else + hr = m_pDevice->CreateTexture1D(&Descriptor, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Texture1D(ret, this, dispType); + + GetResourceManager()->AddLiveResource(pTexture, ret); + } + } + + for(size_t i=0; i < descs.size(); i++) + SAFE_DELETE_ARRAY(descs[i].pSysMem); + + return true; +} + +HRESULT WrappedID3D11Device::CreateTexture1D( + /* [annotation] */ + __in const D3D11_TEXTURE1D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture1D **ppTexture1D) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppTexture1D == NULL) return m_pDevice->CreateTexture1D(pDesc, pInitialData, NULL); + + ID3D11Texture1D *real = NULL; + ID3D11Texture1D *wrapped = NULL; + HRESULT ret = m_pDevice->CreateTexture1D(pDesc, pInitialData, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Texture1D(real, this); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(CREATE_TEXTURE_1D); + Serialise_CreateTexture1D(pDesc, pInitialData, &wrapped); + + chunk = scope.Get(); + } + + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(wrapped)); + RDCASSERT(record); + + record->AddChunk(chunk); + record->SetDataPtr(chunk->GetData()); + } + + *ppTexture1D = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateTexture2D( + /* [annotation] */ + __in const D3D11_TEXTURE2D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture2D **ppTexture2D) +{ + SERIALISE_ELEMENT_PTR(D3D11_TEXTURE2D_DESC, Descriptor, pDesc); + SERIALISE_ELEMENT(ResourceId, pTexture, GetIDForResource(*ppTexture2D)); + + SERIALISE_ELEMENT(bool, HasInitialData, pInitialData != NULL); + + vector descs = Serialise_CreateTextureData(ppTexture2D ? *ppTexture2D : NULL, pTexture, pInitialData, + Descriptor.Width, Descriptor.Height, 1, Descriptor.Format, + Descriptor.MipLevels, Descriptor.ArraySize, HasInitialData); + + if(m_State == READING) + { + ID3D11Texture2D *ret; + HRESULT hr = S_OK; + + TextureDisplayType dispType = DispTypeForTexture(Descriptor); + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + if(HasInitialData) + hr = m_pDevice->CreateTexture2D(&Descriptor, &descs[0], &ret); + else + hr = m_pDevice->CreateTexture2D(&Descriptor, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Texture2D(ret, this, dispType); + + GetResourceManager()->AddLiveResource(pTexture, ret); + } + } + + for(size_t i=0; i < descs.size(); i++) + SAFE_DELETE_ARRAY(descs[i].pSysMem); + + return true; +} + +HRESULT WrappedID3D11Device::CreateTexture2D( + /* [annotation] */ + __in const D3D11_TEXTURE2D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture2D **ppTexture2D) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppTexture2D == NULL) return m_pDevice->CreateTexture2D(pDesc, pInitialData, NULL); + + ID3D11Texture2D *real = NULL; + ID3D11Texture2D *wrapped = NULL; + HRESULT ret = m_pDevice->CreateTexture2D(pDesc, pInitialData, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Texture2D(real, this); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(CREATE_TEXTURE_2D); + Serialise_CreateTexture2D(pDesc, pInitialData, &wrapped); + + chunk = scope.Get(); + } + + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(wrapped)); + RDCASSERT(record); + + record->AddChunk(chunk); + record->SetDataPtr(chunk->GetData()); + } + else + { + WrappedID3D11Texture2D *w = (WrappedID3D11Texture2D *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppTexture2D = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateTexture3D( + /* [annotation] */ + __in const D3D11_TEXTURE3D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture3D **ppTexture3D) +{ + SERIALISE_ELEMENT_PTR(D3D11_TEXTURE3D_DESC, Descriptor, pDesc); + SERIALISE_ELEMENT(ResourceId, pTexture, GetIDForResource(*ppTexture3D)); + + SERIALISE_ELEMENT(bool, HasInitialData, pInitialData != NULL); + + vector descs = Serialise_CreateTextureData(ppTexture3D ? *ppTexture3D : NULL, pTexture, pInitialData, + Descriptor.Width, Descriptor.Height, Descriptor.Depth, Descriptor.Format, + Descriptor.MipLevels, 1, HasInitialData); + + if(m_State == READING) + { + ID3D11Texture3D *ret; + HRESULT hr = S_OK; + + TextureDisplayType dispType = DispTypeForTexture(Descriptor); + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + if(HasInitialData) + hr = m_pDevice->CreateTexture3D(&Descriptor, &descs[0], &ret); + else + hr = m_pDevice->CreateTexture3D(&Descriptor, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Texture3D(ret, this, dispType); + + GetResourceManager()->AddLiveResource(pTexture, ret); + } + } + + for(size_t i=0; i < descs.size(); i++) + SAFE_DELETE_ARRAY(descs[i].pSysMem); + + return true; +} + +HRESULT WrappedID3D11Device::CreateTexture3D( + /* [annotation] */ + __in const D3D11_TEXTURE3D_DESC *pDesc, + /* [annotation] */ + __in_xcount_opt(pDesc->MipLevels) const D3D11_SUBRESOURCE_DATA *pInitialData, + /* [annotation] */ + __out_opt ID3D11Texture3D **ppTexture3D) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppTexture3D == NULL) return m_pDevice->CreateTexture3D(pDesc, pInitialData, NULL); + + ID3D11Texture3D *real = NULL; + ID3D11Texture3D *wrapped = NULL; + HRESULT ret = m_pDevice->CreateTexture3D(pDesc, pInitialData, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Texture3D(real, this); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(CREATE_TEXTURE_3D); + Serialise_CreateTexture3D(pDesc, pInitialData, &wrapped); + + chunk = scope.Get(); + } + + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(wrapped)); + RDCASSERT(record); + + record->AddChunk(chunk); + record->SetDataPtr(chunk->GetData()); + } + + *ppTexture3D = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateShaderResourceView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11ShaderResourceView **ppSRView) +{ + SERIALISE_ELEMENT(ResourceId, Resource, GetIDForResource(pResource)); + SERIALISE_ELEMENT(bool, HasDesc, pDesc != NULL); + SERIALISE_ELEMENT_PTR_OPT(D3D11_SHADER_RESOURCE_VIEW_DESC, Descriptor, pDesc, HasDesc); + SERIALISE_ELEMENT(ResourceId, pView, GetIDForResource(*ppSRView)); + + if(m_State == READING && GetResourceManager()->HasLiveResource(Resource)) + { + ID3D11ShaderResourceView *ret; + + D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc = NULL; + if(HasDesc) + pDesc = &Descriptor; + + ID3D11Resource *live = (ID3D11Resource*)GetResourceManager()->GetLiveResource(Resource); + + WrappedID3D11Texture2D *tex2d = (WrappedID3D11Texture2D *)live; + + D3D11_SHADER_RESOURCE_VIEW_DESC backbufferTypedDesc; + + // need to fixup typeless backbuffer fudging, if a descriptor isn't specified then + // we need to make one to give the correct type + if(!HasDesc && WrappedID3D11Texture2D::IsAlloc(live) && tex2d->m_RealDescriptor) + { + backbufferTypedDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + + if(tex2d->m_RealDescriptor->SampleDesc.Quality > 0 || + tex2d->m_RealDescriptor->SampleDesc.Count > 1) + backbufferTypedDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + + backbufferTypedDesc.Format = tex2d->m_RealDescriptor->Format; + backbufferTypedDesc.Texture2D.MipLevels = 1; + backbufferTypedDesc.Texture2D.MostDetailedMip = 0; + pDesc = &backbufferTypedDesc; + } + + HRESULT hr = m_pDevice->CreateShaderResourceView(GetResourceManager()->UnwrapResource(live), pDesc, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11ShaderResourceView(ret, live, this); + + GetResourceManager()->AddLiveResource(pView, ret); + } + } + else if(m_State >= WRITING) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(Resource); + + ((WrappedID3D11ShaderResourceView *)*ppSRView)->SetResourceRecord(record); + + RDCASSERT(record); + + record->AddRef(); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateShaderResourceView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11ShaderResourceView **ppSRView) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppSRView == NULL) return m_pDevice->CreateShaderResourceView(GetResourceManager()->UnwrapResource(pResource), pDesc, NULL); + + ID3D11ShaderResourceView *real = NULL; + ID3D11ShaderResourceView *wrapped = NULL; + HRESULT ret = m_pDevice->CreateShaderResourceView(GetResourceManager()->UnwrapResource(pResource), pDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11ShaderResourceView(real, pResource, this); + + Chunk *chunk = NULL; + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_SRV); + Serialise_CreateShaderResourceView(pResource, pDesc, &wrapped); + + chunk = scope.Get(); + + if(WrappedID3D11Texture1D::IsAlloc(pResource) || + WrappedID3D11Texture2D::IsAlloc(pResource) || + WrappedID3D11Texture3D::IsAlloc(pResource) || + WrappedID3D11Buffer::IsAlloc(pResource)) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + RDCERR("Unexpected resource type in SRV creation"); + + m_DeviceRecord->AddChunk(chunk); + } + } + + *ppSRView = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateUnorderedAccessView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11UnorderedAccessView **ppUAView) +{ + SERIALISE_ELEMENT(ResourceId, Resource, GetIDForResource(pResource)); + SERIALISE_ELEMENT(bool, HasDesc, pDesc != NULL); + SERIALISE_ELEMENT_PTR_OPT(D3D11_UNORDERED_ACCESS_VIEW_DESC, Descriptor, pDesc, HasDesc); + SERIALISE_ELEMENT(ResourceId, pView, GetIDForResource(*ppUAView)); + + if(m_State == READING && GetResourceManager()->HasLiveResource(Resource)) + { + ID3D11UnorderedAccessView *ret; + + D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc = NULL; + if(HasDesc) + pDesc = &Descriptor; + + ID3D11Resource *live = (ID3D11Resource*)GetResourceManager()->GetLiveResource(Resource); + + HRESULT hr = m_pDevice->CreateUnorderedAccessView(GetResourceManager()->UnwrapResource(live), pDesc, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11UnorderedAccessView(ret, live, this); + + GetResourceManager()->AddLiveResource(pView, ret); + } + } + else if(m_State >= WRITING) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(ResourceId(Resource)); + + ((WrappedID3D11UnorderedAccessView *)*ppUAView)->SetResourceRecord(record); + + RDCASSERT(record); + + record->AddRef(); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateUnorderedAccessView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11UnorderedAccessView **ppUAView) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppUAView == NULL) return m_pDevice->CreateUnorderedAccessView(GetResourceManager()->UnwrapResource(pResource), pDesc, NULL); + + ID3D11UnorderedAccessView *real = NULL; + ID3D11UnorderedAccessView *wrapped = NULL; + HRESULT ret = m_pDevice->CreateUnorderedAccessView(GetResourceManager()->UnwrapResource(pResource), pDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11UnorderedAccessView(real, pResource, this); + + Chunk *chunk = NULL; + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_UAV); + Serialise_CreateUnorderedAccessView(pResource, pDesc, &wrapped); + + chunk = scope.Get(); + + if(WrappedID3D11Texture1D::IsAlloc(pResource) || + WrappedID3D11Texture2D::IsAlloc(pResource) || + WrappedID3D11Texture3D::IsAlloc(pResource) || + WrappedID3D11Buffer::IsAlloc(pResource)) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + RDCERR("Unexpected resource type in UAV creation"); + + m_DeviceRecord->AddChunk(chunk); + } + } + + *ppUAView = wrapped; + } + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateRenderTargetView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_RENDER_TARGET_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11RenderTargetView **ppRTView) +{ + SERIALISE_ELEMENT(ResourceId, Resource, GetIDForResource(pResource)); + SERIALISE_ELEMENT(bool, HasDesc, pDesc != NULL); + SERIALISE_ELEMENT_PTR_OPT(D3D11_RENDER_TARGET_VIEW_DESC, Descriptor, pDesc, HasDesc); + SERIALISE_ELEMENT(ResourceId, pView, GetIDForResource(*ppRTView)); + + if(m_State == READING && GetResourceManager()->HasLiveResource(Resource)) + { + ID3D11RenderTargetView *ret; + + D3D11_RENDER_TARGET_VIEW_DESC *pDesc = NULL; + if(HasDesc) + pDesc = &Descriptor; + + ID3D11Resource *live = (ID3D11Resource *)GetResourceManager()->GetLiveResource(Resource); + + WrappedID3D11Texture2D *tex2d = (WrappedID3D11Texture2D *)live; + + D3D11_RENDER_TARGET_VIEW_DESC backbufferTypedDesc; + + // need to fixup typeless backbuffer fudging, if a descriptor isn't specified then + // we need to make one to give the correct type + if(!HasDesc && WrappedID3D11Texture2D::IsAlloc(live) && tex2d->m_RealDescriptor) + { + backbufferTypedDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + + if(tex2d->m_RealDescriptor->SampleDesc.Quality > 0 || + tex2d->m_RealDescriptor->SampleDesc.Count > 1) + backbufferTypedDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + + backbufferTypedDesc.Format = tex2d->m_RealDescriptor->Format; + backbufferTypedDesc.Texture2D.MipSlice = 0; + pDesc = &backbufferTypedDesc; + } + + HRESULT hr = m_pDevice->CreateRenderTargetView(GetResourceManager()->UnwrapResource(live), pDesc, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11RenderTargetView(ret, live, this); + + GetResourceManager()->AddLiveResource(pView, ret); + } + } + else if(m_State >= WRITING) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(ResourceId(Resource)); + + RDCASSERT(record); + + ((WrappedID3D11RenderTargetView *)*ppRTView)->SetResourceRecord(record); + + record->AddRef(); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateRenderTargetView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_RENDER_TARGET_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11RenderTargetView **ppRTView) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppRTView == NULL) return m_pDevice->CreateRenderTargetView(GetResourceManager()->UnwrapResource(pResource), pDesc, NULL); + + ID3D11RenderTargetView *real = NULL; + ID3D11RenderTargetView *wrapped = NULL; + HRESULT ret = m_pDevice->CreateRenderTargetView(GetResourceManager()->UnwrapResource(pResource), pDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11RenderTargetView(real, pResource, this); + + Chunk *chunk = NULL; + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_RTV); + Serialise_CreateRenderTargetView(pResource, pDesc, &wrapped); + + chunk = scope.Get(); + + if(WrappedID3D11Texture1D::IsAlloc(pResource) || + WrappedID3D11Texture2D::IsAlloc(pResource) || + WrappedID3D11Texture3D::IsAlloc(pResource) || + WrappedID3D11Buffer::IsAlloc(pResource)) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + RDCERR("Unexpected resource type in RTV creation"); + + m_DeviceRecord->AddChunk(chunk); + } + } + + *ppRTView = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateDepthStencilView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11DepthStencilView **ppDepthStencilView) +{ + SERIALISE_ELEMENT(ResourceId, Resource, GetIDForResource(pResource)); + SERIALISE_ELEMENT(bool, HasDesc, pDesc != NULL); + SERIALISE_ELEMENT_PTR_OPT(D3D11_DEPTH_STENCIL_VIEW_DESC, Descriptor, pDesc, HasDesc); + SERIALISE_ELEMENT(ResourceId, pView, GetIDForResource(*ppDepthStencilView)); + + if(m_State == READING && GetResourceManager()->HasLiveResource(Resource)) + { + ID3D11DepthStencilView *ret; + + ID3D11Resource *live = (ID3D11Resource*)GetResourceManager()->GetLiveResource(Resource); + + D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc = NULL; + if(HasDesc) pDesc = &Descriptor; + + HRESULT hr = m_pDevice->CreateDepthStencilView(GetResourceManager()->UnwrapResource(live), pDesc, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11DepthStencilView(ret, live, this); + + GetResourceManager()->AddLiveResource(pView, ret); + } + } + else if(m_State >= WRITING) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(ResourceId(Resource)); + + ((WrappedID3D11DepthStencilView *)*ppDepthStencilView)->SetResourceRecord(record); + + RDCASSERT(record); + + record->AddRef(); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateDepthStencilView( + /* [annotation] */ + __in ID3D11Resource *pResource, + /* [annotation] */ + __in_opt const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc, + /* [annotation] */ + __out_opt ID3D11DepthStencilView **ppDepthStencilView) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppDepthStencilView == NULL) return m_pDevice->CreateDepthStencilView(GetResourceManager()->UnwrapResource(pResource), pDesc, NULL); + + ID3D11DepthStencilView *real = NULL; + ID3D11DepthStencilView *wrapped = NULL; + HRESULT ret = m_pDevice->CreateDepthStencilView(GetResourceManager()->UnwrapResource(pResource), pDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11DepthStencilView(real, pResource, this); + + Chunk *chunk = NULL; + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_DSV); + Serialise_CreateDepthStencilView(pResource, pDesc, &wrapped); + + chunk = scope.Get(); + + if(WrappedID3D11Texture1D::IsAlloc(pResource) || + WrappedID3D11Texture2D::IsAlloc(pResource) || + WrappedID3D11Texture3D::IsAlloc(pResource) || + WrappedID3D11Buffer::IsAlloc(pResource)) + { + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); + + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + RDCERR("Unexpected resource type in DSV creation"); + + m_DeviceRecord->AddChunk(chunk); + } + } + + *ppDepthStencilView = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateInputLayout( + /* [annotation] */ + __in_ecount(NumElements) const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT ) UINT NumElements, + /* [annotation] */ + __in const void *pShaderBytecodeWithInputSignature, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __out_opt ID3D11InputLayout **ppInputLayout) +{ + SERIALISE_ELEMENT(uint32_t, NumElems, NumElements); + + D3D11_INPUT_ELEMENT_DESC *layouts = new D3D11_INPUT_ELEMENT_DESC[NumElems]; + + for(UINT i=0; i < NumElems; i++) + { + SERIALISE_ELEMENT(D3D11_INPUT_ELEMENT_DESC, layout, pInputElementDescs[i]); + + layouts[i] = layout; + } + + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecodeWithInputSignature, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLayout, GetIDForResource(*ppInputLayout)); + + ID3D11InputLayout *ret = NULL; + if(m_State >= WRITING) + { + ret = *ppInputLayout; + } + else if(m_State == READING) + { + HRESULT hr = m_pDevice->CreateInputLayout(layouts, NumElems, ShaderBytecode, (size_t)BytecodeLen, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11InputLayout(ret, this); + + GetResourceManager()->AddLiveResource(pLayout, ret); + } + + vector descvec(layouts, layouts+NumElems); + + m_LayoutDescs[ret] = descvec; + m_LayoutDXBC[ret] = NULL; + if(BytecodeLen > 0 && ShaderBytecode) + { + DXBC::DXBCFile *dxbc = new DXBC::DXBCFile(ShaderBytecode, BytecodeLen); + + m_LayoutDXBC[ret] = MakeShaderReflection(dxbc); + + delete dxbc; + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + SAFE_DELETE_ARRAY(layouts); + + return true; +} + +HRESULT WrappedID3D11Device::CreateInputLayout( + /* [annotation] */ + __in_ecount(NumElements) const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, + /* [annotation] */ + __in_range( 0, D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT ) UINT NumElements, + /* [annotation] */ + __in const void *pShaderBytecodeWithInputSignature, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __out_opt ID3D11InputLayout **ppInputLayout) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppInputLayout == NULL) return m_pDevice->CreateInputLayout(pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, NULL); + + ID3D11InputLayout *real = NULL; + ID3D11InputLayout *wrapped = NULL; + HRESULT ret = m_pDevice->CreateInputLayout(pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11InputLayout(real, this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_INPUT_LAYOUT); + Serialise_CreateInputLayout(pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + } + + *ppInputLayout = wrapped; + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateVertexShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11VertexShader **ppVertexShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, (void *&)pShaderBytecode, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppVertexShader)); + + if(m_State == READING) + { + ID3D11VertexShader *ret; + HRESULT hr = m_pDevice->CreateVertexShader(ShaderBytecode, (size_t)BytecodeLen, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateVertexShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11VertexShader **ppVertexShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppVertexShader == NULL) return m_pDevice->CreateVertexShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11VertexShader *real = NULL; + ID3D11VertexShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreateVertexShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_VERTEX_SHADER); + Serialise_CreateVertexShader(pShaderBytecode, BytecodeLength, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppVertexShader = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateGeometryShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11GeometryShader **ppGeometryShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecode, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppGeometryShader)); + + if(m_State == READING) + { + ID3D11GeometryShader *ret; + HRESULT hr = m_pDevice->CreateGeometryShader(ShaderBytecode, (size_t)BytecodeLen, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateGeometryShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11GeometryShader **ppGeometryShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppGeometryShader == NULL) return m_pDevice->CreateGeometryShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11GeometryShader *real = NULL; + ID3D11GeometryShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreateGeometryShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_GEOMETRY_SHADER); + Serialise_CreateGeometryShader(pShaderBytecode, BytecodeLength, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppGeometryShader = wrapped; + } + + return ret; +} + + +bool WrappedID3D11Device::Serialise_CreateGeometryShaderWithStreamOutput( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_ecount_opt(NumEntries) const D3D11_SO_DECLARATION_ENTRY *pSODeclaration, + /* [annotation] */ + __in_range( 0, D3D11_SO_STREAM_COUNT * D3D11_SO_OUTPUT_COMPONENT_COUNT ) UINT NumEntries, + /* [annotation] */ + __in_ecount_opt(NumStrides) const UINT *pBufferStrides, + /* [annotation] */ + __in_range( 0, D3D11_SO_BUFFER_SLOT_COUNT ) UINT NumStrides, + /* [annotation] */ + __in UINT RasterizedStream, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11GeometryShader **ppGeometryShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecode, BytecodeLength); + + SERIALISE_ELEMENT(uint32_t, numEntries, NumEntries); + SERIALISE_ELEMENT_ARR(D3D11_SO_DECLARATION_ENTRY, SODecl, pSODeclaration, numEntries); + + SERIALISE_ELEMENT(uint32_t, numStrides, NumStrides); + SERIALISE_ELEMENT_ARR(uint32_t, BufStrides, pBufferStrides, numStrides); + + SERIALISE_ELEMENT(uint32_t, RastStream, RasterizedStream); + + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppGeometryShader)); + + if(m_State == READING) + { + ID3D11GeometryShader *ret; + HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput(ShaderBytecode, (size_t)BytecodeLen, + SODecl, numEntries, + BufStrides, numStrides, + RastStream, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + SAFE_DELETE_ARRAY(SODecl); + SAFE_DELETE_ARRAY(BufStrides); + + return true; +} + +HRESULT WrappedID3D11Device::CreateGeometryShaderWithStreamOutput( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_ecount_opt(NumEntries) const D3D11_SO_DECLARATION_ENTRY *pSODeclaration, + /* [annotation] */ + __in_range( 0, D3D11_SO_STREAM_COUNT * D3D11_SO_OUTPUT_COMPONENT_COUNT ) UINT NumEntries, + /* [annotation] */ + __in_ecount_opt(NumStrides) const UINT *pBufferStrides, + /* [annotation] */ + __in_range( 0, D3D11_SO_BUFFER_SLOT_COUNT ) UINT NumStrides, + /* [annotation] */ + __in UINT RasterizedStream, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11GeometryShader **ppGeometryShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppGeometryShader == NULL) return m_pDevice->CreateGeometryShaderWithStreamOutput(pShaderBytecode, BytecodeLength, pSODeclaration, + NumEntries, pBufferStrides, NumStrides, RasterizedStream, + UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11GeometryShader *real = NULL; + ID3D11GeometryShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreateGeometryShaderWithStreamOutput(pShaderBytecode, BytecodeLength, pSODeclaration, + NumEntries, pBufferStrides, NumStrides, RasterizedStream, + UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_GEOMETRY_SHADER_WITH_SO); + Serialise_CreateGeometryShaderWithStreamOutput(pShaderBytecode, BytecodeLength, pSODeclaration, NumEntries, + pBufferStrides, NumStrides, RasterizedStream, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppGeometryShader = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreatePixelShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11PixelShader **ppPixelShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecode, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppPixelShader)); + + if(m_State == READING) + { + ID3D11PixelShader *ret; + HRESULT hr = m_pDevice->CreatePixelShader(ShaderBytecode, (size_t)BytecodeLen, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreatePixelShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11PixelShader **ppPixelShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppPixelShader == NULL) return m_pDevice->CreatePixelShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11PixelShader *real = NULL; + ID3D11PixelShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreatePixelShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_PIXEL_SHADER); + Serialise_CreatePixelShader(pShaderBytecode, BytecodeLength, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppPixelShader = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateHullShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11HullShader **ppHullShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecode, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppHullShader)); + + if(m_State == READING) + { + ID3D11HullShader *ret; + HRESULT hr = m_pDevice->CreateHullShader(ShaderBytecode, (size_t)BytecodeLen, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateHullShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11HullShader **ppHullShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppHullShader == NULL) return m_pDevice->CreateHullShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11HullShader *real = NULL; + ID3D11HullShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreateHullShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_HULL_SHADER); + Serialise_CreateHullShader(pShaderBytecode, BytecodeLength, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppHullShader = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateDomainShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11DomainShader **ppDomainShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecode, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppDomainShader)); + + if(m_State == READING) + { + ID3D11DomainShader *ret; + HRESULT hr = m_pDevice->CreateDomainShader(ShaderBytecode, (size_t)BytecodeLen, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateDomainShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11DomainShader **ppDomainShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppDomainShader == NULL) return m_pDevice->CreateDomainShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11DomainShader *real = NULL; + ID3D11DomainShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreateDomainShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_DOMAIN_SHADER); + Serialise_CreateDomainShader(pShaderBytecode, BytecodeLength, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppDomainShader = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateComputeShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11ComputeShader **ppComputeShader) +{ + SERIALISE_ELEMENT(uint32_t, BytecodeLen, (uint32_t)BytecodeLength); + SERIALISE_ELEMENT_BUF(byte *, ShaderBytecode, pShaderBytecode, BytecodeLength); + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(pClassLinkage)); + SERIALISE_ELEMENT(ResourceId, pShader, GetIDForResource(*ppComputeShader)); + + if(m_State == READING) + { + ID3D11ComputeShader *ret; + HRESULT hr = m_pDevice->CreateComputeShader(ShaderBytecode, (size_t)BytecodeLen, + UNWRAP(WrappedID3D11ClassLinkage, (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage)), + &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Shader(ret, DXBC::DXBCFile(ShaderBytecode, (size_t)BytecodeLen), this); + + GetResourceManager()->AddLiveResource(pShader, ret); + } + + SAFE_DELETE_ARRAY(ShaderBytecode); + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateComputeShader( + /* [annotation] */ + __in const void *pShaderBytecode, + /* [annotation] */ + __in SIZE_T BytecodeLength, + /* [annotation] */ + __in_opt ID3D11ClassLinkage *pClassLinkage, + /* [annotation] */ + __out_opt ID3D11ComputeShader **ppComputeShader) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppComputeShader == NULL) return m_pDevice->CreateComputeShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL); + + ID3D11ComputeShader *real = NULL; + ID3D11ComputeShader *wrapped = NULL; + HRESULT ret = m_pDevice->CreateComputeShader(pShaderBytecode, BytecodeLength, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Shader(real, DXBC::DXBCFile(pShaderBytecode, BytecodeLength), this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_COMPUTE_SHADER); + Serialise_CreateComputeShader(pShaderBytecode, BytecodeLength, pClassLinkage, &wrapped); + + WrappedID3D11Shader *sh = (WrappedID3D11Shader *)wrapped; + ResourceId id = sh->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); + } + else + { + WrappedID3D11Shader *w = (WrappedID3D11Shader *)wrapped; + + GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped); + } + + *ppComputeShader = wrapped; + } + + return ret; +} + +// Class Linkage 'fake' interfaces +bool WrappedID3D11Device::Serialise_CreateClassInstance(LPCSTR pClassTypeName, + UINT ConstantBufferOffset, UINT ConstantVectorOffset, + UINT TextureOffset, UINT SamplerOffset, + WrappedID3D11ClassLinkage *linkage, ID3D11ClassInstance *inst) +{ + string name = pClassTypeName ? pClassTypeName : ""; + m_pSerialiser->Serialise("name", name); + + SERIALISE_ELEMENT(UINT, cbOffset, ConstantBufferOffset); + SERIALISE_ELEMENT(UINT, cvOffset, ConstantVectorOffset); + SERIALISE_ELEMENT(UINT, texOffset, TextureOffset); + SERIALISE_ELEMENT(UINT, sampOffset, SamplerOffset); + SERIALISE_ELEMENT(ResourceId, pLinkage, linkage->GetResourceID()); + SERIALISE_ELEMENT(ResourceId, instance, GetIDForResource(inst)); + + if(m_State == READING) + { + ID3D11ClassLinkage *wrappedLink = (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage); + ID3D11ClassLinkage *realLink = UNWRAP(WrappedID3D11ClassLinkage, wrappedLink); + + ID3D11ClassInstance *real = NULL; + ID3D11ClassInstance *wrapped = NULL; + HRESULT hr = realLink->CreateClassInstance(name.c_str(), cbOffset, cvOffset, texOffset, sampOffset, &real); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + wrapped = new WrappedID3D11ClassInstance(real, wrappedLink, this); + + GetResourceManager()->AddLiveResource(instance, wrapped); + } + } + + return true; +} + +ID3D11ClassInstance *WrappedID3D11Device::CreateClassInstance(LPCSTR pClassTypeName, + UINT ConstantBufferOffset, UINT ConstantVectorOffset, + UINT TextureOffset, UINT SamplerOffset, + WrappedID3D11ClassLinkage *linkage, ID3D11ClassInstance *inst) +{ + ID3D11ClassInstance *wrapped = NULL; + + if(m_State >= WRITING) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11ClassInstance(inst, linkage, this); + + { + SCOPED_SERIALISE_CONTEXT(CREATE_CLASS_INSTANCE); + Serialise_CreateClassInstance(pClassTypeName, ConstantBufferOffset, ConstantVectorOffset, TextureOffset, SamplerOffset, linkage, wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + return wrapped; + } + + return inst; +} + +bool WrappedID3D11Device::Serialise_GetClassInstance(LPCSTR pClassInstanceName, UINT InstanceIndex, + WrappedID3D11ClassLinkage *linkage, ID3D11ClassInstance *inst) +{ + string name = pClassInstanceName ? pClassInstanceName : ""; + m_pSerialiser->Serialise("name", name); + + SERIALISE_ELEMENT(UINT, idx, InstanceIndex); + SERIALISE_ELEMENT(ResourceId, pLinkage, linkage->GetResourceID()); + SERIALISE_ELEMENT(ResourceId, instance, GetIDForResource(inst)); + + if(m_State == READING) + { + ID3D11ClassLinkage *wrappedLink = (ID3D11ClassLinkage *)GetResourceManager()->GetLiveResource(pLinkage); + ID3D11ClassLinkage *realLink = UNWRAP(WrappedID3D11ClassLinkage, wrappedLink); + + ID3D11ClassInstance *real = NULL; + ID3D11ClassInstance *wrapped = NULL; + HRESULT hr = realLink->GetClassInstance(name.c_str(), idx, &real); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + wrapped = new WrappedID3D11ClassInstance(real, wrappedLink, this); + + GetResourceManager()->AddLiveResource(instance, wrapped); + } + } + + return true; +} + +ID3D11ClassInstance *WrappedID3D11Device::GetClassInstance(LPCSTR pClassInstanceName, UINT InstanceIndex, + WrappedID3D11ClassLinkage *linkage, ID3D11ClassInstance *inst) +{ + ID3D11ClassInstance *wrapped = NULL; + + if(m_State >= WRITING) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11ClassInstance(inst, linkage, this); + + { + SCOPED_SERIALISE_CONTEXT(GET_CLASS_INSTANCE); + Serialise_GetClassInstance(pClassInstanceName, InstanceIndex, linkage, wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + return wrapped; + } + + return inst; +} + +bool WrappedID3D11Device::Serialise_CreateClassLinkage( + /* [annotation] */ + __out ID3D11ClassLinkage **ppLinkage) +{ + SERIALISE_ELEMENT(ResourceId, pLinkage, GetIDForResource(*ppLinkage)); + + if(m_State == READING) + { + ID3D11ClassLinkage *ret; + HRESULT hr = m_pDevice->CreateClassLinkage(&ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11ClassLinkage(ret, this); + + GetResourceManager()->AddLiveResource(pLinkage, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateClassLinkage( + /* [annotation] */ + __out ID3D11ClassLinkage **ppLinkage) +{ + // get 'real' return value for NULL parameter + if(ppLinkage == NULL) return m_pDevice->CreateClassLinkage(NULL); + + ID3D11ClassLinkage *real = NULL; + ID3D11ClassLinkage *wrapped = NULL; + HRESULT ret = m_pDevice->CreateClassLinkage(&real); + + if(SUCCEEDED(ret) && m_State >= WRITING) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11ClassLinkage(real, this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_CLASS_LINKAGE); + Serialise_CreateClassLinkage(&wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppLinkage = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateBlendState( + /* [annotation] */ + __in const D3D11_BLEND_DESC *pBlendStateDesc, + /* [annotation] */ + __out_opt ID3D11BlendState **ppBlendState) +{ + SERIALISE_ELEMENT_PTR(D3D11_BLEND_DESC, Descriptor, pBlendStateDesc); + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(*ppBlendState)); + + if(m_State == READING) + { + ID3D11BlendState *ret; + HRESULT hr = m_pDevice->CreateBlendState(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + if(GetResourceManager()->HasWrapper(ret)) + { + ret = (ID3D11BlendState *)GetResourceManager()->GetWrapper(ret); + ret->AddRef(); + + GetResourceManager()->AddLiveResource(State, ret); + } + else + { + ret = new WrappedID3D11BlendState(ret, this); + + GetResourceManager()->AddLiveResource(State, ret); + } + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateBlendState( + /* [annotation] */ + __in const D3D11_BLEND_DESC *pBlendStateDesc, + /* [annotation] */ + __out_opt ID3D11BlendState **ppBlendState) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppBlendState == NULL) return m_pDevice->CreateBlendState(pBlendStateDesc, NULL); + + ID3D11BlendState *real = NULL; + HRESULT ret = m_pDevice->CreateBlendState(pBlendStateDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + // duplicate states can be returned, if Create is called with a previous descriptor + if(GetResourceManager()->HasWrapper(real)) + { + real->Release(); + *ppBlendState = (ID3D11BlendState *)GetResourceManager()->GetWrapper(real); + (*ppBlendState)->AddRef(); + return ret; + } + + ID3D11BlendState *wrapped = new WrappedID3D11BlendState(real, this); + + if(RenderDoc::Inst().GetCaptureOptions().CacheStateObjects) + { + RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end()); + wrapped->AddRef(); + InternalRef(); + m_CachedStateObjects.insert(wrapped); + } + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_BLEND_STATE); + Serialise_CreateBlendState(pBlendStateDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppBlendState = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateDepthStencilState( + /* [annotation] */ + __in const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc, + /* [annotation] */ + __out_opt ID3D11DepthStencilState **ppDepthStencilState) +{ + SERIALISE_ELEMENT_PTR(D3D11_DEPTH_STENCIL_DESC, Descriptor, pDepthStencilDesc); + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(*ppDepthStencilState)); + + if(m_State == READING) + { + ID3D11DepthStencilState *ret; + HRESULT hr = m_pDevice->CreateDepthStencilState(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11DepthStencilState(ret, this); + + GetResourceManager()->AddLiveResource(State, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateDepthStencilState( + /* [annotation] */ + __in const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc, + /* [annotation] */ + __out_opt ID3D11DepthStencilState **ppDepthStencilState) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppDepthStencilState == NULL) return m_pDevice->CreateDepthStencilState(pDepthStencilDesc, NULL); + + ID3D11DepthStencilState *real = NULL; + HRESULT ret = m_pDevice->CreateDepthStencilState(pDepthStencilDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + // duplicate states can be returned, if Create is called with a previous descriptor + if(GetResourceManager()->HasWrapper(real)) + { + real->Release(); + *ppDepthStencilState = (ID3D11DepthStencilState *)GetResourceManager()->GetWrapper(real); + (*ppDepthStencilState)->AddRef(); + return ret; + } + + ID3D11DepthStencilState *wrapped = new WrappedID3D11DepthStencilState(real, this); + + if(RenderDoc::Inst().GetCaptureOptions().CacheStateObjects) + { + RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end()); + wrapped->AddRef(); + InternalRef(); + m_CachedStateObjects.insert(wrapped); + } + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_DEPTHSTENCIL_STATE); + Serialise_CreateDepthStencilState(pDepthStencilDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppDepthStencilState = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateRasterizerState( + /* [annotation] */ + __in const D3D11_RASTERIZER_DESC *pRasterizerDesc, + /* [annotation] */ + __out_opt ID3D11RasterizerState **ppRasterizerState) +{ + SERIALISE_ELEMENT_PTR(D3D11_RASTERIZER_DESC, Descriptor, pRasterizerDesc); + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(*ppRasterizerState)); + + if(m_State == READING) + { + ID3D11RasterizerState *ret; + HRESULT hr = m_pDevice->CreateRasterizerState(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11RasterizerState(ret, this); + + GetResourceManager()->AddLiveResource(State, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateRasterizerState( + /* [annotation] */ + __in const D3D11_RASTERIZER_DESC *pRasterizerDesc, + /* [annotation] */ + __out_opt ID3D11RasterizerState **ppRasterizerState) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppRasterizerState == NULL) return m_pDevice->CreateRasterizerState(pRasterizerDesc, NULL); + + ID3D11RasterizerState *real = NULL; + HRESULT ret = m_pDevice->CreateRasterizerState(pRasterizerDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + // duplicate states can be returned, if Create is called with a previous descriptor + if(GetResourceManager()->HasWrapper(real)) + { + real->Release(); + *ppRasterizerState = (ID3D11RasterizerState *)GetResourceManager()->GetWrapper(real); + (*ppRasterizerState)->AddRef(); + return ret; + } + + ID3D11RasterizerState *wrapped = new WrappedID3D11RasterizerState(real, this); + + if(RenderDoc::Inst().GetCaptureOptions().CacheStateObjects) + { + RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end()); + wrapped->AddRef(); + InternalRef(); + m_CachedStateObjects.insert(wrapped); + } + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_RASTER_STATE); + Serialise_CreateRasterizerState(pRasterizerDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppRasterizerState = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateSamplerState( + /* [annotation] */ + __in const D3D11_SAMPLER_DESC *pSamplerDesc, + /* [annotation] */ + __out_opt ID3D11SamplerState **ppSamplerState) +{ + SERIALISE_ELEMENT_PTR(D3D11_SAMPLER_DESC, Descriptor, pSamplerDesc); + SERIALISE_ELEMENT(ResourceId, State, GetIDForResource(*ppSamplerState)); + + if(m_State == READING) + { + ID3D11SamplerState *ret; + HRESULT hr = m_pDevice->CreateSamplerState(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11SamplerState(ret, this); + + GetResourceManager()->AddLiveResource(State, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateSamplerState( + /* [annotation] */ + __in const D3D11_SAMPLER_DESC *pSamplerDesc, + /* [annotation] */ + __out_opt ID3D11SamplerState **ppSamplerState) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppSamplerState == NULL) return m_pDevice->CreateSamplerState(pSamplerDesc, NULL); + + ID3D11SamplerState *real = NULL; + HRESULT ret = m_pDevice->CreateSamplerState(pSamplerDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + // duplicate states can be returned, if Create is called with a previous descriptor + if(GetResourceManager()->HasWrapper(real)) + { + real->Release(); + *ppSamplerState = (ID3D11SamplerState *)GetResourceManager()->GetWrapper(real); + (*ppSamplerState)->AddRef(); + return ret; + } + + ID3D11SamplerState *wrapped = new WrappedID3D11SamplerState(real, this); + + if(RenderDoc::Inst().GetCaptureOptions().CacheStateObjects) + { + RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end()); + wrapped->AddRef(); + InternalRef(); + m_CachedStateObjects.insert(wrapped); + } + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_SAMPLER_STATE); + Serialise_CreateSamplerState(pSamplerDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppSamplerState = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateQuery( + /* [annotation] */ + __in const D3D11_QUERY_DESC *pQueryDesc, + /* [annotation] */ + __out_opt ID3D11Query **ppQuery) +{ + SERIALISE_ELEMENT_PTR(D3D11_QUERY_DESC, Descriptor, pQueryDesc); + SERIALISE_ELEMENT(ResourceId, Query, GetIDForResource(*ppQuery)); + + if(m_State == READING) + { + ID3D11Query *ret; + HRESULT hr = m_pDevice->CreateQuery(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Query(ret, this); + + GetResourceManager()->AddLiveResource(Query, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateQuery( + /* [annotation] */ + __in const D3D11_QUERY_DESC *pQueryDesc, + /* [annotation] */ + __out_opt ID3D11Query **ppQuery) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppQuery == NULL) return m_pDevice->CreateQuery(pQueryDesc, NULL); + + ID3D11Query *real = NULL; + HRESULT ret = m_pDevice->CreateQuery(pQueryDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + *ppQuery = new WrappedID3D11Query(real, this); + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreatePredicate( + /* [annotation] */ + __in const D3D11_QUERY_DESC *pPredicateDesc, + /* [annotation] */ + __out_opt ID3D11Predicate **ppPredicate) +{ + SERIALISE_ELEMENT_PTR(D3D11_QUERY_DESC, Descriptor, pPredicateDesc); + SERIALISE_ELEMENT(ResourceId, Predicate, GetIDForResource(*ppPredicate)); + + if(m_State == READING) + { + ID3D11Predicate *ret; + HRESULT hr = m_pDevice->CreatePredicate(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Predicate(ret, this); + + GetResourceManager()->AddLiveResource(Predicate, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreatePredicate( + /* [annotation] */ + __in const D3D11_QUERY_DESC *pPredicateDesc, + /* [annotation] */ + __out_opt ID3D11Predicate **ppPredicate) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppPredicate == NULL) return m_pDevice->CreatePredicate(pPredicateDesc, NULL); + + ID3D11Predicate *real = NULL; + ID3D11Predicate *wrapped = NULL; + HRESULT ret = m_pDevice->CreatePredicate(pPredicateDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + wrapped = new WrappedID3D11Predicate(real, this); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CREATE_PREDICATE); + Serialise_CreatePredicate(pPredicateDesc, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppPredicate = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateCounter( + /* [annotation] */ + __in const D3D11_COUNTER_DESC *pCounterDesc, + /* [annotation] */ + __out_opt ID3D11Counter **ppCounter) +{ + SERIALISE_ELEMENT_PTR(D3D11_COUNTER_DESC, Descriptor, pCounterDesc); + SERIALISE_ELEMENT(ResourceId, Counter, GetIDForResource(*ppCounter)); + + if(m_State == READING) + { + ID3D11Counter *ret; + HRESULT hr = m_pDevice->CreateCounter(&Descriptor, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Counter(ret, this); + + GetResourceManager()->AddLiveResource(Counter, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateCounter( + /* [annotation] */ + __in const D3D11_COUNTER_DESC *pCounterDesc, + /* [annotation] */ + __out_opt ID3D11Counter **ppCounter) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppCounter == NULL) return m_pDevice->CreateCounter(pCounterDesc, NULL); + + ID3D11Counter *real = NULL; + HRESULT ret = m_pDevice->CreateCounter(pCounterDesc, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + *ppCounter = new WrappedID3D11Counter(real, this); + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_CreateDeferredContext( + /* [annotation] */ + __in const UINT ContextFlags, + /* [annotation] */ + __out_opt ID3D11DeviceContext **ppDeferredContext) +{ + SERIALISE_ELEMENT(uint32_t, Flags, ContextFlags); + SERIALISE_ELEMENT(ResourceId, Context, GetIDForResource(*ppDeferredContext)); + + if(m_State == READING) + { + ID3D11DeviceContext *ret; + HRESULT hr = m_pDevice->CreateDeferredContext(Flags, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11DeviceContext(this, ret, m_pSerialiser, m_pDebugSerialiser); + + AddDeferredContext((WrappedID3D11DeviceContext *)ret); + + GetResourceManager()->AddLiveResource(Context, ret); + } + } + + return true; +} + +HRESULT WrappedID3D11Device::CreateDeferredContext( + UINT ContextFlags, + /* [annotation] */ + __out_opt ID3D11DeviceContext **ppDeferredContext) +{ + // validation, returns S_FALSE for valid params, or an error code + if(ppDeferredContext == NULL) return m_pDevice->CreateDeferredContext(ContextFlags, NULL); + + ID3D11DeviceContext *real = NULL; + ID3D11DeviceContext *wrapped = NULL; + HRESULT ret = m_pDevice->CreateDeferredContext(ContextFlags, &real); + + if(SUCCEEDED(ret)) + { + SCOPED_LOCK(m_D3DLock); + + WrappedID3D11DeviceContext *w = new WrappedID3D11DeviceContext(this, real, m_pSerialiser, m_pDebugSerialiser); + + wrapped = w; + + if(m_State >= WRITING) + { + AddDeferredContext(w); + + SCOPED_SERIALISE_CONTEXT(CREATE_DEFERRED_CONTEXT); + Serialise_CreateDeferredContext(ContextFlags, &wrapped); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + *ppDeferredContext = wrapped; + } + + return ret; +} + +bool WrappedID3D11Device::Serialise_OpenSharedResource( + /* [annotation] */ + __in HANDLE hResource, + /* [annotation] */ + __in REFIID ReturnedInterface, + /* [annotation] */ + __out_opt void **ppResource) +{ + SERIALISE_ELEMENT(ResourceType, type, IdentifyTypeByPtr((IUnknown *)*ppResource)); + SERIALISE_ELEMENT(ResourceId, pResource, GetIDForResource((ID3D11DeviceChild*)*ppResource)); + + if(type == Resource_Buffer) + { + D3D11_BUFFER_DESC desc; + RDCEraseEl(desc); + + if(m_State >= WRITING) + { + ID3D11Buffer *buf = (ID3D11Buffer *)*ppResource; + buf->GetDesc(&desc); + } + + SERIALISE_ELEMENT(D3D11_BUFFER_DESC, Descriptor, desc); + + char *dummy = new char[Descriptor.ByteWidth]; + SERIALISE_ELEMENT_BUF(byte *, InitialData, dummy, Descriptor.ByteWidth); + delete[] dummy; + + uint64_t offs = m_pSerialiser->GetOffset()-Descriptor.ByteWidth; + + RDCASSERT((offs%16)==0); + + if(m_State >= WRITING) + { + RDCASSERT(GetResourceManager()->GetResourceRecord(pResource) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(pResource); + record->SetDataOffset(offs); + record->DataInSerialiser = true; + record->Length = Descriptor.ByteWidth; + } + + if(m_State == READING) + { + ID3D11Buffer *ret; + + HRESULT hr = S_OK; + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = InitialData; + data.SysMemPitch = Descriptor.ByteWidth; + data.SysMemSlicePitch = Descriptor.ByteWidth; + hr = m_pDevice->CreateBuffer(&Descriptor, &data, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Buffer(ret, Descriptor.ByteWidth, this); + + GetResourceManager()->AddLiveResource(pResource, ret); + } + + if(Descriptor.Usage != D3D11_USAGE_IMMUTABLE) + { + ID3D11Buffer *stage = NULL; + + D3D11_BUFFER_DESC desc; + desc.ByteWidth = Descriptor.ByteWidth; + desc.MiscFlags = 0; + desc.StructureByteStride = 0; + // We don't need to bind this, but IMMUTABLE requires at least one + // BindFlags. + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_IMMUTABLE; + + hr = m_pDevice->CreateBuffer(&desc, &data, &stage); + + if(FAILED(hr) || stage == NULL) + { + RDCERR("Failed to create staging buffer for buffer initial contents %08x", hr); + } + else + { + m_ResourceManager->SetInitialContents(pResource, stage, 0); + } + } + + SAFE_DELETE_ARRAY(InitialData); + } + } + else if(type == Resource_Texture1D) + { + D3D11_TEXTURE1D_DESC desc; + RDCEraseEl(desc); + + if(m_State >= WRITING) + { + ID3D11Texture1D *tex = (ID3D11Texture1D *)*ppResource; + tex->GetDesc(&desc); + } + + SERIALISE_ELEMENT(D3D11_TEXTURE1D_DESC, Descriptor, desc); + + Serialise_CreateTextureData(ppResource ? (ID3D11Texture1D *)*ppResource : NULL, pResource, NULL, + Descriptor.Width, 1, 1, Descriptor.Format, + Descriptor.MipLevels, Descriptor.ArraySize, false); + + if(m_State == READING) + { + ID3D11Texture1D *ret; + HRESULT hr = S_OK; + + TextureDisplayType dispType = DispTypeForTexture(Descriptor); + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + hr = m_pDevice->CreateTexture1D(&Descriptor, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Texture1D(ret, this, dispType); + + GetResourceManager()->AddLiveResource(pResource, ret); + } + } + } + else if(type == Resource_Texture2D) + { + D3D11_TEXTURE2D_DESC desc; + RDCEraseEl(desc); + + if(m_State >= WRITING) + { + ID3D11Texture2D *tex = (ID3D11Texture2D *)*ppResource; + tex->GetDesc(&desc); + } + + SERIALISE_ELEMENT(D3D11_TEXTURE2D_DESC, Descriptor, desc); + + Serialise_CreateTextureData(ppResource ? (ID3D11Texture2D *)*ppResource : NULL, pResource, NULL, + Descriptor.Width, Descriptor.Height, 1, Descriptor.Format, + Descriptor.MipLevels, Descriptor.ArraySize, false); + + if(m_State == READING) + { + ID3D11Texture2D *ret; + HRESULT hr = S_OK; + + TextureDisplayType dispType = DispTypeForTexture(Descriptor); + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + hr = m_pDevice->CreateTexture2D(&Descriptor, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Texture2D(ret, this, dispType); + + GetResourceManager()->AddLiveResource(pResource, ret); + } + } + } + else if(type == Resource_Texture3D) + { + D3D11_TEXTURE3D_DESC desc; + RDCEraseEl(desc); + + if(m_State >= WRITING) + { + ID3D11Texture3D *tex = (ID3D11Texture3D *)*ppResource; + tex->GetDesc(&desc); + } + + SERIALISE_ELEMENT(D3D11_TEXTURE3D_DESC, Descriptor, desc); + + Serialise_CreateTextureData(ppResource ? (ID3D11Texture3D *)*ppResource : NULL, pResource, NULL, + Descriptor.Width, Descriptor.Height, Descriptor.Depth, Descriptor.Format, + Descriptor.MipLevels, 1, false); + + if(m_State == READING) + { + ID3D11Texture3D *ret; + HRESULT hr = S_OK; + + TextureDisplayType dispType = DispTypeForTexture(Descriptor); + + // unset flags that are unimportant/problematic in replay + Descriptor.MiscFlags &= ~(D3D11_RESOURCE_MISC_SHARED| + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX| + D3D11_RESOURCE_MISC_GDI_COMPATIBLE| + D3D11_RESOURCE_MISC_SHARED_NTHANDLE); + + hr = m_pDevice->CreateTexture3D(&Descriptor, NULL, &ret); + + if(FAILED(hr)) + { + RDCERR("Failed on resource serialise-creation, HRESULT: 0x%08x", hr); + } + else + { + ret = new WrappedID3D11Texture3D(ret, this, dispType); + + GetResourceManager()->AddLiveResource(pResource, ret); + } + } + } + + return true; +} + +HRESULT WrappedID3D11Device::OpenSharedResource( + /* [annotation] */ + __in HANDLE hResource, + /* [annotation] */ + __in REFIID ReturnedInterface, + /* [annotation] */ + __out_opt void **ppResource) +{ + if(m_State < WRITING || ppResource == NULL) return E_INVALIDARG; + + bool isRes = ReturnedInterface == __uuidof(ID3D11Resource); + bool isBuf = ReturnedInterface == __uuidof(ID3D11Buffer); + bool isTex1D = ReturnedInterface == __uuidof(ID3D11Texture1D); + bool isTex2D = ReturnedInterface == __uuidof(ID3D11Texture2D); + bool isTex3D = ReturnedInterface == __uuidof(ID3D11Texture3D); + + if(isRes || isBuf || isTex1D || isTex2D || isTex3D) + { + void *res = NULL; + HRESULT hr = m_pDevice->OpenSharedResource(hResource, ReturnedInterface, &res); + + if(FAILED(hr)) + { + IUnknown *unk = (IUnknown *)res; + SAFE_RELEASE(unk); + return hr; + } + else + { + SCOPED_LOCK(m_D3DLock); + + ResourceId wrappedID; + + if(isRes) + { + ID3D11Resource *resource = (ID3D11Resource *)res; + D3D11_RESOURCE_DIMENSION dim; + resource->GetType(&dim); + + if(dim == D3D11_RESOURCE_DIMENSION_BUFFER) + { + res = (ID3D11Buffer *)(ID3D11Resource *)res; + isBuf = true; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + res = (ID3D11Texture1D *)(ID3D11Resource *)res; + isTex1D = true; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + res = (ID3D11Texture2D *)(ID3D11Resource *)res; + isTex2D = true; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) + { + res = (ID3D11Texture3D *)(ID3D11Resource *)res; + isTex3D = true; + } + } + + ID3D11Resource *realRes = NULL; + + if(isBuf) + { + WrappedID3D11Buffer *w = new WrappedID3D11Buffer((ID3D11Buffer *)res, 0, this); + wrappedID = w->GetResourceID(); + + realRes = w->GetReal(); + + *ppResource = (ID3D11Buffer *)w; + } + else if(isTex1D) + { + WrappedID3D11Texture1D *w = new WrappedID3D11Texture1D((ID3D11Texture1D *)res, this); + wrappedID = w->GetResourceID(); + + realRes = w->GetReal(); + + *ppResource = (ID3D11Texture1D *)w; + } + else if(isTex2D) + { + WrappedID3D11Texture2D *w = new WrappedID3D11Texture2D((ID3D11Texture2D *)res, this); + wrappedID = w->GetResourceID(); + + realRes = w->GetReal(); + + *ppResource = (ID3D11Texture2D *)w; + } + else if(isTex3D) + { + WrappedID3D11Texture3D *w = new WrappedID3D11Texture3D((ID3D11Texture3D *)res, this); + wrappedID = w->GetResourceID(); + + realRes = w->GetReal(); + + *ppResource = (ID3D11Texture3D *)w; + } + + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(OPEN_SHARED_RESOURCE); + Serialise_OpenSharedResource(hResource, ReturnedInterface, ppResource); + + chunk = scope.Get(); + } + + // don't know where this came from or who might modify it at any point. + GetResourceManager()->MarkDirtyResource(wrappedID); + + D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(wrappedID); + RDCASSERT(record); + + record->AddChunk(chunk); + record->SetDataPtr(chunk->GetData()); + } + + return S_OK; + } + + return E_NOINTERFACE; +} + +HRESULT WrappedID3D11Device::CheckFormatSupport( + /* [annotation] */ + __in DXGI_FORMAT Format, + /* [annotation] */ + __out UINT *pFormatSupport) +{ + return m_pDevice->CheckFormatSupport(Format, pFormatSupport); +} + +HRESULT WrappedID3D11Device::CheckMultisampleQualityLevels( + /* [annotation] */ + __in DXGI_FORMAT Format, + /* [annotation] */ + __in UINT SampleCount, + /* [annotation] */ + __out UINT *pNumQualityLevels) +{ + return m_pDevice->CheckMultisampleQualityLevels(Format, SampleCount, pNumQualityLevels); +} + +void WrappedID3D11Device::CheckCounterInfo( + /* [annotation] */ + __out D3D11_COUNTER_INFO *pCounterInfo) +{ + m_pDevice->CheckCounterInfo(pCounterInfo); +} + +HRESULT WrappedID3D11Device::CheckCounter( + /* [annotation] */ + __in const D3D11_COUNTER_DESC *pDesc, + /* [annotation] */ + __out D3D11_COUNTER_TYPE *pType, + /* [annotation] */ + __out UINT *pActiveCounters, + /* [annotation] */ + __out_ecount_opt(*pNameLength) LPSTR szName, + /* [annotation] */ + __inout_opt UINT *pNameLength, + /* [annotation] */ + __out_ecount_opt(*pUnitsLength) LPSTR szUnits, + /* [annotation] */ + __inout_opt UINT *pUnitsLength, + /* [annotation] */ + __out_ecount_opt(*pDescriptionLength) LPSTR szDescription, + /* [annotation] */ + __inout_opt UINT *pDescriptionLength) +{ + return m_pDevice->CheckCounter(pDesc, pType, pActiveCounters, szName, pNameLength, szUnits, pUnitsLength, szDescription, pDescriptionLength); +} + +HRESULT WrappedID3D11Device::CheckFeatureSupport( + D3D11_FEATURE Feature, + /* [annotation] */ + __out_bcount(FeatureSupportDataSize) void *pFeatureSupportData, + UINT FeatureSupportDataSize) +{ + return m_pDevice->CheckFeatureSupport(Feature, pFeatureSupportData, FeatureSupportDataSize); +} + +HRESULT WrappedID3D11Device::GetPrivateData( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __inout UINT *pDataSize, + /* [annotation] */ + __out_bcount_opt(*pDataSize) void *pData) +{ + return m_pDevice->GetPrivateData(guid, pDataSize, pData); +} + +HRESULT WrappedID3D11Device::SetPrivateData( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __in UINT DataSize, + /* [annotation] */ + __in_bcount_opt(DataSize) const void *pData) +{ + return m_pDevice->SetPrivateData(guid, DataSize, pData); +} + +HRESULT WrappedID3D11Device::SetPrivateDataInterface( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __in_opt const IUnknown *pData) +{ + return m_pDevice->SetPrivateDataInterface(guid, pData); +} + +D3D_FEATURE_LEVEL WrappedID3D11Device::GetFeatureLevel() +{ + return m_pDevice->GetFeatureLevel(); +} + +UINT WrappedID3D11Device::GetCreationFlags() +{ + return m_pDevice->GetCreationFlags(); +} + +HRESULT WrappedID3D11Device::GetDeviceRemovedReason() +{ + return m_pDevice->GetDeviceRemovedReason(); +} + +void WrappedID3D11Device::GetImmediateContext( + /* [annotation] */ + __out ID3D11DeviceContext **ppImmediateContext) +{ + if(ppImmediateContext) + { + *ppImmediateContext = (ID3D11DeviceContext *)m_pImmediateContext; + m_pImmediateContext->AddRef(); + } +} + +bool WrappedID3D11Device::Serialise_SetExceptionMode(UINT RaiseFlags) +{ + SERIALISE_ELEMENT(uint32_t, Flags, RaiseFlags); + + if(m_State == READING) + { + m_pDevice->SetExceptionMode(Flags); + } + + return true; +} + +HRESULT WrappedID3D11Device::SetExceptionMode(UINT RaiseFlags) +{ + HRESULT ret = m_pDevice->SetExceptionMode(RaiseFlags); + + if(SUCCEEDED(ret) && m_State >= WRITING) + { + SCOPED_LOCK(m_D3DLock); + + SCOPED_SERIALISE_CONTEXT(SET_EXCEPTION_MODE); + Serialise_SetExceptionMode(RaiseFlags); + + m_DeviceRecord->AddChunk(scope.Get()); + } + + return ret; +} + +UINT WrappedID3D11Device::GetExceptionMode() +{ + return m_pDevice->GetExceptionMode(); +} \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_manager.cpp b/renderdoc/driver/d3d11/d3d11_manager.cpp new file mode 100644 index 0000000000..6379f1062a --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_manager.cpp @@ -0,0 +1,115 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/d3d11/d3d11_manager.h" +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_resources.h" + +ID3D11DeviceChild *D3D11ResourceManager::UnwrapResource(ID3D11DeviceChild *res) +{ + if(res == NULL) return res; + + if(WrappedID3D11Buffer::IsAlloc(res)) + return UNWRAP(WrappedID3D11Buffer, res); + else if(WrappedID3D11Texture1D::IsAlloc(res)) + return UNWRAP(WrappedID3D11Texture1D, res); + else if(WrappedID3D11Texture2D::IsAlloc(res)) + return UNWRAP(WrappedID3D11Texture2D, res); + else if(WrappedID3D11Texture3D::IsAlloc(res)) + return UNWRAP(WrappedID3D11Texture3D, res); + + RDCERR("UnwrapResource(): Unexpected non-wrapped resource"); + return res; +} + +bool D3D11ResourceManager::SerialisableResource(ResourceId id, D3D11ResourceRecord *record) +{ + if(id == m_Device->GetImmediateContext()->GetResourceID()) + return false; + + if(id == m_Device->GetResourceID()) + return true; + + if(record->ignoreSerialise) + return false; + + bool skip = false; + for(size_t i=0; i < m_Device->GetNumDeferredContexts(); i++) + { + if(id == m_Device->GetDeferredContext(i)->GetResourceID()) + { + skip = true; + break; + } + } + + if(skip) + return false; + + return true; +} + +ResourceId D3D11ResourceManager::GetID(ID3D11DeviceChild *res) +{ + return GetIDForResource(res); +} + +bool D3D11ResourceManager::ResourceTypeRelease(ID3D11DeviceChild *res) +{ + if(res) + res->Release(); + + return true; +} + +bool D3D11ResourceManager::Need_InitialState(ID3D11DeviceChild *res) +{ + return IdentifyTypeByPtr(res) == Resource_UnorderedAccessView; +} + +bool D3D11ResourceManager::Need_InitialStateChunk(ID3D11DeviceChild *res) +{ + return IdentifyTypeByPtr(res) != Resource_Buffer; +} + +bool D3D11ResourceManager::Prepare_InitialState(ID3D11DeviceChild *res) +{ + return m_Device->Prepare_InitialState(res); +} + +bool D3D11ResourceManager::Serialise_InitialState(ID3D11DeviceChild *res) +{ + return m_Device->Serialise_InitialState(res); +} + +void D3D11ResourceManager::Create_InitialState(ResourceId id, ID3D11DeviceChild *live, bool hasData) +{ + m_Device->Create_InitialState(id, live, hasData); +} + +void D3D11ResourceManager::Apply_InitialState(ID3D11DeviceChild *live, ID3D11DeviceChild *initial, uint32_t count) +{ + m_Device->Apply_InitialState(live, initial, count); +} diff --git a/renderdoc/driver/d3d11/d3d11_manager.h b/renderdoc/driver/d3d11/d3d11_manager.h new file mode 100644 index 0000000000..d267f8760b --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_manager.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#define INITGUID + +#include +#include + +#include "driver/d3d11/d3d11_common.h" + +#include "core/core.h" +#include "replay/renderdoc.h" + +#include "serialise/serialiser.h" +#include "common/wrapped_pool.h" +#include "core/resource_manager.h" + +struct D3D11ResourceRecord : public ResourceRecord +{ + enum { NullResource = NULL }; + + D3D11ResourceRecord(ResourceId id) + : ResourceRecord(id, true) + { + RDCEraseEl(ShadowPtr); + RDCEraseEl(contexts); + ignoreSerialise = false; + } + + ~D3D11ResourceRecord() + { + FreeShadowStorage(); + } + + void AllocShadowStorage(int ctx, size_t size) + { + if(ShadowPtr[ctx][0] == NULL) + { + ShadowPtr[ctx][0] = Serialiser::AllocAlignedBuffer(size); + ShadowPtr[ctx][1] = Serialiser::AllocAlignedBuffer(size); + } + } + + void FreeShadowStorage() + { + for(int i=0; i < 32; i++) + { + if(ShadowPtr[i][0] != NULL) + { + Serialiser::FreeAlignedBuffer(ShadowPtr[i][0]); + Serialiser::FreeAlignedBuffer(ShadowPtr[i][1]); + } + ShadowPtr[i][0] = ShadowPtr[i][1] = NULL; + } + } + + byte *GetShadowPtr(int ctx, int p) + { + return ShadowPtr[ctx][p]; + } + + int GetContextID() + { + // 0 is reserved for the immediate context + for(int i=1; i < 32; i++) + { + if(contexts[i] == false) + { + contexts[i] = true; + return i; + } + } + + RDCERR("More than 32 deferred contexts wanted an ID! Either a leak, or many many contexts mapping the same buffer"); + + return 0; + } + + void FreeContextID(int ctx) + { + contexts[ctx] = false; + } + + bool ignoreSerialise; + +private: + byte *ShadowPtr[32][2]; + + bool contexts[32]; +}; + +class D3D11ResourceManager : public ResourceManager +{ + public: + D3D11ResourceManager(WrappedID3D11Device *dev) + : m_Device(dev) + { + } + + + ID3D11DeviceChild *UnwrapResource(ID3D11DeviceChild *res); + ID3D11Resource *UnwrapResource(ID3D11Resource *res) { return (ID3D11Resource *)UnwrapResource((ID3D11DeviceChild *)res); } + + private: + bool SerialisableResource(ResourceId id, D3D11ResourceRecord *record); + ResourceId GetID(ID3D11DeviceChild *res); + + bool ResourceTypeRelease(ID3D11DeviceChild *res); + + bool Need_InitialState(ID3D11DeviceChild *res); + bool Need_InitialStateChunk(ID3D11DeviceChild *res); + bool Prepare_InitialState(ID3D11DeviceChild *res); + bool Serialise_InitialState(ID3D11DeviceChild *res); + void Create_InitialState(ResourceId id, ID3D11DeviceChild *live, bool hasData); + void Apply_InitialState(ID3D11DeviceChild *live, ID3D11DeviceChild *initial, uint32_t count); + + WrappedID3D11Device *m_Device; +}; + +template +typename Dest::InnerType *Unwrap(typename Dest::InnerType *obj) +{ +#if !defined(RELEASE) + if(obj && !Dest::IsAlloc(obj)) + { + RDCERR("Trying to unwrap invalid type"); + return NULL; + } +#endif + return obj == NULL ? NULL : (Dest::InnerType *)((Dest *)obj)->GetReal(); +} + +#define UNWRAP(type, obj) Unwrap((type::InnerType *)obj) diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.cpp b/renderdoc/driver/d3d11/d3d11_renderstate.cpp new file mode 100644 index 0000000000..42a8fdef18 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_renderstate.cpp @@ -0,0 +1,1427 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/d3d11/d3d11_renderstate.h" +#include "driver/d3d11/d3d11_device.h" +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_resources.h" + +D3D11RenderState::D3D11RenderState(Serialiser *ser) +{ + RDCEraseEl(IA); + RDCEraseEl(VS); + RDCEraseEl(HS); + RDCEraseEl(DS); + RDCEraseEl(GS); + RDCEraseEl(SO); + RDCEraseEl(RS); + RDCEraseEl(PS); + RDCEraseEl(OM); + RDCEraseEl(CS); + Clear(); + m_pSerialiser = ser; + + m_ImmediatePipeline = false; + m_pDevice = NULL; +} + +D3D11RenderState::D3D11RenderState(const D3D11RenderState &other) +{ + RDCEraseEl(IA); + RDCEraseEl(VS); + RDCEraseEl(HS); + RDCEraseEl(DS); + RDCEraseEl(GS); + RDCEraseEl(SO); + RDCEraseEl(RS); + RDCEraseEl(PS); + RDCEraseEl(OM); + RDCEraseEl(CS); + *this = other; + + m_ImmediatePipeline = false; + m_pDevice = NULL; +} + +D3D11RenderState &D3D11RenderState::operator =(const D3D11RenderState &other) +{ + ReleaseRefs(); + + memcpy(&IA, &other.IA, sizeof(IA)); + memcpy(&VS, &other.VS, sizeof(VS)); + memcpy(&HS, &other.HS, sizeof(HS)); + memcpy(&DS, &other.DS, sizeof(DS)); + memcpy(&GS, &other.GS, sizeof(GS)); + memcpy(&SO, &other.SO, sizeof(SO)); + memcpy(&RS, &other.RS, sizeof(RS)); + memcpy(&PS, &other.PS, sizeof(PS)); + memcpy(&OM, &other.OM, sizeof(OM)); + memcpy(&CS, &other.CS, sizeof(CS)); + + m_ImmediatePipeline = false; + m_pDevice = NULL; + + AddRefs(); + + return *this; +} + +D3D11RenderState::~D3D11RenderState() +{ + ReleaseRefs(); +} + +void D3D11RenderState::ReleaseRefs() +{ + ReleaseRef(IA.IndexBuffer); + ReleaseRef(IA.Layout); + + for(UINT i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + ReleaseRef(IA.VBs[i]); + + shader *sh = &VS; + for(int s=0; s < 6; s++) + { + ReleaseRef(sh->Shader); + + for(UINT i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + ReleaseRef(sh->ConstantBuffers[i]); + + for(UINT i=0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) + ReleaseRef(sh->Samplers[i]); + + for(UINT i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + ReleaseRef(sh->SRVs[i]); + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + ReleaseRef(sh->UAVs[i]); + + for(UINT i=0; i < D3D11_SHADER_MAX_INTERFACES; i++) + ReleaseRef(sh->Instances[i]); + + sh++; + } + + for(UINT i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + ReleaseRef(SO.Buffers[i]); + + ReleaseRef(RS.State); + + ReleaseRef(OM.BlendState); + ReleaseRef(OM.DepthStencilState); + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + ReleaseRef(OM.RenderTargets[i]); + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + ReleaseRef(OM.UAVs[i]); + + ReleaseRef(OM.DepthView); + + RDCEraseEl(IA); + RDCEraseEl(VS); + RDCEraseEl(HS); + RDCEraseEl(DS); + RDCEraseEl(GS); + RDCEraseEl(SO); + RDCEraseEl(RS); + RDCEraseEl(PS); + RDCEraseEl(OM); + RDCEraseEl(CS); +} + +void D3D11RenderState::MarkDirty(D3D11ResourceManager *manager) const +{ + const shader *sh = &VS; + for(int s=0; s < 6; s++) + { + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(sh->UAVs[i]) + { + sh->UAVs[i]->GetResource(&res); + manager->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + } + + sh++; + } + + for(UINT i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + manager->MarkDirtyResource(GetIDForResource(SO.Buffers[i])); + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(OM.RenderTargets[i]) + { + OM.RenderTargets[i]->GetResource(&res); + manager->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + } + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(OM.UAVs[i]) + { + OM.UAVs[i]->GetResource(&res); + manager->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + } + + { + ID3D11Resource *res = NULL; + if(OM.DepthView) + { + OM.DepthView->GetResource(&res); + manager->MarkDirtyResource(GetIDForResource(res)); + SAFE_RELEASE(res); + } + } +} + +void D3D11RenderState::MarkReferenced(WrappedID3D11DeviceContext *ctx, bool initial) const +{ + ctx->MarkResourceReferenced(GetIDForResource(IA.IndexBuffer), initial ? eFrameRef_Unknown : eFrameRef_Read); + + for(UINT i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + ctx->MarkResourceReferenced(GetIDForResource(IA.VBs[i]), initial ? eFrameRef_Unknown : eFrameRef_Read); + + const shader *sh = &VS; + for(int s=0; s < 6; s++) + { + ctx->MarkResourceReferenced(GetIDForResource(sh->Shader), initial ? eFrameRef_Unknown : eFrameRef_Read); + + for(UINT i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + ctx->MarkResourceReferenced(GetIDForResource(sh->ConstantBuffers[i]), initial ? eFrameRef_Unknown : eFrameRef_Read); + + for(UINT i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(sh->SRVs[i]) + { + sh->SRVs[i]->GetResource(&res); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Read); + SAFE_RELEASE(res); + } + } + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(sh->UAVs[i]) + { + sh->UAVs[i]->GetResource(&res); + ctx->m_MissingTracks.insert(GetIDForResource(res)); + ctx->m_MissingTracks.insert(GetIDForResource(sh->UAVs[i])); + // UAVs we always assume to be partial updates + ctx->MarkResourceReferenced(GetIDForResource(sh->UAVs[i]), initial ? eFrameRef_Unknown : eFrameRef_Read); + ctx->MarkResourceReferenced(GetIDForResource(sh->UAVs[i]), initial ? eFrameRef_Unknown : eFrameRef_Write); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Read); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Write); + SAFE_RELEASE(res); + } + } + + sh++; + } + + for(UINT i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + ctx->MarkResourceReferenced(GetIDForResource(SO.Buffers[i]), initial ? eFrameRef_Unknown : eFrameRef_Write); + + // tracks the min region of the enabled viewports plus scissors, to see if we could potentially + // partially-update a render target (ie. we know for sure that we are only + // writing to a region in one of the viewports). In this case we mark the + // RT/DSV as read-write instead of just write, for initial state tracking. + D3D11_RECT viewportScissorMin = { 0, 0, 0xfffffff, 0xfffffff }; + + D3D11_RASTERIZER_DESC rsdesc; + RDCEraseEl(rsdesc); + rsdesc.ScissorEnable = FALSE; + if(RS.State) + RS.State->GetDesc(&rsdesc); + + for(UINT v=0; v < RS.NumViews; v++) + { + D3D11_RECT scissor = { (LONG)RS.Viewports[v].TopLeftX, + (LONG)RS.Viewports[v].TopLeftY, + (LONG)RS.Viewports[v].Width, + (LONG)RS.Viewports[v].Height }; + + // scissor (if set) is relative to matching viewport) + if(v < RS.NumScissors && rsdesc.ScissorEnable) + { + scissor.left += RS.Scissors[v].left; + scissor.top += RS.Scissors[v].top; + scissor.right = RDCMIN(scissor.right, RS.Scissors[v].right-RS.Scissors[v].left); + scissor.bottom = RDCMIN(scissor.bottom, RS.Scissors[v].bottom-RS.Scissors[v].top); + } + + viewportScissorMin.left = RDCMAX(viewportScissorMin.left, scissor.left); + viewportScissorMin.top = RDCMAX(viewportScissorMin.top, scissor.top); + viewportScissorMin.right = RDCMIN(viewportScissorMin.right, scissor.right); + viewportScissorMin.bottom = RDCMIN(viewportScissorMin.bottom, scissor.bottom); + } + + bool viewportScissorPartial = false; + + if(viewportScissorMin.left > 0 || viewportScissorMin.top > 0) + { + viewportScissorPartial = true; + } + else + { + ID3D11Resource *res = NULL; + if(OM.RenderTargets[0]) + OM.RenderTargets[0]->GetResource(&res); + else if(OM.DepthView) + OM.DepthView->GetResource(&res); + + if(res) + { + D3D11_RESOURCE_DIMENSION dim; + res->GetType(&dim); + + if(dim == D3D11_RESOURCE_DIMENSION_BUFFER) + { + // assume partial + viewportScissorPartial = true; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + D3D11_TEXTURE1D_DESC desc; + ((ID3D11Texture1D *)res)->GetDesc(&desc); + + if(viewportScissorMin.right < (LONG)desc.Width) + viewportScissorPartial = true; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + D3D11_TEXTURE2D_DESC desc; + ((ID3D11Texture2D *)res)->GetDesc(&desc); + + if(viewportScissorMin.right < (LONG)desc.Width || viewportScissorMin.bottom < (LONG)desc.Height) + viewportScissorPartial = true; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) + { + D3D11_TEXTURE3D_DESC desc; + ((ID3D11Texture3D *)res)->GetDesc(&desc); + + if(viewportScissorMin.right < (LONG)desc.Width || viewportScissorMin.bottom < (LONG)desc.Height) + viewportScissorPartial = true; + } + } + + SAFE_RELEASE(res); + } + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(OM.RenderTargets[i]) + { + OM.RenderTargets[i]->GetResource(&res); + ctx->m_MissingTracks.insert(GetIDForResource(res)); + if(viewportScissorPartial) + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Read); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Write); + SAFE_RELEASE(res); + } + } + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + ID3D11Resource *res = NULL; + if(OM.UAVs[i]) + { + OM.UAVs[i]->GetResource(&res); + ctx->m_MissingTracks.insert(GetIDForResource(OM.UAVs[i])); + ctx->m_MissingTracks.insert(GetIDForResource(res)); + // UAVs we always assume to be partial updates + ctx->MarkResourceReferenced(GetIDForResource(OM.UAVs[i]), initial ? eFrameRef_Unknown : eFrameRef_Read); + ctx->MarkResourceReferenced(GetIDForResource(OM.UAVs[i]), initial ? eFrameRef_Unknown : eFrameRef_Write); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Read); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Write); + SAFE_RELEASE(res); + } + } + + { + ID3D11Resource *res = NULL; + if(OM.DepthView) + { + OM.DepthView->GetResource(&res); + ctx->m_MissingTracks.insert(GetIDForResource(res)); + if(viewportScissorPartial) + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Read); + ctx->MarkResourceReferenced(GetIDForResource(res), initial ? eFrameRef_Unknown : eFrameRef_Write); + SAFE_RELEASE(res); + } + } +} + +void D3D11RenderState::AddRefs() +{ + TakeRef(IA.IndexBuffer); + TakeRef(IA.Layout); + + for(UINT i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + TakeRef(IA.VBs[i]); + + shader *sh = &VS; + for(int s=0; s < 6; s++) + { + TakeRef(sh->Shader); + + for(UINT i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + TakeRef(sh->ConstantBuffers[i]); + + for(UINT i=0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) + TakeRef(sh->Samplers[i]); + + for(UINT i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + TakeRef(sh->SRVs[i]); + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + TakeRef(sh->UAVs[i]); + + for(UINT i=0; i < D3D11_SHADER_MAX_INTERFACES; i++) + TakeRef(sh->Instances[i]); + + sh++; + } + + for(UINT i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + TakeRef(SO.Buffers[i]); + + TakeRef(RS.State); + + TakeRef(OM.BlendState); + TakeRef(OM.DepthStencilState); + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + TakeRef(OM.RenderTargets[i]); + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + TakeRef(OM.UAVs[i]); + + TakeRef(OM.DepthView); +} + +void D3D11RenderState::Serialise(LogState m_State, WrappedID3D11Device *device) +{ + SERIALISE_ELEMENT(ResourceId, IALayout, GetIDForResource(IA.Layout)); + if(m_State < WRITING) + IA.Layout = (ID3D11InputLayout *)device->GetResourceManager()->GetLiveResource(IALayout); + + m_pSerialiser->Serialise("IA.Topo", IA.Topo); + + SERIALISE_ELEMENT(ResourceId, IAIndexBuffer, GetIDForResource(IA.IndexBuffer)); + if(m_State < WRITING) + IA.IndexBuffer = (ID3D11Buffer *)device->GetResourceManager()->GetLiveResource(IAIndexBuffer); + + for(int i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + { + ResourceId VB; + if(m_State >= WRITING) VB = GetIDForResource(IA.VBs[i]); + m_pSerialiser->Serialise("IA.VBs", VB); + if(m_State < WRITING) IA.VBs[i] = (ID3D11Buffer *)device->GetResourceManager()->GetLiveResource(VB); + } + + m_pSerialiser->Serialise("IA.Strides", IA.Strides); + m_pSerialiser->Serialise("IA.Offsets", IA.Offsets); + m_pSerialiser->Serialise("IA.indexFormat", IA.IndexFormat); + m_pSerialiser->Serialise("IA.indexOffset", IA.IndexOffset); + + const char *names[] = { "VS", "DS", "HS", "GS", "CS", "PS" }; + shader *sh = &VS; + for(int s=0; s < 6; s++) + { + SERIALISE_ELEMENT(ResourceId, Shader, GetIDForResource(sh->Shader)); + if(m_State < WRITING) + sh->Shader = (ID3D11DeviceChild *)device->GetResourceManager()->GetLiveResource(Shader); + + for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + { + ResourceId id; + if(m_State >= WRITING) id = GetIDForResource(sh->ConstantBuffers[i]); + m_pSerialiser->Serialise((string(names[s]) + ".ConstantBuffers").c_str(), id); + if(m_State < WRITING) sh->ConstantBuffers[i] = (ID3D11Buffer *)device->GetResourceManager()->GetLiveResource(id); + + m_pSerialiser->Serialise((string(names[s]) + ".CBOffsets").c_str(), sh->CBOffsets[i]); + m_pSerialiser->Serialise((string(names[s]) + ".CBCounts").c_str(), sh->CBCounts[i]); + } + + for(int i=0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) + { + ResourceId id; + if(m_State >= WRITING) id = GetIDForResource(sh->Samplers[i]); + m_pSerialiser->Serialise((string(names[s]) + ".Samplers").c_str(), id); + if(m_State < WRITING) sh->Samplers[i] = (ID3D11SamplerState *)device->GetResourceManager()->GetLiveResource(id); + } + + for(int i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + { + ResourceId id; + if(m_State >= WRITING) id = GetIDForResource(sh->SRVs[i]); + m_pSerialiser->Serialise((string(names[s]) + ".SRVs").c_str(), id); + if(m_State < WRITING) sh->SRVs[i] = (ID3D11ShaderResourceView *)device->GetResourceManager()->GetLiveResource(id); + } + + for(int i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + ResourceId id; + if(m_State >= WRITING) id = GetIDForResource(sh->UAVs[i]); + m_pSerialiser->Serialise((string(names[s]) + ".UAVs").c_str(), id); + if(m_State < WRITING) sh->UAVs[i] = (ID3D11UnorderedAccessView *)device->GetResourceManager()->GetLiveResource(id); + } + + for(int i=0; i < D3D11_SHADER_MAX_INTERFACES; i++) + { + ResourceId id; + if(m_State >= WRITING) id = GetIDForResource(sh->Instances[i]); + m_pSerialiser->Serialise((string(names[s]) + ".Instances").c_str(), id); + if(m_State < WRITING) sh->Instances[i] = (ID3D11ClassInstance *)device->GetResourceManager()->GetLiveResource(id); + } + + sh++; + } + + for(int i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + { + ResourceId id; + if(m_State >= WRITING) id = GetIDForResource(SO.Buffers[i]); + m_pSerialiser->Serialise("SO.Buffers", id); + if(m_State < WRITING) SO.Buffers[i] = (ID3D11Buffer *)device->GetResourceManager()->GetLiveResource(id); + + m_pSerialiser->Serialise("SO.Offsets", SO.Offsets[i]); + } + + SERIALISE_ELEMENT(ResourceId, RSState, GetIDForResource(RS.State)); + if(m_State < WRITING) + RS.State = (ID3D11RasterizerState *)device->GetResourceManager()->GetLiveResource(RSState); + + m_pSerialiser->Serialise("RS.NumViews", RS.NumViews); + m_pSerialiser->Serialise("RS.NumScissors", RS.NumScissors); + m_pSerialiser->Serialise("RS.Viewports", RS.Viewports); + m_pSerialiser->Serialise("RS.Scissors", RS.Scissors); + + SERIALISE_ELEMENT(ResourceId, OMDepthStencilState, GetIDForResource(OM.DepthStencilState)); + if(m_State < WRITING) + OM.DepthStencilState = (ID3D11DepthStencilState *)device->GetResourceManager()->GetLiveResource(OMDepthStencilState); + + m_pSerialiser->Serialise("OM.StencRef", OM.StencRef); + + SERIALISE_ELEMENT(ResourceId, OMBlendState, GetIDForResource(OM.BlendState)); + if(m_State < WRITING) + OM.BlendState = (ID3D11BlendState *)device->GetResourceManager()->GetLiveResource(OMBlendState); + + m_pSerialiser->Serialise<4>("OM.BlendFactor", OM.BlendFactor); + m_pSerialiser->Serialise("OM.SampleMask", OM.SampleMask); + + SERIALISE_ELEMENT(ResourceId, OMDepthView, GetIDForResource(OM.DepthView)); + if(m_State < WRITING) + OM.DepthView = (ID3D11DepthStencilView *)device->GetResourceManager()->GetLiveResource(OMDepthView); + + m_pSerialiser->Serialise("OM.UAVStartSlot", OM.UAVStartSlot); + + for(int i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + ResourceId UAV; + if(m_State >= WRITING) UAV = GetIDForResource(OM.UAVs[i]); + m_pSerialiser->Serialise("OM.UAVs", UAV); + if(m_State < WRITING) OM.UAVs[i] = (ID3D11UnorderedAccessView *)device->GetResourceManager()->GetLiveResource(UAV); + } + + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + ResourceId RTV; + if(m_State >= WRITING) RTV = GetIDForResource(OM.RenderTargets[i]); + m_pSerialiser->Serialise("OM.RenderTargets", RTV); + if(m_State < WRITING) OM.RenderTargets[i] = (ID3D11RenderTargetView *)device->GetResourceManager()->GetLiveResource(RTV); + } + + if(m_State < WRITING) + AddRefs(); +} + +D3D11RenderState::D3D11RenderState(WrappedID3D11DeviceContext *context) +{ + RDCEraseMem(this, sizeof(D3D11RenderState)); + m_pSerialiser = context->GetSerialiser(); + + // IA + context->IAGetInputLayout(&IA.Layout); + context->IAGetPrimitiveTopology(&IA.Topo); + context->IAGetVertexBuffers(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, IA.VBs, (UINT*)IA.Strides, (UINT*)IA.Offsets); + context->IAGetIndexBuffer(&IA.IndexBuffer, &IA.IndexFormat, &IA.IndexOffset); + + // VS + context->VSGetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, VS.ConstantBuffers, VS.CBOffsets, VS.CBCounts); + context->VSGetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, VS.SRVs); + context->VSGetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, VS.Samplers); + context->VSGetShader((ID3D11VertexShader **)&VS.Shader, VS.Instances, &VS.NumInstances); + + // DS + context->DSGetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, DS.ConstantBuffers, DS.CBOffsets, DS.CBCounts); + context->DSGetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, DS.SRVs); + context->DSGetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, DS.Samplers); + context->DSGetShader((ID3D11DomainShader **)&DS.Shader, DS.Instances, &DS.NumInstances); + + // HS + context->HSGetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, HS.ConstantBuffers, HS.CBOffsets, HS.CBCounts); + context->HSGetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, HS.SRVs); + context->HSGetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, HS.Samplers); + context->HSGetShader((ID3D11HullShader **)&HS.Shader, HS.Instances, &HS.NumInstances); + + // GS + context->GSGetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, GS.ConstantBuffers, GS.CBOffsets, GS.CBCounts); + context->GSGetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, GS.SRVs); + context->GSGetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, GS.Samplers); + context->GSGetShader((ID3D11GeometryShader **)&GS.Shader, GS.Instances, &GS.NumInstances); + + context->SOGetTargets(D3D11_SO_BUFFER_SLOT_COUNT, SO.Buffers); + + // RS + context->RSGetState(&RS.State); + RDCEraseEl(RS.Viewports); + RS.NumViews = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + context->RSGetViewports(&RS.NumViews, RS.Viewports); + RDCEraseEl(RS.Scissors); + RS.NumScissors = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + context->RSGetScissorRects(&RS.NumScissors, RS.Scissors); + + // CS + context->CSGetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, CS.ConstantBuffers, CS.CBOffsets, CS.CBCounts); + context->CSGetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, CS.SRVs); + context->CSGetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, CS.UAVs); + context->CSGetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, CS.Samplers); + context->CSGetShader((ID3D11ComputeShader **)&CS.Shader, CS.Instances, &CS.NumInstances); + + // PS + context->PSGetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, PS.ConstantBuffers, PS.CBOffsets, PS.CBCounts); + context->PSGetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, PS.SRVs); + context->PSGetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, PS.Samplers); + context->PSGetShader((ID3D11PixelShader **)&PS.Shader, PS.Instances, &PS.NumInstances); + + // OM + context->OMGetBlendState(&OM.BlendState, OM.BlendFactor, &OM.SampleMask); + context->OMGetDepthStencilState(&OM.DepthStencilState, &OM.StencRef); + + ID3D11RenderTargetView* tmpViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + context->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, tmpViews, NULL); + + OM.UAVStartSlot = 0; + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if(tmpViews[i] != NULL) + { + OM.UAVStartSlot = i+1; + SAFE_RELEASE(tmpViews[i]); + } + } + + context->OMGetRenderTargetsAndUnorderedAccessViews(OM.UAVStartSlot, OM.RenderTargets, + &OM.DepthView, + OM.UAVStartSlot, D3D11_PS_CS_UAV_REGISTER_COUNT-OM.UAVStartSlot, OM.UAVs); +} + +void D3D11RenderState::Clear() +{ + ReleaseRefs(); + OM.BlendFactor[0] = OM.BlendFactor[1] = OM.BlendFactor[2] = OM.BlendFactor[3] = 1.0f; + OM.SampleMask = 0xffffffff; +} + +void D3D11RenderState::ApplyState(WrappedID3D11DeviceContext *context) +{ + context->ClearState(); + + // IA + context->IASetInputLayout(IA.Layout); + context->IASetPrimitiveTopology(IA.Topo); + context->IASetIndexBuffer(IA.IndexBuffer, IA.IndexFormat, IA.IndexOffset); + context->IASetVertexBuffers(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, IA.VBs, IA.Strides, IA.Offsets); + + // VS + context->VSSetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, VS.ConstantBuffers, VS.CBOffsets, VS.CBCounts); + context->VSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, VS.SRVs); + context->VSSetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, VS.Samplers); + context->VSSetShader((ID3D11VertexShader *)VS.Shader, VS.Instances, VS.NumInstances); + + // DS + context->DSSetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, DS.ConstantBuffers, DS.CBOffsets, DS.CBCounts); + context->DSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, DS.SRVs); + context->DSSetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, DS.Samplers); + context->DSSetShader((ID3D11DomainShader *)DS.Shader, DS.Instances, DS.NumInstances); + + // HS + context->HSSetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, HS.ConstantBuffers, HS.CBOffsets, HS.CBCounts); + context->HSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, HS.SRVs); + context->HSSetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, HS.Samplers); + context->HSSetShader((ID3D11HullShader *)HS.Shader, HS.Instances, HS.NumInstances); + + // GS + context->GSSetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, GS.ConstantBuffers, GS.CBOffsets, GS.CBCounts); + context->GSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, GS.SRVs); + context->GSSetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, GS.Samplers); + context->GSSetShader((ID3D11GeometryShader *)GS.Shader, GS.Instances, GS.NumInstances); + + context->SOSetTargets(D3D11_SO_BUFFER_SLOT_COUNT, SO.Buffers, SO.Offsets); + + // RS + context->RSSetState(RS.State); + context->RSSetViewports(RS.NumViews, RS.Viewports); + context->RSSetScissorRects(RS.NumScissors, RS.Scissors); + + UINT UAV_keepcounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 }; + + // CS + context->CSSetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, CS.ConstantBuffers, CS.CBOffsets, CS.CBCounts); + context->CSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, CS.SRVs); + context->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, CS.UAVs, UAV_keepcounts); + context->CSSetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, CS.Samplers); + context->CSSetShader((ID3D11ComputeShader *)CS.Shader, CS.Instances, CS.NumInstances); + + // PS + context->PSSetConstantBuffers1(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, PS.ConstantBuffers, PS.CBOffsets, PS.CBCounts); + context->PSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, PS.SRVs); + context->PSSetSamplers(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, PS.Samplers); + context->PSSetShader((ID3D11PixelShader *)PS.Shader, PS.Instances, PS.NumInstances); + + // OM + context->OMSetBlendState(OM.BlendState, OM.BlendFactor, OM.SampleMask); + context->OMSetDepthStencilState(OM.DepthStencilState, OM.StencRef); + + context->OMSetRenderTargetsAndUnorderedAccessViews(OM.UAVStartSlot, OM.RenderTargets, + OM.DepthView, + OM.UAVStartSlot, D3D11_PS_CS_UAV_REGISTER_COUNT-OM.UAVStartSlot, OM.UAVs, UAV_keepcounts); +} + +void D3D11RenderState::TakeRef(IUnknown *p) +{ + if(p) + { + p->AddRef(); + if(m_ImmediatePipeline) + { + if(WrappedID3D11RenderTargetView::IsAlloc(p) || + WrappedID3D11ShaderResourceView::IsAlloc(p) || + WrappedID3D11DepthStencilView::IsAlloc(p) || + WrappedID3D11UnorderedAccessView::IsAlloc(p)) + m_pDevice->InternalRef(); + + m_pDevice->InternalRef(); + } + } +} + +void D3D11RenderState::ReleaseRef(IUnknown *p) +{ + if(p) + { + p->Release(); + if(m_ImmediatePipeline) + { + if(WrappedID3D11RenderTargetView::IsAlloc(p) || + WrappedID3D11ShaderResourceView::IsAlloc(p) || + WrappedID3D11DepthStencilView::IsAlloc(p) || + WrappedID3D11UnorderedAccessView::IsAlloc(p)) + m_pDevice->InternalRelease(); + + m_pDevice->InternalRelease(); + } + } +} + +bool D3D11RenderState::IsBoundIUnknownForWrite(IUnknown *resource, bool readDepthOnly, bool readStencilOnly) +{ + const char *names[] = { "VS", "DS", "HS", "GS", "CS", "PS" }; + shader *sh = &VS; + for(int s=0; s < 6; s++) + { + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + bool found = false; + + ID3D11Resource *res = NULL; + if(sh->UAVs[i]) + { + sh->UAVs[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)sh->UAVs[i]) + { + //RDCDEBUG("Resource was bound on %hs UAV %u", names[s], i); + return true; + } + } + + sh++; + } + + for(UINT i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + { + if(resource == (IUnknown *)SO.Buffers[i]) + { + //RDCDEBUG("Resource was bound on SO buffer %u", i); + return true; + } + } + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + bool found = false; + + ID3D11Resource *res = NULL; + if(OM.RenderTargets[i]) + { + OM.RenderTargets[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)OM.RenderTargets[i]) + { + //RDCDEBUG("Resource was bound on RTV %u", i); + return true; + } + } + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + bool found = false; + + ID3D11Resource *res = NULL; + if(OM.UAVs[i]) + { + OM.UAVs[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)OM.UAVs[i]) + { + //RDCDEBUG("Resource was bound on OM UAV %d", i); + return true; + } + } + + { + bool found = false; + + UINT depthFlags = 0; + + ID3D11Resource *res = NULL; + if(OM.DepthView) + { + OM.DepthView->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + + D3D11_DEPTH_STENCIL_VIEW_DESC d; + OM.DepthView->GetDesc(&d); + + depthFlags = d.Flags; + } + + if(found || resource == (IUnknown *)OM.DepthView) + { + //RDCDEBUG("Resource was bound on OM DSV"); + + if(depthFlags == (D3D11_DSV_READ_ONLY_DEPTH|D3D11_DSV_READ_ONLY_STENCIL)) + { + //RDCDEBUG("but it's a readonly DSV, so that's fine"); + } + else if(depthFlags == D3D11_DSV_READ_ONLY_DEPTH && readDepthOnly) + { + //RDCDEBUG("but it's a depth readonly DSV and we're only reading depth, so that's fine"); + } + else if(depthFlags == D3D11_DSV_READ_ONLY_STENCIL && readStencilOnly) + { + //RDCDEBUG("but it's a depth readonly DSV and we're only reading depth, so that's fine"); + } + else + { + return true; + } + } + } + + return false; +} + +void D3D11RenderState::UnbindIUnknownForWrite(IUnknown *resource) +{ + shader *sh = &VS; + for(int s=0; s < 6; s++) + { + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + bool found = false; + + ID3D11Resource *res = NULL; + if(sh->UAVs[i]) + { + sh->UAVs[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)sh->UAVs[i]) + { + ReleaseRef(sh->UAVs[i]); + sh->UAVs[i] = NULL; + } + } + + sh++; + } + + for(UINT i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + { + if(resource == (IUnknown *)SO.Buffers[i]) + { + ReleaseRef(SO.Buffers[i]); + SO.Buffers[i] = NULL; + } + } + + for(UINT i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + bool found = false; + + ID3D11Resource *res = NULL; + if(OM.RenderTargets[i]) + { + OM.RenderTargets[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)OM.RenderTargets[i]) + { + ReleaseRef(OM.RenderTargets[i]); + OM.RenderTargets[i] = NULL; + } + } + + for(UINT i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++) + { + bool found = false; + + ID3D11Resource *res = NULL; + if(OM.UAVs[i]) + { + OM.UAVs[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)OM.UAVs[i]) + { + ReleaseRef(OM.UAVs[i]); + OM.UAVs[i] = NULL; + } + } + + { + bool found = false; + + UINT depthFlags = 0; + + ID3D11Resource *res = NULL; + if(OM.DepthView) + { + OM.DepthView->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + SAFE_RELEASE(res); + + D3D11_DEPTH_STENCIL_VIEW_DESC d; + OM.DepthView->GetDesc(&d); + + depthFlags = d.Flags; + } + + if(found || resource == (IUnknown *)OM.DepthView) + { + ReleaseRef(OM.DepthView); + OM.DepthView = NULL; + } + } +} + +void D3D11RenderState::UnbindIUnknownForRead(IUnknown *resource, bool allowDepthOnly, bool allowStencilOnly) +{ + for(int i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + { + if(resource == (IUnknown *)IA.VBs[i]) + { + //RDCDEBUG("Resource was bound on IA VB %u", i); + ReleaseRef(IA.VBs[i]); + IA.VBs[i] = NULL; + } + } + + if(resource == (IUnknown *)IA.IndexBuffer) + { + //RDCDEBUG("Resource was bound on IA IB"); + ReleaseRef(IA.IndexBuffer); + IA.IndexBuffer = NULL; + } + + const char *names[] = { "VS", "DS", "HS", "GS", "PS", "CS" }; + shader *sh = &VS; + for(int s=0; s < 6; s++) + { + for(UINT i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) + { + if(resource == (IUnknown *)sh->ConstantBuffers[i]) + { + //RDCDEBUG("Resource was bound on %hs CB %u", names[s], i); + ReleaseRef(sh->ConstantBuffers[i]); + sh->ConstantBuffers[i] = NULL; + } + } + + for(UINT i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) + { + bool found = false; + + bool readDepthOnly = false; + bool readStencilOnly = false; + + D3D11_RESOURCE_DIMENSION dim; + DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN; + + ID3D11Resource *res = NULL; + if(sh->SRVs[i]) + { + sh->SRVs[i]->GetResource(&res); + if(resource == (IUnknown *)res) + found = true; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + sh->SRVs[i]->GetDesc(&srvDesc); + + fmt = srvDesc.Format; + + res->GetType(&dim); + + if(fmt == DXGI_FORMAT_UNKNOWN) + { + if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + D3D11_TEXTURE1D_DESC d; + ((ID3D11Texture1D *)res)->GetDesc(&d); + + fmt = d.Format; + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + D3D11_TEXTURE2D_DESC d; + ((ID3D11Texture2D *)res)->GetDesc(&d); + + fmt = d.Format; + } + } + + if(fmt == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT || + fmt == DXGI_FORMAT_X24_TYPELESS_G8_UINT) + { + readStencilOnly = true; + } + if(fmt == DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS || + fmt == DXGI_FORMAT_R24_UNORM_X8_TYPELESS) + { + readDepthOnly = true; + } + + SAFE_RELEASE(res); + } + + if(found || resource == (IUnknown *)sh->SRVs[i]) + { + //RDCDEBUG("Resource was bound on %hs SRV %u", names[s], i); + + if(allowDepthOnly && readDepthOnly) + { + //RDCDEBUG("but it's a depth readonly DSV and we're only reading depth, so that's fine"); + } + else if(allowStencilOnly && readStencilOnly) + { + //RDCDEBUG("but it's a depth readonly DSV and we're only reading depth, so that's fine"); + } + else + { + //RDCDEBUG("Unbinding."); + ReleaseRef(sh->SRVs[i]); + sh->SRVs[i] = NULL; + } + } + } + + sh++; + } +} + +bool D3D11RenderState::ValidOutputMerger(ID3D11RenderTargetView **RTs, ID3D11DepthStencilView *depth) +{ + D3D11_RENDER_TARGET_VIEW_DESC RTDescs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + D3D11_DEPTH_STENCIL_VIEW_DESC DepthDesc; + + RDCEraseEl(RTDescs); + RDCEraseEl(DepthDesc); + + ID3D11Resource *Resources[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; + ID3D11Resource *DepthResource = NULL; + + D3D11_RESOURCE_DIMENSION renderdim[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {D3D11_RESOURCE_DIMENSION_UNKNOWN}; + D3D11_RESOURCE_DIMENSION depthdim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + + for(int i=0; RTs && i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if(RTs[i]) + { + RTs[i]->GetDesc(&RTDescs[i]); + RTs[i]->GetResource(&Resources[i]); + Resources[i]->GetType(&renderdim[i]); + } + } + + if(depth) + { + depth->GetDesc(&DepthDesc); + depth->GetResource(&DepthResource); + DepthResource->GetType(&depthdim); + } + + bool valid = true; + + ////////////////////////////////////////////////////////////////////////// + // Resource dimensions of all views must be the same + + D3D11_RESOURCE_DIMENSION dim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if(renderdim[i] == D3D11_RESOURCE_DIMENSION_UNKNOWN) continue; + if(dim == D3D11_RESOURCE_DIMENSION_UNKNOWN) dim = renderdim[i]; + + if(renderdim[i] != dim) + { + valid = false; + break; + } + } + + if(depthdim != D3D11_RESOURCE_DIMENSION_UNKNOWN && + dim != D3D11_RESOURCE_DIMENSION_UNKNOWN && + depthdim != dim) + { + valid = false; + } + + if(!valid) + { + //RDCDEBUG("Resource dimensions don't match between render targets and/or depth stencil"); + } + else + { + // pretend all resources are 3D descs just to make the code simpler + // * put arraysize for 1D/2D into the depth for 3D + // * use sampledesc from 2d as it will be identical for 1D/3D + + D3D11_TEXTURE3D_DESC desc = {0}; + D3D11_TEXTURE2D_DESC desc2 = {0}; + + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if(Resources[i] == NULL) continue; + + D3D11_TEXTURE1D_DESC d1 = {0}; + D3D11_TEXTURE2D_DESC d2 = {0}; + D3D11_TEXTURE3D_DESC d3 = {0}; + + if(dim == D3D11_RESOURCE_DIMENSION_BUFFER) + { + } + if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + ((ID3D11Texture1D *)Resources[i])->GetDesc(&d1); + d3.Width = RDCMAX(1U, d1.Width >> RTDescs[i].Texture1D.MipSlice); + + if(RTDescs[i].ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1D) + d3.Depth = 1; + else if(RTDescs[i].ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1DARRAY) + d3.Depth = RDCMIN(d1.ArraySize, RTDescs[i].Texture1DArray.ArraySize); + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + ((ID3D11Texture2D *)Resources[i])->GetDesc(&d2); + + if(RTDescs[i].ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2D) + { + d3.Width = RDCMAX(1U, d2.Width >> RTDescs[i].Texture2D.MipSlice); + d3.Height = RDCMAX(1U, d2.Height >> RTDescs[i].Texture2D.MipSlice); + d3.Depth = 1; + } + else if(RTDescs[i].ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DMS) + { + d3.Width = d2.Width; + d3.Height = d2.Height; + d3.Depth = 1; + } + else if(RTDescs[i].ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DARRAY) + { + d3.Width = RDCMAX(1U, d2.Width >> RTDescs[i].Texture2DArray.MipSlice); + d3.Height = RDCMAX(1U, d2.Height >> RTDescs[i].Texture2DArray.MipSlice); + d3.Depth = RDCMIN(d2.ArraySize, RTDescs[i].Texture2DArray.ArraySize); + } + else if(RTDescs[i].ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY) + { + d3.Width = d2.Width; + d3.Height = d2.Height; + d3.Depth = RDCMIN(d2.ArraySize, RTDescs[i].Texture2DMSArray.ArraySize); + } + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) + { + ((ID3D11Texture3D *)Resources[i])->GetDesc(&d3); + d3.Width = RDCMAX(1U, d3.Width >> RTDescs[i].Texture3D.MipSlice); + d3.Height = RDCMAX(1U, d3.Height >> RTDescs[i].Texture3D.MipSlice); + d3.Depth = RDCMAX(1U, d3.Depth >> RTDescs[i].Texture3D.MipSlice); + d3.Depth = RDCMIN(d3.Depth, RTDescs[i].Texture3D.WSize); + } + + if(desc.Width == 0) + { + desc = d3; + desc2 = d2; + continue; + } + + if(desc.Width != d3.Width || + desc.Height != d3.Height || + desc.Depth != d3.Depth || + desc2.SampleDesc.Count != d2.SampleDesc.Count || + desc2.SampleDesc.Quality != d2.SampleDesc.Quality) + { + valid = false; + break; + } + } + + if(DepthResource && valid) + { + D3D11_TEXTURE1D_DESC d1 = {0}; + D3D11_TEXTURE2D_DESC d2 = {0}; + D3D11_TEXTURE3D_DESC d3 = {0}; + + if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + ((ID3D11Texture1D *)DepthResource)->GetDesc(&d1); + d3.Width = RDCMAX(1U, d1.Width >> DepthDesc.Texture1D.MipSlice); + + if(DepthDesc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1D) + d3.Depth = 1; + else if(DepthDesc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1DARRAY) + d3.Depth = RDCMIN(d1.ArraySize, DepthDesc.Texture1DArray.ArraySize); + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + ((ID3D11Texture2D *)DepthResource)->GetDesc(&d2); + d3.Width = RDCMAX(1U, d2.Width >> DepthDesc.Texture2D.MipSlice); + d3.Height = RDCMAX(1U, d2.Height >> DepthDesc.Texture2D.MipSlice); + + if(DepthDesc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE2D) + d3.Depth = 1; + else if(DepthDesc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE2DARRAY) + d3.Depth = RDCMIN(d2.ArraySize, DepthDesc.Texture2DArray.ArraySize); + else if(DepthDesc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY) + d3.Depth = RDCMIN(d2.ArraySize, DepthDesc.Texture2DMSArray.ArraySize); + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D || + dim == D3D11_RESOURCE_DIMENSION_BUFFER) + { + valid = false; + } + + if(desc.Width != 0 && valid) + { + if(desc.Width != d3.Width || + desc.Height != d3.Height || + desc.Depth != d3.Depth || + desc2.SampleDesc.Count != d2.SampleDesc.Count || + desc2.SampleDesc.Quality != d2.SampleDesc.Quality) + { + valid = false; + } + } + } + + if(!valid) + { + //RDCDEBUG("Different effective dimensions between output views"); + valid = true; + } + } + + for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + SAFE_RELEASE(Resources[i]); + + SAFE_RELEASE(DepthResource); + + return valid; +} + +bool D3D11RenderState::inputassembler::Used_VB(WrappedID3D11Device *device, uint32_t slot) const +{ + if(Layout == NULL) + return false; + + const vector &vec = device->GetLayoutDesc(Layout); + + for(size_t i=0; i < vec.size(); i++) + if(vec[i].InputSlot == slot) + return true; + + return false; +} + +bool D3D11RenderState::shader::Used_CB(uint32_t slot) const +{ + if(ConstantBuffers[slot] == NULL) + return false; + + WrappedShader *shad = (WrappedShader*)(WrappedID3D11Shader *)Shader; + + if(shad == NULL) + return false; + + DXBC::DXBCFile *dxbc = shad->GetDXBC(); + + // have to assume it's used if there's no DXBC + if(dxbc == NULL) + return true; + + if(slot >= dxbc->m_CBuffers.size()) + return false; + + if(dxbc->m_CBuffers[slot].variables.empty()) + return false; + + return true; +} + +bool D3D11RenderState::shader::Used_SRV(uint32_t slot) const +{ + if(SRVs[slot] == NULL) + return false; + + WrappedShader *shad = (WrappedShader*)(WrappedID3D11Shader *)Shader; + + if(shad == NULL) + return false; + + DXBC::DXBCFile *dxbc = shad->GetDXBC(); + + // have to assume it's used if there's no DXBC + if(dxbc == NULL) + return true; + + for(size_t i=0; i < dxbc->m_Resources.size(); i++) + { + if(dxbc->m_Resources[i].bindPoint == slot && + (dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_TEXTURE || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_STRUCTURED || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_TBUFFER || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS) + ) + { + return true; + } + } + + return false; +} + +bool D3D11RenderState::shader::Used_UAV(uint32_t slot) const +{ + WrappedShader *shad = (WrappedShader*)(WrappedID3D11Shader *)Shader; + + if(shad == NULL) + return false; + + DXBC::DXBCFile *dxbc = shad->GetDXBC(); + + // have to assume it's used if there's no DXBC + if(dxbc == NULL) + return true; + + for(size_t i=0; i < dxbc->m_Resources.size(); i++) + { + if(dxbc->m_Resources[i].bindPoint == slot && + (dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER || + dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED) + ) + { + return true; + } + } + + return false; +} + +D3D11RenderStateTracker::D3D11RenderStateTracker(WrappedID3D11DeviceContext *ctx) + : m_RS(*ctx->GetCurrentPipelineState()) +{ + m_pContext = ctx; +} + +D3D11RenderStateTracker::~D3D11RenderStateTracker() +{ + m_RS.ApplyState(m_pContext); +} diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.h b/renderdoc/driver/d3d11/d3d11_renderstate.h new file mode 100644 index 0000000000..f076c5ef13 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_renderstate.h @@ -0,0 +1,445 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +#include "core/core.h" +#include "driver/d3d11/d3d11_manager.h" +#include "common/common.h" + +class Serialiser; +class WrappedID3D11Device; +class WrappedID3D11DeviceContext; +class D3D11ResourceManager; + +struct D3D11RenderState +{ + D3D11RenderState(Serialiser *ser); + D3D11RenderState(WrappedID3D11DeviceContext *context); + D3D11RenderState(const D3D11RenderState &other); + ~D3D11RenderState(); + + D3D11RenderState &operator =(const D3D11RenderState &other); + + void ApplyState(WrappedID3D11DeviceContext *context); + void Clear(); + + /////////////////////////////////////////////////////////////////////////////// + // pipeline-auto NULL. When binding a resource for write, it will be + // unbound anywhere that it is bound for read. + // + // if binding a resource for READ, and it's still bound for write, the + // bind will be disallowed and NULL will be bound instead + // + // need to be aware of depth-stencil as a special case, DSV can be flagged read-only + // of depth, stencil or both to allow read binds of that component at the same time. + + bool IsBoundIUnknownForWrite(IUnknown *resource, bool readDepthOnly, bool readStencilOnly); + void UnbindIUnknownForRead(IUnknown *resource, bool allowDepthOnly, bool allowStencilOnly); + + // just for utility, not used below + void UnbindIUnknownForWrite(IUnknown *resource); + + template + bool IsBoundForWrite(T *resource) + { + if(resource == NULL) return false; + + return IsBoundIUnknownForWrite((IUnknown *)resource, false, false); + } + + template<> + bool IsBoundForWrite(ID3D11Resource *resource) + { + if(resource == NULL) return false; + + bool readDepthOnly = false; + bool readStencilOnly = false; + + D3D11_RESOURCE_DIMENSION dim; + resource->GetType(&dim); + + if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + D3D11_TEXTURE1D_DESC d; + ((ID3D11Texture1D *)resource)->GetDesc(&d); + + if(d.Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT || + d.Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT) + { + readStencilOnly = true; + } + if(d.Format == DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS || + d.Format == DXGI_FORMAT_R24_UNORM_X8_TYPELESS) + { + readDepthOnly = true; + } + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + D3D11_TEXTURE2D_DESC d; + ((ID3D11Texture2D *)resource)->GetDesc(&d); + + if(d.Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT || + d.Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT) + { + readStencilOnly = true; + } + if(d.Format == DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS || + d.Format == DXGI_FORMAT_R24_UNORM_X8_TYPELESS) + { + readDepthOnly = true; + } + } + + return IsBoundIUnknownForWrite((IUnknown *)resource, readDepthOnly, readStencilOnly); + } + + template<> + bool IsBoundForWrite(ID3D11ShaderResourceView *resource) + { + if(resource == NULL) return false; + + ID3D11Resource *res = NULL; + resource->GetResource(&res); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvd; + resource->GetDesc(&srvd); + + bool readDepthOnly = false; + bool readStencilOnly = false; + + D3D11_RESOURCE_DIMENSION dim; + res->GetType(&dim); + + if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) + { + D3D11_TEXTURE1D_DESC d; + ((ID3D11Texture1D *)res)->GetDesc(&d); + + if(d.Format == DXGI_FORMAT_R24G8_TYPELESS || + d.Format == DXGI_FORMAT_R32G8X24_TYPELESS) + { + d.Format = srvd.Format; + } + + if(d.Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT || + d.Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT) + { + readStencilOnly = true; + } + if(d.Format == DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS || + d.Format == DXGI_FORMAT_R24_UNORM_X8_TYPELESS) + { + readDepthOnly = true; + } + } + else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + D3D11_TEXTURE2D_DESC d; + ((ID3D11Texture2D *)res)->GetDesc(&d); + + if(d.Format == DXGI_FORMAT_R24G8_TYPELESS || + d.Format == DXGI_FORMAT_R32G8X24_TYPELESS) + { + d.Format = srvd.Format; + } + + if(d.Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT || + d.Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT) + { + readStencilOnly = true; + } + if(d.Format == DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS || + d.Format == DXGI_FORMAT_R24_UNORM_X8_TYPELESS) + { + readDepthOnly = true; + } + } + + bool ret = IsBoundIUnknownForWrite((IUnknown *)res, readDepthOnly, readStencilOnly); + + SAFE_RELEASE(res); + + return ret; + } + + template + void UnbindForRead(T *resource) + { + if(resource == NULL) return; + UnbindIUnknownForRead((IUnknown *)resource, false, false); + } + + template<> + void UnbindForRead(ID3D11RenderTargetView *resource) + { + if(resource == NULL) return; + + ID3D11Resource *res = NULL; + resource->GetResource(&res); + + UnbindIUnknownForRead((IUnknown *)res, false, false); + + SAFE_RELEASE(res); + } + + template<> + void UnbindForRead(ID3D11DepthStencilView *resource) + { + if(resource == NULL) return; + + ID3D11Resource *res = NULL; + resource->GetResource(&res); + + D3D11_DEPTH_STENCIL_VIEW_DESC d; + resource->GetDesc(&d); + + if(d.Flags == (D3D11_DSV_READ_ONLY_DEPTH|D3D11_DSV_READ_ONLY_STENCIL)) + { + // don't need to. + } + else if(d.Flags == D3D11_DSV_READ_ONLY_DEPTH) + { + UnbindIUnknownForRead((IUnknown *)res, true, false); + } + else if(d.Flags == D3D11_DSV_READ_ONLY_STENCIL) + { + UnbindIUnknownForRead((IUnknown *)res, false, true); + } + else + { + UnbindIUnknownForRead((IUnknown *)res, false, false); + } + + SAFE_RELEASE(res); + } + + template<> + void UnbindForRead(ID3D11UnorderedAccessView *resource) + { + if(resource == NULL) return; + + ID3D11Resource *res = NULL; + resource->GetResource(&res); + + UnbindIUnknownForRead((IUnknown *)res, false, false); + + SAFE_RELEASE(res); + } + + ///////////////////////////////////////////////////////////////////////// + // Utility functions to swap resources around, removing and adding refs + + void TakeRef(IUnknown *p); + void ReleaseRef(IUnknown *p); + + template + void ChangeRefRead(T **stateArray, T *const*newArray, size_t offset, size_t num) + { + for(size_t i=0; i < num; i++) + { + T *old = stateArray[offset+i]; + ReleaseRef(old); + + if(newArray[i] == NULL) + { + stateArray[offset+i] = newArray[i]; + } + else + { + if(IsBoundForWrite(newArray[i])) + { + //RDCDEBUG("Resource %d was bound for write, forcing to NULL", offset+i); + stateArray[offset+i] = NULL; + } + else + { + stateArray[offset+i] = newArray[i]; + } + } + TakeRef(stateArray[offset+i]); + } + } + + template + void ChangeRefWrite(T **stateArray, T *const*newArray, size_t offset, size_t num) + { + for(size_t i=0; i < num; i++) + { + T *old = stateArray[offset+i]; + ReleaseRef(old); + + if(newArray[i]) UnbindForRead(newArray[i]); + stateArray[offset+i] = newArray[i]; + TakeRef(stateArray[offset+i]); + } + } + + template + void ChangeRefRead(T *&stateItem, T *newItem) + { + ReleaseRef(stateItem); + stateItem = newItem; + + if(newItem == NULL) + { + stateItem = newItem; + } + else + { + if(IsBoundForWrite(newItem)) + { + //RDCDEBUG("Resource was bound for write, forcing to NULL"); + stateItem = NULL; + } + else + { + stateItem = newItem; + } + } + + TakeRef(newItem); + } + + template + void ChangeRefWrite(T *&stateItem, T *newItem) + { + ReleaseRef(stateItem); + stateItem = newItem; + if(newItem) UnbindForRead(newItem); + TakeRef(newItem); + } + + template + void Change(T *stateArray, const T *newArray, size_t offset, size_t num) + { + for(size_t i=0; i < num; i++) + stateArray[i+offset] = newArray[i]; + } + + template + void Change(T &stateItem, const T &newItem) + { + stateItem = newItem; + } + + ///////////////////////////////////////////////////////////////////////// + // Implement any checks that D3D does that will change the state in ways + // that might not be obvious/intended. + + // validate an output merger combination of render targets and depth view + bool ValidOutputMerger(ID3D11RenderTargetView **RTs, ID3D11DepthStencilView *depth); + + struct inputassembler + { + ID3D11InputLayout *Layout; + D3D11_PRIMITIVE_TOPOLOGY Topo; + ID3D11Buffer *VBs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + UINT Strides[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + UINT Offsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + ID3D11Buffer *IndexBuffer; + DXGI_FORMAT IndexFormat; + UINT IndexOffset; + + bool Used_VB(WrappedID3D11Device *device, uint32_t slot) const; + } IA; + + struct shader + { + ID3D11DeviceChild *Shader; + ID3D11Buffer *ConstantBuffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + UINT CBOffsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + UINT CBCounts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + ID3D11UnorderedAccessView *UAVs[D3D11_PS_CS_UAV_REGISTER_COUNT]; + ID3D11SamplerState *Samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + ID3D11ClassInstance *Instances[D3D11_SHADER_MAX_INTERFACES]; + UINT NumInstances; + + bool Used_CB(uint32_t slot) const; + bool Used_SRV(uint32_t slot) const; + bool Used_UAV(uint32_t slot) const; + } VS, HS, DS, GS, PS, CS; + + struct streamout + { + ID3D11Buffer *Buffers[D3D11_SO_BUFFER_SLOT_COUNT]; + UINT Offsets[D3D11_SO_BUFFER_SLOT_COUNT]; + } SO; + + struct rasterizer + { + UINT NumViews, NumScissors; + D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + D3D11_RECT Scissors[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + ID3D11RasterizerState *State; + } RS; + + struct outmerger + { + ID3D11DepthStencilState *DepthStencilState; + UINT StencRef; + + ID3D11BlendState *BlendState; + FLOAT BlendFactor[4]; + UINT SampleMask; + + ID3D11DepthStencilView *DepthView; + + ID3D11RenderTargetView *RenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + + UINT UAVStartSlot; + ID3D11UnorderedAccessView *UAVs[D3D11_PS_CS_UAV_REGISTER_COUNT]; + } OM; + + void SetSerialiser(Serialiser *ser) { m_pSerialiser = ser; } + void Serialise(LogState state, WrappedID3D11Device *device); + ID3D11Resource *GetSerialised(ID3D11Resource *res) const; + + void SetImmediatePipeline(WrappedID3D11Device *device) { m_ImmediatePipeline = true; m_pDevice = device; } + + void MarkReferenced(WrappedID3D11DeviceContext *ctx, bool initial) const; + void MarkDirty(D3D11ResourceManager *manager) const; +private: + void AddRefs(); + void ReleaseRefs(); + + Serialiser *m_pSerialiser; + bool m_ImmediatePipeline; + WrappedID3D11Device *m_pDevice; +}; + +struct D3D11RenderStateTracker +{ + public: + D3D11RenderStateTracker(WrappedID3D11DeviceContext *ctx); + ~D3D11RenderStateTracker(); + private: + D3D11RenderState m_RS; + WrappedID3D11DeviceContext *m_pContext; +}; diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp new file mode 100644 index 0000000000..556d585a2d --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -0,0 +1,1677 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "d3d11_device.h" +#include "d3d11_context.h" +#include "d3d11_resources.h" +#include "d3d11_renderstate.h" +#include "d3d11_replay.h" + +#include + +#include "shaders/dxbc_debug.h" + +#include "common/string_utils.h" + +D3D11Replay::D3D11Replay() +{ + m_pDevice = NULL; + m_Proxy = false; +} + +void D3D11Replay::Shutdown() +{ + m_pDevice->Release(); +} + +FetchTexture D3D11Replay::GetTexture(ResourceId id) +{ + FetchTexture tex; + tex.ID = ResourceId(); + + auto it1D = WrappedID3D11Texture1D::m_TextureList.find(id); + if(it1D != WrappedID3D11Texture1D::m_TextureList.end()) + { + WrappedID3D11Texture1D *d3dtex = (WrappedID3D11Texture1D *)it1D->second.m_Texture; + + string str = GetDebugName(d3dtex); + + D3D11_TEXTURE1D_DESC desc; + d3dtex->GetDesc(&desc); + + tex.ID = m_pDevice->GetResourceManager()->GetOriginalID(it1D->first); + tex.dimension = 1; + tex.width = desc.Width; + tex.height = 1; + tex.depth = 1; + tex.cubemap = false; + tex.format = MakeResourceFormat(desc.Format); + tex.customName = true; + + if(str == "") + { + tex.customName = false; + str = StringFormat::Fmt("Texture1D %llu", tex.ID); + } + + tex.name = widen(str); + + tex.numSubresources = desc.MipLevels; + + tex.creationFlags = 0; + if(desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) + tex.creationFlags |= eTextureCreate_SRV; + if(desc.BindFlags & D3D11_BIND_RENDER_TARGET) + tex.creationFlags |= eTextureCreate_RTV; + if(desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) + tex.creationFlags |= eTextureCreate_DSV; + if(desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) + tex.creationFlags |= eTextureCreate_UAV; + + if(desc.MipLevels == 0) + tex.numSubresources = CalcNumMips(desc.Width, 1, 1); + + tex.mips = tex.numSubresources; + tex.arraysize = desc.ArraySize; + + tex.msQual = 0; tex.msSamp = 1; + + tex.numSubresources *= desc.ArraySize; + + tex.byteSize = 0; + for(uint32_t s=0; s < tex.numSubresources; s++) + tex.byteSize += GetByteSize(d3dtex, s); + + return tex; + } + + auto it2D = WrappedID3D11Texture2D::m_TextureList.find(id); + if(it2D != WrappedID3D11Texture2D::m_TextureList.end()) + { + WrappedID3D11Texture2D *d3dtex = (WrappedID3D11Texture2D *)it2D->second.m_Texture; + + string str = GetDebugName(d3dtex); + + D3D11_TEXTURE2D_DESC desc; + d3dtex->GetDesc(&desc); + + if(d3dtex->m_RealDescriptor) + desc.Format = d3dtex->m_RealDescriptor->Format; + + tex.ID = m_pDevice->GetResourceManager()->GetOriginalID(it2D->first); + tex.dimension = 2; + tex.width = desc.Width; + tex.height = desc.Height; + tex.depth = 1; + tex.format = MakeResourceFormat(desc.Format); + tex.customName = true; + + if(str == "") + { + tex.customName = false; + str = StringFormat::Fmt("Texture2D %llu", tex.ID); + } + + tex.name = widen(str); + + tex.numSubresources = desc.MipLevels; + + tex.creationFlags = 0; + if(desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) + tex.creationFlags |= eTextureCreate_SRV; + if(desc.BindFlags & D3D11_BIND_RENDER_TARGET) + tex.creationFlags |= eTextureCreate_RTV; + if(desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) + tex.creationFlags |= eTextureCreate_DSV; + if(desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) + tex.creationFlags |= eTextureCreate_UAV; + if(d3dtex->m_RealDescriptor) + tex.creationFlags |= eTextureCreate_SwapBuffer; + + tex.cubemap = false; + if(desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) + tex.cubemap = true; + + if(desc.MipLevels == 0) + tex.numSubresources = CalcNumMips(desc.Width, desc.Height, 1); + + tex.mips = tex.numSubresources; + tex.arraysize = desc.ArraySize; + + tex.msQual = desc.SampleDesc.Quality; tex.msSamp = desc.SampleDesc.Count; + + tex.numSubresources *= desc.ArraySize; + + tex.byteSize = 0; + for(uint32_t s=0; s < tex.numSubresources; s++) + tex.byteSize += GetByteSize(d3dtex, s); + + return tex; + } + + auto it3D = WrappedID3D11Texture3D::m_TextureList.find(id); + if(it3D != WrappedID3D11Texture3D::m_TextureList.end()) + { + WrappedID3D11Texture3D *d3dtex = (WrappedID3D11Texture3D *)it3D->second.m_Texture; + + string str = GetDebugName(d3dtex); + + D3D11_TEXTURE3D_DESC desc; + d3dtex->GetDesc(&desc); + + tex.ID = m_pDevice->GetResourceManager()->GetOriginalID(it3D->first); + tex.dimension = 3; + tex.width = desc.Width; + tex.height = desc.Height; + tex.depth = desc.Depth; + tex.cubemap = false; + tex.format = MakeResourceFormat(desc.Format); + tex.customName = true; + + if(str == "") + { + tex.customName = false; + str = StringFormat::Fmt("Texture3D %llu", tex.ID); + } + + tex.name = widen(str); + + tex.numSubresources = desc.MipLevels; + + tex.creationFlags = 0; + if(desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) + tex.creationFlags |= eTextureCreate_SRV; + if(desc.BindFlags & D3D11_BIND_RENDER_TARGET) + tex.creationFlags |= eTextureCreate_RTV; + if(desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) + tex.creationFlags |= eTextureCreate_DSV; + if(desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) + tex.creationFlags |= eTextureCreate_UAV; + + if(desc.MipLevels == 0) + tex.numSubresources = CalcNumMips(desc.Width, desc.Height, desc.Depth); + + tex.msQual = 0; tex.msSamp = 1; + + tex.mips = tex.numSubresources; + tex.arraysize = 1; + + tex.byteSize = 0; + for(uint32_t s=0; s < tex.numSubresources; s++) + tex.byteSize += GetByteSize(d3dtex, s); + + return tex; + } + + return tex; +} + +ShaderReflection *D3D11Replay::GetShader(ResourceId id) +{ + auto it = WrappedShader::m_ShaderList.find(id); + + if(it == WrappedShader::m_ShaderList.end()) + return NULL; + + RDCASSERT(it->second.m_Details); + + return it->second.m_Details; +} + +void D3D11Replay::FreeTargetResource(ResourceId id) +{ + ID3D11DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id); + + SAFE_RELEASE(resource); +} + +void D3D11Replay::FreeCustomShader(ResourceId id) +{ + ID3D11DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id); + + SAFE_RELEASE(resource); +} + +vector D3D11Replay::GetFrameRecord() +{ + return m_pDevice->GetFrameRecord(); +} + +vector D3D11Replay::GetUsage(ResourceId id) +{ + return m_pDevice->GetImmediateContext()->GetUsage(id); +} + +APIProperties D3D11Replay::GetAPIProperties() +{ + APIProperties ret; + + ret.pipelineType = ePipelineState_D3D11; + + return ret; +} + +vector D3D11Replay::GetBuffers() +{ + vector ret; + + ret.reserve(WrappedID3D11Buffer::m_BufferList.size()); + + for(auto it = WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it) + ret.push_back(it->first); + + return ret; +} + +FetchBuffer D3D11Replay::GetBuffer(ResourceId id) +{ + FetchBuffer ret; + ret.ID = ResourceId(); + + auto it = WrappedID3D11Buffer::m_BufferList.find(id); + + if(it == WrappedID3D11Buffer::m_BufferList.end()) + return ret; + + WrappedID3D11Buffer *d3dbuf = it->second.m_Buffer; + + string str = GetDebugName(d3dbuf); + + ret.ID = m_pDevice->GetResourceManager()->GetOriginalID(it->first); + ret.customName = true; + + if(str == "") + { + ret.customName = false; + str = StringFormat::Fmt("Buffer %llu", ret.ID); + } + + D3D11_BUFFER_DESC desc; + it->second.m_Buffer->GetDesc(&desc); + + ret.name = widen(str); + ret.length = it->second.length; + ret.structureSize = desc.StructureByteStride; + ret.byteSize = desc.ByteWidth; + + ret.creationFlags = 0; + if(desc.BindFlags & D3D11_BIND_VERTEX_BUFFER) + ret.creationFlags |= eBufferCreate_VB; + if(desc.BindFlags & D3D11_BIND_INDEX_BUFFER) + ret.creationFlags |= eBufferCreate_IB; + + return ret; +} + +vector D3D11Replay::GetTextures() +{ + vector ret; + + ret.reserve(WrappedID3D11Texture1D::m_TextureList.size() + + WrappedID3D11Texture2D::m_TextureList.size() + + WrappedID3D11Texture3D::m_TextureList.size()); + + for(auto it = WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it) + ret.push_back(it->first); + + for(auto it = WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it) + ret.push_back(it->first); + + for(auto it = WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it) + ret.push_back(it->first); + + return ret; +} + +D3D11PipelineState D3D11Replay::MakePipelineState() +{ + D3D11RenderState *rs = m_pDevice->GetImmediateContext()->GetCurrentPipelineState(); + + D3D11PipelineState ret; + + ///////////////////////////////////////////////// + // Input Assembler + ///////////////////////////////////////////////// + + switch(rs->IA.Topo) + { + default: + case D3D_PRIMITIVE_TOPOLOGY_UNDEFINED: + ret.m_IA.Topology = eTopology_Unknown; + break; + case D3D_PRIMITIVE_TOPOLOGY_POINTLIST: + ret.m_IA.Topology = eTopology_PointList; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINELIST: + ret.m_IA.Topology = eTopology_LineList; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP: + ret.m_IA.Topology = eTopology_LineStrip; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST: + ret.m_IA.Topology = eTopology_TriangleList; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: + ret.m_IA.Topology = eTopology_TriangleStrip; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: + ret.m_IA.Topology = eTopology_LineList_Adj; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: + ret.m_IA.Topology = eTopology_LineStrip_Adj; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: + ret.m_IA.Topology = eTopology_TriangleList_Adj; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: + ret.m_IA.Topology = eTopology_TriangleStrip_Adj; + break; + case D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST: + case D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST: + ret.m_IA.Topology = PrimitiveTopology(eTopology_PatchList_1CPs + (rs->IA.Topo - D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST) ); + break; + } + + D3D11ResourceManager *rm = m_pDevice->GetResourceManager(); + + ret.m_IA.Bytecode = NULL; + + if(rs->IA.Layout) + { + const vector &vec = m_pDevice->GetLayoutDesc(rs->IA.Layout); + + ret.m_IA.layout = rm->GetOriginalID(GetIDForResource(rs->IA.Layout)); + ret.m_IA.Bytecode = m_pDevice->GetLayoutDXBC(rs->IA.Layout); + + create_array_uninit(ret.m_IA.layouts, vec.size()); + + for(size_t i=0; i < vec.size(); i++) + { + D3D11PipelineState::InputAssembler::LayoutInput &l = ret.m_IA.layouts[i]; + + l.ByteOffset = vec[i].AlignedByteOffset; + l.Format = MakeResourceFormat(vec[i].Format); + l.InputSlot = vec[i].InputSlot; + l.PerInstance = vec[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA; + l.InstanceDataStepRate = vec[i].InstanceDataStepRate; + l.SemanticIndex = vec[i].SemanticIndex; + l.SemanticName = widen(vec[i].SemanticName); + } + } + + create_array_uninit(ret.m_IA.vbuffers, ARRAY_COUNT(rs->IA.VBs)); + + for(size_t i=0; i < ARRAY_COUNT(rs->IA.VBs); i++) + { + D3D11PipelineState::InputAssembler::VertexBuffer &vb = ret.m_IA.vbuffers[i]; + + vb.Buffer = rm->GetOriginalID(GetIDForResource(rs->IA.VBs[i])); + vb.Offset = rs->IA.Offsets[i]; + vb.Stride = rs->IA.Strides[i]; + } + + ret.m_IA.ibuffer.Buffer = rm->GetOriginalID(GetIDForResource(rs->IA.IndexBuffer)); + ret.m_IA.ibuffer.Format = MakeResourceFormat(rs->IA.IndexFormat); + ret.m_IA.ibuffer.Offset = rs->IA.IndexOffset; + + ///////////////////////////////////////////////// + // Shaders + ///////////////////////////////////////////////// + + { + D3D11PipelineState::ShaderStage *dstArr = &ret.m_VS; + const D3D11RenderState::shader *srcArr = &rs->VS; + + for(size_t i=0; i < 6; i++) + { + D3D11PipelineState::ShaderStage &dst = dstArr[i]; + const D3D11RenderState::shader &src = srcArr[i]; + + dst.stage = (ShaderStageType)i; + + ResourceId id = GetIDForResource(src.Shader); + + dst.Shader = rm->GetOriginalID(id); + dst.ShaderDetails = NULL; + + create_array_uninit(dst.ConstantBuffers, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); + for(size_t s=0; s < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; s++) + { + dst.ConstantBuffers[s].Buffer = rm->GetOriginalID(GetIDForResource(src.ConstantBuffers[s])); + dst.ConstantBuffers[s].VecOffset = src.CBOffsets[s]; + dst.ConstantBuffers[s].VecCount = src.CBCounts[s]; + } + + create_array_uninit(dst.Samplers, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT); + for(size_t s=0; s < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; s++) + { + D3D11PipelineState::ShaderStage::Sampler &samp = dst.Samplers[s]; + + samp.Samp = rm->GetOriginalID(GetIDForResource(src.Samplers[s])); + + if(samp.Samp != ResourceId()) + { + D3D11_SAMPLER_DESC desc; + src.Samplers[s]->GetDesc(&desc); + + samp.AddressU = widen(ToStr::Get(desc.AddressU)); + samp.AddressV = widen(ToStr::Get(desc.AddressV)); + samp.AddressW = widen(ToStr::Get(desc.AddressW)); + + memcpy(samp.BorderColor, desc.BorderColor, sizeof(FLOAT)*4); + + samp.Comparison = widen(ToStr::Get(desc.ComparisonFunc)); + samp.Filter = widen(ToStr::Get(desc.Filter)); + samp.MaxAniso = desc.MaxAnisotropy; + samp.MaxLOD = desc.MaxLOD; + samp.MinLOD = desc.MinLOD; + samp.MipLODBias = desc.MipLODBias; + } + } + + create_array_uninit(dst.SRVs, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT); + for(size_t s=0; s < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; s++) + { + D3D11PipelineState::ShaderStage::ResourceView &view = dst.SRVs[s]; + + view.View = rm->GetOriginalID(GetIDForResource(src.SRVs[s])); + + if(view.View != ResourceId()) + { + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + src.SRVs[s]->GetDesc(&desc); + + view.Format = MakeResourceFormat(desc.Format); + + ID3D11Resource *res = NULL; + src.SRVs[s]->GetResource(&res); + + view.Structured = false; + view.BufferStructCount = 0; + + view.Resource = rm->GetOriginalID(GetIDForResource(res)); + + view.Type = widen(ToStr::Get(desc.ViewDimension)); + + if(desc.ViewDimension == D3D11_SRV_DIMENSION_BUFFER) + { + view.FirstElement = desc.Buffer.FirstElement; + view.NumElements = desc.Buffer.NumElements; + view.ElementOffset = desc.Buffer.ElementOffset; + view.ElementWidth = desc.Buffer.ElementWidth; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) + { + view.FirstElement = desc.BufferEx.FirstElement; + view.NumElements = desc.BufferEx.NumElements; + view.Flags = desc.BufferEx.Flags; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1D) + { + view.HighestMip = desc.Texture1D.MostDetailedMip; + view.NumMipLevels = desc.Texture1D.MipLevels; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY) + { + view.ArraySize = desc.Texture1DArray.ArraySize; + view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice; + view.HighestMip = desc.Texture1DArray.MostDetailedMip; + view.NumMipLevels = desc.Texture1DArray.MipLevels; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D) + { + view.HighestMip = desc.Texture2D.MostDetailedMip; + view.NumMipLevels = desc.Texture2D.MipLevels; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DARRAY) + { + view.ArraySize = desc.Texture2DArray.ArraySize; + view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice; + view.HighestMip = desc.Texture2DArray.MostDetailedMip; + view.NumMipLevels = desc.Texture2DArray.MipLevels; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMS) + { + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY) + { + view.ArraySize = desc.Texture2DArray.ArraySize; + view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) + { + view.HighestMip = desc.Texture3D.MostDetailedMip; + view.NumMipLevels = desc.Texture3D.MipLevels; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE) + { + view.HighestMip = desc.TextureCube.MostDetailedMip; + view.NumMipLevels = desc.TextureCube.MipLevels; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) + { + view.ArraySize = desc.TextureCubeArray.NumCubes; + view.FirstArraySlice = desc.TextureCubeArray.First2DArrayFace; + view.HighestMip = desc.TextureCubeArray.MostDetailedMip; + view.NumMipLevels = desc.TextureCubeArray.MipLevels; + } + + SAFE_RELEASE(res); + } + } + + create_array_uninit(dst.UAVs, D3D11_PS_CS_UAV_REGISTER_COUNT); + for(size_t s=0; s < D3D11_PS_CS_UAV_REGISTER_COUNT; s++) + { + D3D11PipelineState::ShaderStage::ResourceView &view = dst.UAVs[s]; + + view.View = rm->GetOriginalID(GetIDForResource(src.UAVs[s])); + + if(view.View != ResourceId()) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + src.UAVs[s]->GetDesc(&desc); + + ID3D11Resource *res = NULL; + src.UAVs[s]->GetResource(&res); + + view.Structured = false; + view.BufferStructCount = 0; + + if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER && + (desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND|D3D11_BUFFER_UAV_FLAG_COUNTER))) + { + view.Structured = true; + view.BufferStructCount = m_pDevice->GetDebugManager()->GetStructCount(src.UAVs[s]); + } + + view.Resource = rm->GetOriginalID(GetIDForResource(res)); + + view.Format = MakeResourceFormat(desc.Format); + view.Type = widen(ToStr::Get(desc.ViewDimension)); + + if(desc.ViewDimension == D3D11_RTV_DIMENSION_BUFFER) + { + view.FirstElement = desc.Buffer.FirstElement; + view.NumElements = desc.Buffer.NumElements; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1D) + { + view.MipSlice = desc.Texture1D.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1DARRAY) + { + view.ArraySize = desc.Texture1DArray.ArraySize; + view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice; + view.MipSlice = desc.Texture1DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2D) + { + view.MipSlice = desc.Texture2D.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2DARRAY) + { + view.ArraySize = desc.Texture2DArray.ArraySize; + view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice; + view.MipSlice = desc.Texture2DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE3D) + { + view.ArraySize = desc.Texture3D.WSize; + view.FirstArraySlice = desc.Texture3D.FirstWSlice; + view.MipSlice = desc.Texture3D.MipSlice; + } + + SAFE_RELEASE(res); + } + } + + create_array_uninit(dst.ClassInstances, src.NumInstances); + for(UINT s=0; s < src.NumInstances; s++) + { + D3D11_CLASS_INSTANCE_DESC desc; + src.Instances[s]->GetDesc(&desc); + + char typeName[256] = {0}; + SIZE_T count = 255; + src.Instances[s]->GetTypeName(typeName, &count); + + char instName[256] = {0}; + count = 255; + src.Instances[s]->GetInstanceName(instName, &count); + + dst.ClassInstances[s] = widen(instName); + } + } + } + + ///////////////////////////////////////////////// + // Stream Out + ///////////////////////////////////////////////// + + { + create_array_uninit(ret.m_SO.Outputs, D3D11_SO_BUFFER_SLOT_COUNT); + for(size_t s=0; s < D3D11_SO_BUFFER_SLOT_COUNT; s++) + { + ret.m_SO.Outputs[s].Buffer = rm->GetOriginalID(GetIDForResource(rs->SO.Buffers[s])); + ret.m_SO.Outputs[s].Offset = rs->SO.Offsets[s]; + } + } + + ///////////////////////////////////////////////// + // Rasterizer + ///////////////////////////////////////////////// + + { + D3D11_RASTERIZER_DESC desc; + + if(rs->RS.State) + { + rs->RS.State->GetDesc(&desc); + + ret.m_RS.m_State.AntialiasedLineEnable = desc.AntialiasedLineEnable == TRUE; + + ret.m_RS.m_State.CullMode = eCull_None; + if(desc.CullMode == D3D11_CULL_FRONT) ret.m_RS.m_State.CullMode = eCull_Front; + if(desc.CullMode == D3D11_CULL_BACK) ret.m_RS.m_State.CullMode = eCull_Back; + + ret.m_RS.m_State.FillMode = eFill_Solid; + if(desc.FillMode == D3D11_FILL_WIREFRAME) ret.m_RS.m_State.FillMode = eFill_Wireframe; + + ret.m_RS.m_State.DepthBias = desc.DepthBias; + ret.m_RS.m_State.DepthBiasClamp = desc.DepthBiasClamp; + ret.m_RS.m_State.DepthClip = desc.DepthClipEnable == TRUE; + ret.m_RS.m_State.FrontCCW = desc.FrontCounterClockwise == TRUE; + ret.m_RS.m_State.MultisampleEnable = desc.MultisampleEnable == TRUE; + ret.m_RS.m_State.ScissorEnable = desc.ScissorEnable == TRUE; + ret.m_RS.m_State.SlopeScaledDepthBias = desc.SlopeScaledDepthBias; + ret.m_RS.m_State.ForcedSampleCount = 0; + + D3D11_RASTERIZER_DESC1 desc1; + RDCEraseEl(desc1); + + if(WrappedID3D11RasterizerState1::IsAlloc(rs->RS.State)) + { + ((ID3D11RasterizerState1 *)rs->RS.State)->GetDesc1(&desc1); + ret.m_RS.m_State.ForcedSampleCount = desc1.ForcedSampleCount; + } + + ret.m_RS.m_State.State = rm->GetOriginalID(GetIDForResource(rs->RS.State)); + } + else + { + ret.m_RS.m_State.AntialiasedLineEnable = FALSE; + ret.m_RS.m_State.CullMode = eCull_Back; + ret.m_RS.m_State.DepthBias = 0; + ret.m_RS.m_State.DepthBiasClamp = 0.0f; + ret.m_RS.m_State.DepthClip = TRUE; + ret.m_RS.m_State.FillMode = eFill_Solid; + ret.m_RS.m_State.FrontCCW = FALSE; + ret.m_RS.m_State.MultisampleEnable = FALSE; + ret.m_RS.m_State.ScissorEnable = FALSE; + ret.m_RS.m_State.SlopeScaledDepthBias = 0.0f; + ret.m_RS.m_State.ForcedSampleCount = 0; + ret.m_RS.m_State.State = ResourceId(); + } + + size_t i=0; + create_array_uninit(ret.m_RS.Scissors, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE); + for(i=0; i < rs->RS.NumScissors; i++) + ret.m_RS.Scissors[i] = D3D11PipelineState::Rasterizer::Scissor(rs->RS.Scissors[i].left, rs->RS.Scissors[i].top, + rs->RS.Scissors[i].right, rs->RS.Scissors[i].bottom); + + for(; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; i++) + ret.m_RS.Scissors[i] = D3D11PipelineState::Rasterizer::Scissor(0, 0, 0, 0); + + create_array_uninit(ret.m_RS.Viewports, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE); + for(i=0; i < rs->RS.NumViews; i++) + ret.m_RS.Viewports[i] = D3D11PipelineState::Rasterizer::Viewport(rs->RS.Viewports[i].TopLeftX, rs->RS.Viewports[i].TopLeftY, + rs->RS.Viewports[i].Width, rs->RS.Viewports[i].Height, + rs->RS.Viewports[i].MinDepth, rs->RS.Viewports[i].MaxDepth); + + for(; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; i++) + ret.m_RS.Viewports[i] = D3D11PipelineState::Rasterizer::Viewport(0, 0, 0, 0, 0, 0); + } + + ///////////////////////////////////////////////// + // Output Merger + ///////////////////////////////////////////////// + + { + create_array_uninit(ret.m_OM.RenderTargets, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); + for(size_t i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + D3D11PipelineState::ShaderStage::ResourceView &view = ret.m_OM.RenderTargets[i]; + + view.View = rm->GetOriginalID(GetIDForResource(rs->OM.RenderTargets[i])); + + if(view.View != ResourceId()) + { + D3D11_RENDER_TARGET_VIEW_DESC desc; + rs->OM.RenderTargets[i]->GetDesc(&desc); + + ID3D11Resource *res = NULL; + rs->OM.RenderTargets[i]->GetResource(&res); + + view.Structured = false; + view.BufferStructCount = 0; + + view.Resource = rm->GetOriginalID(GetIDForResource(res)); + + view.Format = MakeResourceFormat(desc.Format); + view.Type = widen(ToStr::Get(desc.ViewDimension)); + + if(desc.ViewDimension == D3D11_RTV_DIMENSION_BUFFER) + { + view.FirstElement = desc.Buffer.FirstElement; + view.NumElements = desc.Buffer.NumElements; + } + else if(desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1D) + { + view.MipSlice = desc.Texture1D.MipSlice; + } + else if(desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1DARRAY) + { + view.ArraySize = desc.Texture1DArray.ArraySize; + view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice; + view.MipSlice = desc.Texture1DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2D) + { + view.MipSlice = desc.Texture2D.MipSlice; + } + else if(desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DARRAY) + { + view.ArraySize = desc.Texture2DArray.ArraySize; + view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice; + view.MipSlice = desc.Texture2DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE3D) + { + view.ArraySize = desc.Texture3D.WSize; + view.FirstArraySlice = desc.Texture3D.FirstWSlice; + view.MipSlice = desc.Texture3D.MipSlice; + } + + SAFE_RELEASE(res); + } + } + + ret.m_OM.UAVStartSlot = rs->OM.UAVStartSlot; + + create_array_uninit(ret.m_OM.UAVs, D3D11_PS_CS_UAV_REGISTER_COUNT); + for(size_t s=0; s < D3D11_PS_CS_UAV_REGISTER_COUNT; s++) + { + D3D11PipelineState::ShaderStage::ResourceView view; + + view.View = rm->GetOriginalID(GetIDForResource(rs->OM.UAVs[s])); + + if(view.View != ResourceId()) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + rs->OM.UAVs[s]->GetDesc(&desc); + + ID3D11Resource *res = NULL; + rs->OM.UAVs[s]->GetResource(&res); + + view.Structured = false; + view.BufferStructCount = 0; + + if(desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND|D3D11_BUFFER_UAV_FLAG_COUNTER)) + { + view.Structured = true; + view.BufferStructCount = m_pDevice->GetDebugManager()->GetStructCount(rs->OM.UAVs[s]); + } + + view.Resource = rm->GetOriginalID(GetIDForResource(res)); + + view.Format = MakeResourceFormat(desc.Format); + view.Type = widen(ToStr::Get(desc.ViewDimension)); + + if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER) + { + view.FirstElement = desc.Buffer.FirstElement; + view.NumElements = desc.Buffer.NumElements; + view.Flags = desc.Buffer.Flags; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1D) + { + view.MipSlice = desc.Texture1D.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1DARRAY) + { + view.ArraySize = desc.Texture1DArray.ArraySize; + view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice; + view.MipSlice = desc.Texture1DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2D) + { + view.MipSlice = desc.Texture2D.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2DARRAY) + { + view.ArraySize = desc.Texture2DArray.ArraySize; + view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice; + view.MipSlice = desc.Texture2DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE3D) + { + view.ArraySize = desc.Texture3D.WSize; + view.FirstArraySlice = desc.Texture3D.FirstWSlice; + view.MipSlice = desc.Texture3D.MipSlice; + } + + SAFE_RELEASE(res); + } + + ret.m_OM.UAVs[s] = view; + } + + { + D3D11PipelineState::ShaderStage::ResourceView &view = ret.m_OM.DepthTarget; + + view.View = rm->GetOriginalID(GetIDForResource(rs->OM.DepthView)); + + if(view.View != ResourceId()) + { + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + rs->OM.DepthView->GetDesc(&desc); + + ID3D11Resource *res = NULL; + rs->OM.DepthView->GetResource(&res); + + view.Structured = false; + view.BufferStructCount = 0; + + ret.m_OM.DepthReadOnly = false; + ret.m_OM.StencilReadOnly = false; + + if(desc.Flags & D3D11_DSV_READ_ONLY_DEPTH) + ret.m_OM.DepthReadOnly = true; + if(desc.Flags & D3D11_DSV_READ_ONLY_STENCIL) + ret.m_OM.StencilReadOnly = true; + + view.Resource = rm->GetOriginalID(GetIDForResource(res)); + + view.Format = MakeResourceFormat(desc.Format); + view.Type = widen(ToStr::Get(desc.ViewDimension)); + + if(desc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE1D) + { + view.MipSlice = desc.Texture1D.MipSlice; + } + else if(desc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE1DARRAY) + { + view.ArraySize = desc.Texture1DArray.ArraySize; + view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice; + view.MipSlice = desc.Texture1DArray.MipSlice; + } + else if(desc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE2D) + { + view.MipSlice = desc.Texture2D.MipSlice; + } + else if(desc.ViewDimension == D3D11_DSV_DIMENSION_TEXTURE2DARRAY) + { + view.ArraySize = desc.Texture2DArray.ArraySize; + view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice; + view.MipSlice = desc.Texture2DArray.MipSlice; + } + + SAFE_RELEASE(res); + } + } + + if(rs->OM.BlendState) + { + D3D11_BLEND_DESC desc; + rs->OM.BlendState->GetDesc(&desc); + + ret.m_OM.m_BlendState.State = GetIDForResource(rs->OM.BlendState); + + ret.m_OM.m_BlendState.SampleMask = rs->OM.SampleMask; + memcpy(ret.m_OM.m_BlendState.BlendFactor, rs->OM.BlendFactor, sizeof(FLOAT)*4); + ret.m_OM.m_BlendState.AlphaToCoverage = desc.AlphaToCoverageEnable == TRUE; + ret.m_OM.m_BlendState.IndependentBlend = desc.IndependentBlendEnable == TRUE; + + bool state1 = false; + D3D11_BLEND_DESC1 desc1; + RDCEraseEl(desc1); + + if(WrappedID3D11BlendState1::IsAlloc(rs->OM.BlendState)) + { + ((ID3D11BlendState1 *)rs->OM.BlendState)->GetDesc1(&desc1); + + state1 = true; + } + + create_array_uninit(ret.m_OM.m_BlendState.Blends, 8); + for(size_t i=0; i < 8; i++) + { + D3D11PipelineState::OutputMerger::BlendState::RTBlend &blend = ret.m_OM.m_BlendState.Blends[i]; + + blend.Enabled = desc.RenderTarget[i].BlendEnable == TRUE; + + blend.LogicEnabled = state1 && desc1.RenderTarget[i].LogicOpEnable == TRUE; + blend.LogicOp = state1 ? widen(ToStr::Get(desc1.RenderTarget[i].LogicOp)) : widen(ToStr::Get(D3D11_LOGIC_OP_NOOP)); + + blend.m_AlphaBlend.Source = widen(ToStr::Get(desc.RenderTarget[i].SrcBlendAlpha)); + blend.m_AlphaBlend.Destination = widen(ToStr::Get(desc.RenderTarget[i].DestBlendAlpha)); + blend.m_AlphaBlend.Operation = widen(ToStr::Get(desc.RenderTarget[i].BlendOpAlpha)); + + blend.m_Blend.Source = widen(ToStr::Get(desc.RenderTarget[i].SrcBlend)); + blend.m_Blend.Destination = widen(ToStr::Get(desc.RenderTarget[i].DestBlend)); + blend.m_Blend.Operation = widen(ToStr::Get(desc.RenderTarget[i].BlendOp)); + + blend.WriteMask = desc.RenderTarget[i].RenderTargetWriteMask; + } + } + else + { + ret.m_OM.m_BlendState.State = ResourceId(); + + ret.m_OM.m_BlendState.SampleMask = ~0U; + ret.m_OM.m_BlendState.BlendFactor[0] = ret.m_OM.m_BlendState.BlendFactor[1] = + ret.m_OM.m_BlendState.BlendFactor[2] = ret.m_OM.m_BlendState.BlendFactor[3] = 1.0f; + ret.m_OM.m_BlendState.AlphaToCoverage = false; + ret.m_OM.m_BlendState.IndependentBlend = false; + + D3D11PipelineState::OutputMerger::BlendState::RTBlend blend; + + blend.Enabled = false; + + blend.m_AlphaBlend.Source = widen(ToStr::Get(D3D11_BLEND_ONE)); + blend.m_AlphaBlend.Destination = widen(ToStr::Get(D3D11_BLEND_ZERO)); + blend.m_AlphaBlend.Operation = widen(ToStr::Get(D3D11_BLEND_OP_ADD)); + + blend.m_Blend.Source = widen(ToStr::Get(D3D11_BLEND_ONE)); + blend.m_Blend.Destination = widen(ToStr::Get(D3D11_BLEND_ZERO)); + blend.m_Blend.Operation = widen(ToStr::Get(D3D11_BLEND_OP_ADD)); + + blend.LogicEnabled = false; + blend.LogicOp = widen(ToStr::Get(D3D11_LOGIC_OP_NOOP)); + + blend.WriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + create_array_uninit(ret.m_OM.m_BlendState.Blends, 8); + for(size_t i=0; i < 8; i++) + ret.m_OM.m_BlendState.Blends[i] = blend; + } + + if(rs->OM.DepthStencilState) + { + D3D11_DEPTH_STENCIL_DESC desc; + rs->OM.DepthStencilState->GetDesc(&desc); + + ret.m_OM.m_State.DepthEnable = desc.DepthEnable == TRUE; + ret.m_OM.m_State.DepthFunc = widen(ToStr::Get(desc.DepthFunc)); + ret.m_OM.m_State.DepthWrites = desc.DepthWriteMask == D3D11_DEPTH_WRITE_MASK_ALL; + ret.m_OM.m_State.StencilEnable = desc.StencilEnable == TRUE; + ret.m_OM.m_State.StencilRef = rs->OM.StencRef; + ret.m_OM.m_State.StencilReadMask = desc.StencilReadMask; + ret.m_OM.m_State.StencilWriteMask = desc.StencilWriteMask; + ret.m_OM.m_State.State = rm->GetOriginalID(GetIDForResource(rs->OM.DepthStencilState)); + + ret.m_OM.m_State.m_FrontFace.Func = widen(ToStr::Get(desc.FrontFace.StencilFunc)); + ret.m_OM.m_State.m_FrontFace.DepthFailOp = widen(ToStr::Get(desc.FrontFace.StencilDepthFailOp)); + ret.m_OM.m_State.m_FrontFace.PassOp = widen(ToStr::Get(desc.FrontFace.StencilPassOp)); + ret.m_OM.m_State.m_FrontFace.FailOp = widen(ToStr::Get(desc.FrontFace.StencilFailOp)); + + ret.m_OM.m_State.m_BackFace.Func = widen(ToStr::Get(desc.BackFace.StencilFunc)); + ret.m_OM.m_State.m_BackFace.DepthFailOp = widen(ToStr::Get(desc.BackFace.StencilDepthFailOp)); + ret.m_OM.m_State.m_BackFace.PassOp = widen(ToStr::Get(desc.BackFace.StencilPassOp)); + ret.m_OM.m_State.m_BackFace.FailOp = widen(ToStr::Get(desc.BackFace.StencilFailOp)); + } + else + { + + ret.m_OM.m_State.DepthEnable = true; + ret.m_OM.m_State.DepthFunc = widen(ToStr::Get(D3D11_COMPARISON_LESS)); + ret.m_OM.m_State.DepthWrites = true; + ret.m_OM.m_State.StencilEnable = false; + ret.m_OM.m_State.StencilRef = rs->OM.StencRef; + ret.m_OM.m_State.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + ret.m_OM.m_State.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + ret.m_OM.m_State.State = ResourceId(); + + ret.m_OM.m_State.m_FrontFace.Func = widen(ToStr::Get(D3D11_COMPARISON_ALWAYS)); + ret.m_OM.m_State.m_FrontFace.DepthFailOp = widen(ToStr::Get(D3D11_STENCIL_OP_KEEP)); + ret.m_OM.m_State.m_FrontFace.PassOp = widen(ToStr::Get(D3D11_STENCIL_OP_KEEP)); + ret.m_OM.m_State.m_FrontFace.FailOp = widen(ToStr::Get(D3D11_STENCIL_OP_KEEP)); + + ret.m_OM.m_State.m_BackFace.Func = widen(ToStr::Get(D3D11_COMPARISON_ALWAYS)); + ret.m_OM.m_State.m_BackFace.DepthFailOp = widen(ToStr::Get(D3D11_STENCIL_OP_KEEP)); + ret.m_OM.m_State.m_BackFace.PassOp = widen(ToStr::Get(D3D11_STENCIL_OP_KEEP)); + ret.m_OM.m_State.m_BackFace.FailOp = widen(ToStr::Get(D3D11_STENCIL_OP_KEEP)); + } + } + + return ret; +} + +void D3D11Replay::ReadLogInitialisation() +{ + m_pDevice->ReadLogInitialisation(); +} + +void D3D11Replay::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ + m_pDevice->SetContextFilter(id, firstDefEv, lastDefEv); +} + +void D3D11Replay::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType) +{ + m_pDevice->ReplayLog(frameID, startEventID, endEventID, replayType); +} + + +uint64_t D3D11Replay::MakeOutputWindow(void *w, bool depth) +{ + return m_pDevice->GetDebugManager()->MakeOutputWindow(w, depth); +} + +void D3D11Replay::DestroyOutputWindow(uint64_t id) +{ + m_pDevice->GetDebugManager()->DestroyOutputWindow(id); +} + +bool D3D11Replay::CheckResizeOutputWindow(uint64_t id) +{ + return m_pDevice->GetDebugManager()->CheckResizeOutputWindow(id); +} + +void D3D11Replay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) +{ + m_pDevice->GetDebugManager()->GetOutputWindowDimensions(id, w, h); +} + +void D3D11Replay::ClearOutputWindowColour(uint64_t id, float col[4]) +{ + m_pDevice->GetDebugManager()->ClearOutputWindowColour(id, col); +} + +void D3D11Replay::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil) +{ + m_pDevice->GetDebugManager()->ClearOutputWindowDepth(id, depth, stencil); +} + +void D3D11Replay::BindOutputWindow(uint64_t id, bool depth) +{ + m_pDevice->GetDebugManager()->BindOutputWindow(id, depth); +} + +bool D3D11Replay::IsOutputWindowVisible(uint64_t id) +{ + return m_pDevice->GetDebugManager()->IsOutputWindowVisible(id); +} + +void D3D11Replay::FlipOutputWindow(uint64_t id) +{ + m_pDevice->GetDebugManager()->FlipOutputWindow(id); +} + +void D3D11Replay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) +{ + m_pDevice->GetDebugManager()->InitPostVSBuffers(frameID, eventID); +} + +ResourceId D3D11Replay::GetLiveID(ResourceId id) +{ + return m_pDevice->GetResourceManager()->GetLiveID(id); +} + +bool D3D11Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval) +{ + return m_pDevice->GetDebugManager()->GetMinMax(texid, sliceFace, mip, minval, maxval); +} + +bool D3D11Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram) +{ + return m_pDevice->GetDebugManager()->GetHistogram(texid, sliceFace, mip, minval, maxval, channels, histogram); +} + +PostVSMeshData D3D11Replay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +{ + return m_pDevice->GetDebugManager()->GetPostVSBuffers(frameID, eventID, stage); +} + +vector D3D11Replay::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) +{ + return m_pDevice->GetDebugManager()->GetBufferData(buff, offset, len); +} + +byte *D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize) +{ + return m_pDevice->GetDebugManager()->GetTextureData(tex, arrayIdx, mip, dataSize); +} + +void D3D11Replay::ReplaceResource(ResourceId from, ResourceId to) +{ + m_pDevice->GetResourceManager()->ReplaceResource(from, to); +} + +void D3D11Replay::RemoveReplacement(ResourceId id) +{ + m_pDevice->GetResourceManager()->RemoveReplacement(id); +} + +void D3D11Replay::TimeDrawcalls(rdctype::array &arr) +{ + return m_pDevice->GetDebugManager()->TimeDrawcalls(arr); +} + +bool D3D11Replay::SaveTexture(ResourceId tex, uint32_t saveMip, wstring path) +{ + return m_pDevice->GetDebugManager()->SaveTexture(tex, saveMip, path); +} + +void D3D11Replay::RenderMesh(int frameID, vector eventID, MeshDisplay cfg) +{ + return m_pDevice->GetDebugManager()->RenderMesh(frameID, eventID, cfg); +} + +void D3D11Replay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) +{ + m_pDevice->GetDebugManager()->BuildShader(source, entry, D3DCOMPILE_DEBUG|compileFlags, type, id, errors); +} + +void D3D11Replay::BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) +{ + m_pDevice->GetDebugManager()->BuildShader(source, entry, compileFlags, type, id, errors); +} + +bool D3D11Replay::RenderTexture(TextureDisplay cfg) +{ + return m_pDevice->GetDebugManager()->RenderTexture(cfg); +} + +void D3D11Replay::RenderCheckerboard(Vec3f light, Vec3f dark) +{ + m_pDevice->GetDebugManager()->RenderCheckerboard(light, dark); +} + +void D3D11Replay::RenderHighlightBox(float w, float h, float scale) +{ + m_pDevice->GetDebugManager()->RenderHighlightBox(w, h, scale); +} + +void D3D11Replay::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) +{ + auto it = WrappedShader::m_ShaderList.find(shader); + + if(it == WrappedShader::m_ShaderList.end()) + return; + + RDCASSERT(it->second.m_DXBCFile); + + DXBC::DXBCFile *dxbc = it->second.m_DXBCFile; + + if(cbufSlot < dxbc->m_CBuffers.size()) + m_pDevice->GetDebugManager()->FillCBufferVariables(dxbc->m_CBuffers[cbufSlot].variables, outvars, false, data); + return; +} + +ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) +{ + return m_pDevice->GetDebugManager()->DebugVertex(frameID, eventID, vertid, instid, idx, instOffset, vertOffset); +} + +ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) +{ + return m_pDevice->GetDebugManager()->DebugPixel(frameID, eventID, x, y); +} + +ShaderDebugTrace D3D11Replay::DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]) +{ + return m_pDevice->GetDebugManager()->DebugThread(frameID, eventID, groupid, threadid); +} + +void D3D11Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]) +{ + m_pDevice->GetDebugManager()->PickPixel(texture, x, y, sliceFace, mip, pixel); +} + +ResourceId D3D11Replay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID) +{ + return m_pDevice->GetDebugManager()->RenderOverlay(texid, overlay, frameID, eventID); +} + +ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) +{ + return m_pDevice->GetDebugManager()->ApplyCustomShader(shader, texid, mip); +} + +bool D3D11Replay::IsRenderOutput(ResourceId id) +{ + for(size_t i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if(m_CurPipelineState.m_OM.RenderTargets[i].View == id || + m_CurPipelineState.m_OM.RenderTargets[i].Resource == id) + return true; + } + + if(m_CurPipelineState.m_OM.DepthTarget.View == id || + m_CurPipelineState.m_OM.DepthTarget.Resource == id) + return true; + + return false; +} + +void D3D11Replay::InitCallstackResolver() +{ + m_pDevice->GetSerialiser()->InitCallstackResolver(); +} + +bool D3D11Replay::HasCallstacks() +{ + return m_pDevice->GetSerialiser()->HasCallstacks(); +} + +Callstack::StackResolver *D3D11Replay::GetCallstackResolver() +{ + return m_pDevice->GetSerialiser()->GetCallstackResolver(); +} + +ResourceId D3D11Replay::CreateProxyTexture(FetchTexture templateTex) +{ + ResourceId ret; + + if(templateTex.dimension == 1) + { + ID3D11Texture1D *throwaway = NULL; + D3D11_TEXTURE1D_DESC desc; + + desc.ArraySize = templateTex.arraysize; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + if(templateTex.creationFlags & eTextureCreate_DSV) + desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL; + + desc.CPUAccessFlags = 0; + desc.Format = MakeDXGIFormat(templateTex.format); + desc.MipLevels = templateTex.mips; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.Width = templateTex.width; + + HRESULT hr = m_pDevice->CreateTexture1D(&desc, NULL, &throwaway); + if(FAILED(hr)) + { + RDCERR("Failed to create 1D proxy texture"); + return ResourceId(); + } + + if(templateTex.creationFlags & eTextureCreate_DSV) + desc.Format = GetTypelessFormat(desc.Format); + + ret = ((WrappedID3D11Texture1D *)throwaway)->GetResourceID(); + + if(templateTex.creationFlags & eTextureCreate_DSV) + WrappedID3D11Texture1D::m_TextureList[ret].m_Type = TEXDISPLAY_DEPTH_TARGET; + } + else if(templateTex.dimension == 2) + { + ID3D11Texture2D *throwaway = NULL; + D3D11_TEXTURE2D_DESC desc; + + desc.ArraySize = templateTex.arraysize; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + desc.CPUAccessFlags = 0; + desc.Format = MakeDXGIFormat(templateTex.format); + desc.MipLevels = templateTex.mips; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.Width = templateTex.width; + desc.Height = templateTex.height; + desc.SampleDesc.Count = templateTex.msSamp; + desc.SampleDesc.Quality = templateTex.msQual; + + if(templateTex.creationFlags & eTextureCreate_DSV) + { + desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL; + desc.Format = GetTypelessFormat(desc.Format); + } + + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &throwaway); + if(FAILED(hr)) + { + RDCERR("Failed to create 2D proxy texture"); + return ResourceId(); + } + + ret = ((WrappedID3D11Texture2D *)throwaway)->GetResourceID(); + if(templateTex.creationFlags & eTextureCreate_DSV) + WrappedID3D11Texture2D::m_TextureList[ret].m_Type = TEXDISPLAY_DEPTH_TARGET; + } + else if(templateTex.dimension == 3) + { + ID3D11Texture3D *throwaway = NULL; + D3D11_TEXTURE3D_DESC desc; + + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + if(templateTex.creationFlags & eTextureCreate_DSV) + desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL; + + desc.CPUAccessFlags = 0; + desc.Format = MakeDXGIFormat(templateTex.format); + desc.MipLevels = templateTex.mips; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.Width = templateTex.width; + desc.Height = templateTex.height; + desc.Depth = templateTex.depth; + + HRESULT hr = m_pDevice->CreateTexture3D(&desc, NULL, &throwaway); + if(FAILED(hr)) + { + RDCERR("Failed to create 3D proxy texture"); + return ResourceId(); + } + + ret = ((WrappedID3D11Texture3D *)throwaway)->GetResourceID(); + } + else + { + RDCERR("Invalid texture dimension: %d", templateTex.dimension); + } + + return ret; +} + +void D3D11Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize) +{ + if(texid == ResourceId()) return; + + ID3D11DeviceContext *ctx = m_pDevice->GetImmediateContext()->GetReal(); + + if(WrappedID3D11Texture1D::m_TextureList.find(texid) != WrappedID3D11Texture1D::m_TextureList.end()) + { + WrappedID3D11Texture1D *tex = (WrappedID3D11Texture1D *)WrappedID3D11Texture1D::m_TextureList[texid].m_Texture; + + D3D11_TEXTURE1D_DESC desc; + tex->GetDesc(&desc); + + uint32_t mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, 1, 1); + + if(mip >= mips || arrayIdx >= desc.ArraySize) + { + RDCERR("arrayIdx %d and mip %d invalid for tex", arrayIdx, mip); + return; + } + + uint32_t sub = arrayIdx*mips + mip; + + if(dataSize < GetByteSize(desc.Width, 1, 1, desc.Format, mip)) + { + RDCERR("Insufficient data provided to SetProxyTextureData"); + return; + } + + ctx->UpdateSubresource(tex->GetReal(), sub, NULL, data, + GetByteSize(desc.Width, 1, 1, desc.Format, mip), + GetByteSize(desc.Width, 1, 1, desc.Format, mip)); + } + else if(WrappedID3D11Texture2D::m_TextureList.find(texid) != WrappedID3D11Texture2D::m_TextureList.end()) + { + WrappedID3D11Texture2D *tex = (WrappedID3D11Texture2D *)WrappedID3D11Texture2D::m_TextureList[texid].m_Texture; + + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + + uint32_t mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, 1); + + if(mip >= mips || arrayIdx >= desc.ArraySize) + { + RDCERR("arrayIdx %d and mip %d invalid for tex", arrayIdx, mip); + return; + } + + uint32_t sub = arrayIdx*mips + mip; + + if(dataSize < GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)) + { + RDCERR("Insufficient data provided to SetProxyTextureData"); + return; + } + + ctx->UpdateSubresource(tex->GetReal(), sub, NULL, data, + GetByteSize(desc.Width, 1, 1, desc.Format, mip), + GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)); + } + else if(WrappedID3D11Texture3D::m_TextureList.find(texid) != WrappedID3D11Texture3D::m_TextureList.end()) + { + WrappedID3D11Texture3D *tex = (WrappedID3D11Texture3D *)WrappedID3D11Texture3D::m_TextureList[texid].m_Texture; + + D3D11_TEXTURE3D_DESC desc; + tex->GetDesc(&desc); + + uint32_t mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, desc.Depth); + + if(mip >= mips) + { + RDCERR("arrayIdx %d and mip %d invalid for tex", arrayIdx, mip); + return; + } + + if(dataSize < GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, mip)) + { + RDCERR("Insufficient data provided to SetProxyTextureData"); + return; + } + + ctx->UpdateSubresource(tex->GetReal(), mip, NULL, data, + GetByteSize(desc.Width, 1, 1, desc.Format, mip), + GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)); + } + else + { + RDCERR("Invalid texture id passed to SetProxyTextureData"); + } +} + +ReplayCreateStatus D3D11_CreateReplayDevice(const wchar_t *logfile, IReplayDriver **driver) +{ + RDCDEBUG("Creating a D3D11 replay device"); + + HMODULE lib = NULL; + lib = LoadLibraryA("d3d11.dll"); + if(lib == NULL) + { + RDCERR("Failed to load d3d11.dll"); + return eReplayCreate_APIInitFailed; + } + + lib = LoadLibraryA("d3d9.dll"); + if(lib == NULL) + { + RDCERR("Failed to load d3d9.dll"); + return eReplayCreate_APIInitFailed; + } + + lib = LoadLibraryA("dxgi.dll"); + if(lib == NULL) + { + RDCERR("Failed to load dxgi.dll"); + return eReplayCreate_APIInitFailed; + } + + if(GetD3DCompiler() == NULL) + { + RDCERR("Failed to load d3dcompiler_??.dll"); + return eReplayCreate_APIInitFailed; + } + + typedef HRESULT (__cdecl* PFN_RENDERDOC_CREATE_DEVICE_AND_SWAP_CHAIN)( __in_opt IDXGIAdapter*, + D3D_DRIVER_TYPE, HMODULE, UINT, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL*, + UINT FeatureLevels, UINT, __in_opt CONST DXGI_SWAP_CHAIN_DESC*, + __out_opt IDXGISwapChain**, __out_opt ID3D11Device**, + __out_opt D3D_FEATURE_LEVEL*, __out_opt ID3D11DeviceContext** ); + + PFN_RENDERDOC_CREATE_DEVICE_AND_SWAP_CHAIN createDevice = (PFN_RENDERDOC_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(GetModuleHandleA("renderdoc.dll"), "RENDERDOC_CreateWrappedD3D11DeviceAndSwapChain"); + + RDCASSERT(createDevice); + + ID3D11Device *device = NULL; + + D3D11InitParams initParams; + RDCDriver driverFileType = RDC_D3D11; + wstring driverName = L"D3D11"; + if(logfile) + { + auto status = RenderDoc::Inst().FillInitParams(logfile, driverFileType, driverName, (RDCInitParams *)&initParams); + if(status != eReplayCreate_Success) + return status; + } + + if(initParams.SerialiseVersion != D3D11InitParams::D3D11_SERIALISE_VERSION) + { + RDCERR("Incompatible D3D11 serialise version, expected %d got %d", D3D11InitParams::D3D11_SERIALISE_VERSION, initParams.SerialiseVersion); + return eReplayCreate_APIIncompatibleVersion; + } + + if(initParams.SDKVersion != D3D11_SDK_VERSION) + { + RDCWARN("Capture file used a different SDK version %lu from replay app %lu. Results may be undefined", initParams.SDKVersion, D3D11_SDK_VERSION); + } + + if(initParams.DriverType == D3D_DRIVER_TYPE_UNKNOWN) + initParams.DriverType = D3D_DRIVER_TYPE_HARDWARE; + + int i=-2; + + // force using our feature levels as we require >= 11_0 for analysis + D3D_FEATURE_LEVEL featureLevelArray11_1[] = {D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 }; + UINT numFeatureLevels11_1 = ARRAY_COUNT(featureLevelArray11_1); + + D3D_FEATURE_LEVEL featureLevelArray11_0[] = { D3D_FEATURE_LEVEL_11_0 }; + UINT numFeatureLevels11_0 = ARRAY_COUNT(featureLevelArray11_0); + + D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE }; + int numDrivers = ARRAY_COUNT(driverTypes); + + D3D_FEATURE_LEVEL *featureLevelArray = featureLevelArray11_1; + UINT numFeatureLevels = numFeatureLevels11_1; + D3D_DRIVER_TYPE driverType = initParams.DriverType; + UINT flags = initParams.Flags; + + HRESULT hr = E_FAIL; + + D3D_FEATURE_LEVEL maxFeatureLevel = D3D_FEATURE_LEVEL_9_1; + + // check for feature level 11 support - passing NULL feature level array implicitly checks for 11_0 before others + hr = createDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, NULL, NULL, NULL, &maxFeatureLevel, NULL); + + if(SUCCEEDED(hr) && maxFeatureLevel < D3D_FEATURE_LEVEL_11_0) + { + RDCERR("Couldn't create FEATURE_LEVEL_11_0 device - RenderDoc requires FEATURE_LEVEL_11_0 availability"); + return eReplayCreate_APIHardwareUnsupported; + } + + hr = E_FAIL; + while(1) + { + hr = createDevice( + /*pAdapter=*/NULL, driverType, /*Software=*/NULL, flags, + /*pFeatureLevels=*/featureLevelArray, /*nFeatureLevels=*/numFeatureLevels, D3D11_SDK_VERSION, + /*pSwapChainDesc=*/NULL, (IDXGISwapChain **)NULL, (ID3D11Device **)&device, (D3D_FEATURE_LEVEL*)NULL, (ID3D11DeviceContext **)NULL); + + if(SUCCEEDED(hr)) + { + if(logfile) ((WrappedID3D11Device *)device)->SetLogFile(logfile); + + RDCLOG("Created device."); + D3D11Replay *replay = ((WrappedID3D11Device *)device)->GetReplay(); + + replay->SetProxy(logfile == NULL); + + *driver = (IReplayDriver *)replay; + return eReplayCreate_Success; + } + + if(i == -1) + { + RDCWARN("Couldn't create device with similar settings to capture."); + } + + SAFE_RELEASE(device); + + i++; + + if(i >= numDrivers*2) + break; + + if(i >= 0) + initParams.DriverType = driverTypes[i/2]; + + if(i % 2 == 0) + { + featureLevelArray = featureLevelArray11_1; + numFeatureLevels = numFeatureLevels11_1; + } + else + { + featureLevelArray = featureLevelArray11_0; + numFeatureLevels = numFeatureLevels11_0; + } + } + + RDCERR("Couldn't create any compatible d3d11 device :(."); + + return eReplayCreate_APIHardwareUnsupported; +} + +static DriverRegistration D3D11DriverRegistration(RDC_D3D11, L"D3D11", &D3D11_CreateReplayDevice); diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h new file mode 100644 index 0000000000..cb03e22e9f --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -0,0 +1,139 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "replay/renderdoc.h" +#include "replay/replay_driver.h" +#include "core/core.h" + +class WrappedID3D11Device; + +class D3D11Replay : public IReplayDriver +{ + public: + D3D11Replay(); + + void SetProxy(bool p) { m_Proxy = p; } + bool IsRemoteProxy() { return m_Proxy; } + + void Shutdown(); + + void SetDevice(WrappedID3D11Device *d) { m_pDevice = d; } + + APIProperties GetAPIProperties(); + + vector GetBuffers(); + FetchBuffer GetBuffer(ResourceId id); + + vector GetTextures(); + FetchTexture GetTexture(ResourceId id); + + ShaderReflection *GetShader(ResourceId id); + + vector GetUsage(ResourceId id); + + vector GetFrameRecord(); + + void SavePipelineState() { m_CurPipelineState = MakePipelineState(); } + D3D11PipelineState GetD3D11PipelineState() { return m_CurPipelineState; } + GLPipelineState GetGLPipelineState() { return GLPipelineState(); } + + void FreeTargetResource(ResourceId id); + void FreeCustomShader(ResourceId id); + + void ReadLogInitialisation(); + void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); + void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); + + uint64_t MakeOutputWindow(void *w, bool depth); + void DestroyOutputWindow(uint64_t id); + bool CheckResizeOutputWindow(uint64_t id); + void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); + void ClearOutputWindowColour(uint64_t id, float col[4]); + void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil); + void BindOutputWindow(uint64_t id, bool depth); + bool IsOutputWindowVisible(uint64_t id); + void FlipOutputWindow(uint64_t id); + + void InitPostVSBuffers(uint32_t frameID, uint32_t eventID); + + ResourceId GetLiveID(ResourceId id); + + bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval); + bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram); + + PostVSMeshData GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + + vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize); + + void BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); + void ReplaceResource(ResourceId from, ResourceId to); + void RemoveReplacement(ResourceId id); + + void TimeDrawcalls(rdctype::array &arr); + + bool SaveTexture(ResourceId tex, uint32_t saveMip, wstring path); + + ResourceId CreateProxyTexture(FetchTexture templateTex); + void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize); + + void RenderMesh(int frameID, vector eventID, MeshDisplay cfg); + + bool RenderTexture(TextureDisplay cfg); + + void RenderCheckerboard(Vec3f light, Vec3f dark); + + void RenderHighlightBox(float w, float h, float scale); + + void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data); + + ShaderDebugTrace DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); + ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y); + ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]); + + ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID); + + void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip); + + bool IsRenderOutput(ResourceId id); + + void InitCallstackResolver(); + bool HasCallstacks(); + Callstack::StackResolver *GetCallstackResolver(); + private: + D3D11PipelineState MakePipelineState(); + + bool m_Proxy; + + WrappedID3D11Device *m_pDevice; + + D3D11PipelineState m_CurPipelineState; +}; + + diff --git a/renderdoc/driver/d3d11/d3d11_resources.cpp b/renderdoc/driver/d3d11/d3d11_resources.cpp new file mode 100644 index 0000000000..a3729c934f --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_resources.cpp @@ -0,0 +1,1514 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/dxgi/dxgi_wrapped.h" +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_resources.h" + +WRAPPED_POOL_INST(WrappedID3D11Buffer); +WRAPPED_POOL_INST(WrappedID3D11Texture1D); +WRAPPED_POOL_INST(WrappedID3D11Texture2D); +WRAPPED_POOL_INST(WrappedID3D11Texture3D); +WRAPPED_POOL_INST(WrappedID3D11InputLayout); +WRAPPED_POOL_INST(WrappedID3D11SamplerState); +WRAPPED_POOL_INST(WrappedID3D11RasterizerState); +WRAPPED_POOL_INST(WrappedID3D11RasterizerState1); +WRAPPED_POOL_INST(WrappedID3D11DepthStencilState); +WRAPPED_POOL_INST(WrappedID3D11BlendState); +WRAPPED_POOL_INST(WrappedID3D11BlendState1); +WRAPPED_POOL_INST(WrappedID3D11ShaderResourceView); +WRAPPED_POOL_INST(WrappedID3D11UnorderedAccessView); +WRAPPED_POOL_INST(WrappedID3D11RenderTargetView); +WRAPPED_POOL_INST(WrappedID3D11DepthStencilView); +WRAPPED_POOL_INST(WrappedID3D11Shader); +WRAPPED_POOL_INST(WrappedID3D11Shader); +WRAPPED_POOL_INST(WrappedID3D11Shader); +WRAPPED_POOL_INST(WrappedID3D11Shader); +WRAPPED_POOL_INST(WrappedID3D11Shader); +WRAPPED_POOL_INST(WrappedID3D11Shader); +WRAPPED_POOL_INST(WrappedID3D11Counter); +WRAPPED_POOL_INST(WrappedID3D11Query); +WRAPPED_POOL_INST(WrappedID3D11Predicate); +WRAPPED_POOL_INST(WrappedID3D11ClassInstance); +WRAPPED_POOL_INST(WrappedID3D11ClassLinkage); + +volatile LONGLONG TrackedResource::globalIDCounter = 1; + +map WrappedTexture::m_TextureList; +map WrappedTexture::m_TextureList; +map WrappedTexture::m_TextureList; +map WrappedID3D11Buffer::m_BufferList; +map WrappedShader::m_ShaderList; + +UINT CalcNumMips(int w, int h, int d) +{ + int mipLevels = 1; + + while(w > 1 || h > 1 || d > 1) + { + w = RDCMAX(1, w>>1); + h = RDCMAX(1, h>>1); + d = RDCMAX(1, d>>1); + mipLevels++; + } + + return mipLevels; +} + +UINT GetMipForSubresource(ID3D11Resource *res, int Subresource) +{ + D3D11_RESOURCE_DIMENSION dim; + + // check for wrapped types first as they will be most common and don't + // require a virtual call + if(WrappedID3D11Texture1D::IsAlloc(res)) + dim = D3D11_RESOURCE_DIMENSION_TEXTURE1D; + else if(WrappedID3D11Texture2D::IsAlloc(res)) + dim = D3D11_RESOURCE_DIMENSION_TEXTURE2D; + else if(WrappedID3D11Texture3D::IsAlloc(res)) + dim = D3D11_RESOURCE_DIMENSION_TEXTURE3D; + else + res->GetType(&dim); + + ID3D11Texture1D *tex1 = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D) ? (ID3D11Texture1D *)res : NULL; + ID3D11Texture2D *tex2 = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) ? (ID3D11Texture2D *)res : NULL; + ID3D11Texture3D *tex3 = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) ? (ID3D11Texture3D *)res : NULL; + + RDCASSERT(tex1 || tex2 || tex3); + + UINT mipLevel = Subresource; + + if(tex1) + { + D3D11_TEXTURE1D_DESC desc; + tex1->GetDesc(&desc); + + int mipLevels = desc.MipLevels; + + if(mipLevels == 0) + mipLevels = CalcNumMips(desc.Width, 1, 1); + + mipLevel %= mipLevels; + } + else if(tex2) + { + D3D11_TEXTURE2D_DESC desc; + tex2->GetDesc(&desc); + + int mipLevels = desc.MipLevels; + + if(mipLevels == 0) + mipLevels = CalcNumMips(desc.Width, desc.Height, 1); + + mipLevel %= mipLevels; + } + else if(tex3) + { + D3D11_TEXTURE3D_DESC desc; + tex3->GetDesc(&desc); + + int mipLevels = desc.MipLevels; + + if(mipLevels == 0) + mipLevels = CalcNumMips(desc.Width, desc.Height, desc.Depth); + + mipLevel %= mipLevels; + } + + return mipLevel; +} + +UINT GetByteSize(ID3D11Texture1D *tex, int SubResource) +{ + D3D11_TEXTURE1D_DESC desc; + tex->GetDesc(&desc); + + return GetByteSize(desc.Width, 1, 1, desc.Format, SubResource%desc.MipLevels); +} + +UINT GetByteSize(ID3D11Texture2D *tex, int SubResource) +{ + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + + return GetByteSize(desc.Width, desc.Height, 1, desc.Format, SubResource%desc.MipLevels); +} + +UINT GetByteSize(ID3D11Texture3D *tex, int SubResource) +{ + D3D11_TEXTURE3D_DESC desc; + tex->GetDesc(&desc); + + return GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, SubResource); +} + +UINT GetFormatBPP(DXGI_FORMAT f) +{ + UINT ret = 8; + + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + ret *= 16; + break; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + ret *= 12; + break; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + ret *= 8; + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + ret *= 4; + break; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + ret *= 2; + break; + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + ret *= 1; + break; + case DXGI_FORMAT_R1_UNORM: + ret /= 8; + break; + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + // return block size (in bits) + ret *= 8; + break; + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + // return block size (in bits) + ret *= 16; + break; + + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + RDCERR("Video formats not supported"); + break; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + ret *= 2; // 4 channels, half a byte each + break; + + default: + RDCFATAL("Unrecognised DXGI Format: %d", f); + break; + } + + return ret; +} + +UINT GetByteSize(int Width, int Height, int Depth, DXGI_FORMAT Format, int mip) +{ + UINT ret = RDCMAX(Width>>mip, 1)*RDCMAX(Height>>mip,1)*RDCMAX(Depth>>mip,1); + + switch(Format) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + ret *= 16; + break; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + ret *= 12; + break; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + ret *= 8; + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + ret *= 4; + break; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + ret *= 2; + break; + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + ret *= 1; + break; + case DXGI_FORMAT_R1_UNORM: + ret = RDCMAX(ret/8, 1U); + break; + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + ret = AlignUp4(RDCMAX(Width>>mip, 1))* + AlignUp4(RDCMAX(Height>>mip, 1))* + RDCMAX(Depth>>mip,1); + ret /= 2; + break; + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + ret = AlignUp4(RDCMAX(Width>>mip, 1))* + AlignUp4(RDCMAX(Height>>mip, 1))* + RDCMAX(Depth>>mip,1); + ret *= 1; + break; + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + RDCERR("Video formats not supported"); + break; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + ret *= 2; // 4 channels, half a byte each + break; + default: + RDCFATAL("Unrecognised DXGI Format: %d", Format); + break; + } + + return ret; +} + +bool IsBlockFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return true; + default: + break; + } + + return false; +} + +bool IsDepthFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_D16_UNORM: + return true; + } + + return false; +} + +bool IsUIntFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R8_UINT: + return true; + } + + return false; +} + +bool IsIntFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R32G32B32_SINT: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_R8_SINT: + return true; + } + + return false; +} + +bool IsSRGBFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return true; + + default: + break; + } + + return false; +} + +DXGI_FORMAT GetDepthTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: + return DXGI_FORMAT_D32_FLOAT; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_R16_TYPELESS: + return DXGI_FORMAT_D16_UNORM; + + default: + break; + } + return f; +} + +DXGI_FORMAT GetSRGBFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + return DXGI_FORMAT_BC1_UNORM_SRGB; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + return DXGI_FORMAT_BC2_UNORM_SRGB; + + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + return DXGI_FORMAT_BC3_UNORM_SRGB; + + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + return DXGI_FORMAT_BC7_UNORM_SRGB; + + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + + default: + break; + } + return f; +} + +DXGI_FORMAT GetUnormTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_UNORM; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UINT: + return DXGI_FORMAT_R10G10B10A2_UNORM; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + return DXGI_FORMAT_R16G16_UNORM; + + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + return DXGI_FORMAT_R8G8_UNORM; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + return DXGI_FORMAT_R16_UNORM; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + return DXGI_FORMAT_R8_UNORM; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM_SRGB: + return DXGI_FORMAT_BC1_UNORM; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM_SRGB: + return DXGI_FORMAT_BC2_UNORM; + + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM_SRGB: + return DXGI_FORMAT_BC3_UNORM; + + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_SNORM: + return DXGI_FORMAT_BC4_UNORM; + + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_SNORM: + return DXGI_FORMAT_BC5_UNORM; + + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_SF16: + return DXGI_FORMAT_BC6H_UF16; + + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return DXGI_FORMAT_BC7_UNORM; + + default: + break; + } + + return f; +} + +DXGI_FORMAT GetSnormTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_SNORM; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_SNORM; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SINT: + return DXGI_FORMAT_R16G16_SNORM; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SINT: + return DXGI_FORMAT_R8G8_SNORM; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SINT: + return DXGI_FORMAT_R16_SNORM; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return DXGI_FORMAT_R8_SNORM; + + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + return DXGI_FORMAT_BC4_SNORM; + + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + return DXGI_FORMAT_BC5_SNORM; + + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + return DXGI_FORMAT_BC6H_SF16; + + default: + break; + } + + return f; +} + +DXGI_FORMAT GetUIntTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return DXGI_FORMAT_R32G32B32A32_UINT; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_SINT: + return DXGI_FORMAT_R32G32B32_UINT; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_UINT; + + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_SINT: + return DXGI_FORMAT_R32G32_UINT; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + return DXGI_FORMAT_R10G10B10A2_UINT; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_UINT; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + return DXGI_FORMAT_R16G16_UINT; + + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_SINT: + return DXGI_FORMAT_R32_UINT; + + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + return DXGI_FORMAT_X24_TYPELESS_G8_UINT; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + return DXGI_FORMAT_R8G8_UINT; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + return DXGI_FORMAT_R16_UINT; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return DXGI_FORMAT_R8_UINT; + + default: + break; + } + + return f; +} + +DXGI_FORMAT GetSIntTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + return DXGI_FORMAT_R32G32B32A32_SINT; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + return DXGI_FORMAT_R32G32B32_SINT; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + return DXGI_FORMAT_R16G16B16A16_SINT; + + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + return DXGI_FORMAT_R32G32_SINT; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + return DXGI_FORMAT_R8G8B8A8_SINT; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + return DXGI_FORMAT_R16G16_SINT; + + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + return DXGI_FORMAT_R32_SINT; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + return DXGI_FORMAT_R8G8_SINT; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + return DXGI_FORMAT_R16_SINT; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + return DXGI_FORMAT_R8_SINT; + + default: + break; + } + + return f; +} + +DXGI_FORMAT GetFloatTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R32G32B32A32_UINT: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_SINT: + case DXGI_FORMAT_R32G32B32_UINT: + return DXGI_FORMAT_R32G32B32_FLOAT; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R16G16B16A16_UINT: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G32_UINT: + return DXGI_FORMAT_R32G32_FLOAT; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UINT: + return DXGI_FORMAT_R10G10B10A2_UNORM; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + return DXGI_FORMAT_R16G16_FLOAT; + + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + return DXGI_FORMAT_R32_FLOAT; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + return DXGI_FORMAT_R8G8_UNORM; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + return DXGI_FORMAT_R16_FLOAT; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + return DXGI_FORMAT_R8_UNORM; + } + + return GetTypedFormat(f); +} + +DXGI_FORMAT GetTypedFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + return DXGI_FORMAT_R32G32B32_FLOAT; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + + case DXGI_FORMAT_R32G32_TYPELESS: + return DXGI_FORMAT_R32G32_FLOAT; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + return DXGI_FORMAT_R32G8X24_TYPELESS; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + return DXGI_FORMAT_R10G10B10A2_UNORM; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case DXGI_FORMAT_R16G16_TYPELESS: + return DXGI_FORMAT_R16G16_FLOAT; + + case DXGI_FORMAT_R32_TYPELESS: + return DXGI_FORMAT_R32_FLOAT; + + // maybe not valid casts? + case DXGI_FORMAT_R24G8_TYPELESS: + return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return DXGI_FORMAT_B8G8R8A8_UNORM; + + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + return DXGI_FORMAT_B8G8R8X8_UNORM; + + case DXGI_FORMAT_R8G8_TYPELESS: + return DXGI_FORMAT_R8G8_UNORM; + + case DXGI_FORMAT_R16_TYPELESS: + return DXGI_FORMAT_R16_UNORM; + + case DXGI_FORMAT_R8_TYPELESS: + return DXGI_FORMAT_R8_UNORM; + + case DXGI_FORMAT_BC1_TYPELESS: + return DXGI_FORMAT_BC1_UNORM; + + case DXGI_FORMAT_BC4_TYPELESS: + return DXGI_FORMAT_BC4_UNORM; + + case DXGI_FORMAT_BC2_TYPELESS: + return DXGI_FORMAT_BC2_UNORM; + + case DXGI_FORMAT_BC3_TYPELESS: + return DXGI_FORMAT_BC3_UNORM; + + case DXGI_FORMAT_BC5_TYPELESS: + return DXGI_FORMAT_BC5_UNORM; + + case DXGI_FORMAT_BC6H_TYPELESS: + return DXGI_FORMAT_BC6H_UF16; + + case DXGI_FORMAT_BC7_TYPELESS: + return DXGI_FORMAT_BC7_UNORM; + + default: + break; + } + + return f; +} + +DXGI_FORMAT GetTypelessFormat(DXGI_FORMAT f) +{ + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return DXGI_FORMAT_R32G32B32A32_TYPELESS; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return DXGI_FORMAT_R32G32B32_TYPELESS; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_TYPELESS; + + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + return DXGI_FORMAT_R32G32_TYPELESS; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return DXGI_FORMAT_R32G8X24_TYPELESS; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: // maybe not valid cast? + return DXGI_FORMAT_R10G10B10A2_TYPELESS; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_TYPELESS; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + return DXGI_FORMAT_R16G16_TYPELESS; + + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: // maybe not valid cast? + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + return DXGI_FORMAT_R32_TYPELESS; + + // maybe not valid casts? + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return DXGI_FORMAT_R24G8_TYPELESS; + + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8_B8G8_UNORM: // maybe not valid cast? + case DXGI_FORMAT_G8R8_G8B8_UNORM: // maybe not valid cast? + return DXGI_FORMAT_B8G8R8A8_TYPELESS; + + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return DXGI_FORMAT_B8G8R8X8_TYPELESS; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + return DXGI_FORMAT_R8G8_TYPELESS; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + return DXGI_FORMAT_R16_TYPELESS; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return DXGI_FORMAT_R8_TYPELESS; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + return DXGI_FORMAT_BC1_TYPELESS; + + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return DXGI_FORMAT_BC4_TYPELESS; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + return DXGI_FORMAT_BC2_TYPELESS; + + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + return DXGI_FORMAT_BC3_TYPELESS; + + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + return DXGI_FORMAT_BC5_TYPELESS; + + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + return DXGI_FORMAT_BC6H_TYPELESS; + + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return DXGI_FORMAT_BC7_TYPELESS; + + case DXGI_FORMAT_R1_UNORM: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + case DXGI_FORMAT_B4G4R4A4_UNORM: + RDCERR("No Typeless DXGI Format for %d", f); + break; + + default: + RDCFATAL("Unrecognised DXGI Format: %d", f); + break; + } + + return DXGI_FORMAT_UNKNOWN; +} + +string ToStrHelper::Get(const ResourceType &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(Resource_InputLayout) + TOSTR_CASE_STRINGIZE(Resource_Buffer) + TOSTR_CASE_STRINGIZE(Resource_Texture1D) + TOSTR_CASE_STRINGIZE(Resource_Texture2D) + TOSTR_CASE_STRINGIZE(Resource_Texture3D) + TOSTR_CASE_STRINGIZE(Resource_RasterizerState) + TOSTR_CASE_STRINGIZE(Resource_RasterizerState1) + TOSTR_CASE_STRINGIZE(Resource_BlendState) + TOSTR_CASE_STRINGIZE(Resource_BlendState1) + TOSTR_CASE_STRINGIZE(Resource_DepthStencilState) + TOSTR_CASE_STRINGIZE(Resource_SamplerState) + TOSTR_CASE_STRINGIZE(Resource_RenderTargetView) + TOSTR_CASE_STRINGIZE(Resource_ShaderResourceView) + TOSTR_CASE_STRINGIZE(Resource_DepthStencilView) + TOSTR_CASE_STRINGIZE(Resource_Shader) + TOSTR_CASE_STRINGIZE(Resource_UnorderedAccessView) + TOSTR_CASE_STRINGIZE(Resource_Counter) + TOSTR_CASE_STRINGIZE(Resource_Query) + TOSTR_CASE_STRINGIZE(Resource_Predicate) + TOSTR_CASE_STRINGIZE(Resource_ClassInstance) + TOSTR_CASE_STRINGIZE(Resource_ClassLinkage) + + TOSTR_CASE_STRINGIZE(Resource_DeviceContext) + TOSTR_CASE_STRINGIZE(Resource_CommandList) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "ResourceType<%d>", el); + + return tostrBuf; +} + +ResourceId GetIDForResource(ID3D11DeviceChild *ptr) +{ + if(ptr == NULL) + return ResourceId(); + + if(WrappedID3D11InputLayout::IsAlloc(ptr)) + return ((WrappedID3D11InputLayout *)ptr)->GetResourceID(); + + if(WrappedID3D11Shader::IsAlloc(ptr)) + return ((WrappedID3D11Shader *)ptr)->GetResourceID(); + if(WrappedID3D11Shader::IsAlloc(ptr)) + return ((WrappedID3D11Shader *)ptr)->GetResourceID(); + if(WrappedID3D11Shader::IsAlloc(ptr)) + return ((WrappedID3D11Shader *)ptr)->GetResourceID(); + if(WrappedID3D11Shader::IsAlloc(ptr)) + return ((WrappedID3D11Shader *)ptr)->GetResourceID(); + if(WrappedID3D11Shader::IsAlloc(ptr)) + return ((WrappedID3D11Shader *)ptr)->GetResourceID(); + if(WrappedID3D11Shader::IsAlloc(ptr)) + return ((WrappedID3D11Shader *)ptr)->GetResourceID(); + + if(WrappedID3D11Buffer::IsAlloc(ptr)) + return ((WrappedID3D11Buffer *)ptr)->GetResourceID(); + + if(WrappedID3D11Texture1D::IsAlloc(ptr)) + return ((WrappedID3D11Texture1D *)ptr)->GetResourceID(); + if(WrappedID3D11Texture2D::IsAlloc(ptr)) + return ((WrappedID3D11Texture2D *)ptr)->GetResourceID(); + if(WrappedID3D11Texture3D::IsAlloc(ptr)) + return ((WrappedID3D11Texture3D *)ptr)->GetResourceID(); + + if(WrappedID3D11RasterizerState::IsAlloc(ptr)) + return ((WrappedID3D11RasterizerState *)ptr)->GetResourceID(); + if(WrappedID3D11BlendState::IsAlloc(ptr)) + return ((WrappedID3D11BlendState *)ptr)->GetResourceID(); + if(WrappedID3D11RasterizerState1::IsAlloc(ptr)) + return ((WrappedID3D11RasterizerState1 *)ptr)->GetResourceID(); + if(WrappedID3D11BlendState1::IsAlloc(ptr)) + return ((WrappedID3D11BlendState1 *)ptr)->GetResourceID(); + if(WrappedID3D11DepthStencilState::IsAlloc(ptr)) + return ((WrappedID3D11DepthStencilState *)ptr)->GetResourceID(); + if(WrappedID3D11SamplerState::IsAlloc(ptr)) + return ((WrappedID3D11SamplerState *)ptr)->GetResourceID(); + + if(WrappedID3D11RenderTargetView::IsAlloc(ptr)) + return ((WrappedID3D11RenderTargetView *)ptr)->GetResourceID(); + if(WrappedID3D11ShaderResourceView::IsAlloc(ptr)) + return ((WrappedID3D11ShaderResourceView *)ptr)->GetResourceID(); + if(WrappedID3D11DepthStencilView::IsAlloc(ptr)) + return ((WrappedID3D11DepthStencilView *)ptr)->GetResourceID(); + if(WrappedID3D11UnorderedAccessView::IsAlloc(ptr)) + return ((WrappedID3D11UnorderedAccessView *)ptr)->GetResourceID(); + + if(WrappedID3D11Counter::IsAlloc(ptr)) + return ((WrappedID3D11Counter *)ptr)->GetResourceID(); + if(WrappedID3D11Query::IsAlloc(ptr)) + return ((WrappedID3D11Query *)ptr)->GetResourceID(); + if(WrappedID3D11Predicate::IsAlloc(ptr)) + return ((WrappedID3D11Predicate *)ptr)->GetResourceID(); + + if(WrappedID3D11ClassInstance::IsAlloc(ptr)) + return ((WrappedID3D11ClassInstance *)ptr)->GetResourceID(); + if(WrappedID3D11ClassLinkage::IsAlloc(ptr)) + return ((WrappedID3D11ClassLinkage *)ptr)->GetResourceID(); + + if(WrappedID3D11DeviceContext::IsAlloc(ptr)) + return ((WrappedID3D11DeviceContext *)ptr)->GetResourceID(); + if(WrappedID3D11CommandList::IsAlloc(ptr)) + return ((WrappedID3D11CommandList *)ptr)->GetResourceID(); + + RDCERR("Unknown type for ptr 0x%p", ptr); + + return ResourceId(); +} + +ResourceType IdentifyTypeByPtr(IUnknown *ptr) +{ + if(WrappedID3D11InputLayout::IsAlloc(ptr)) + return Resource_InputLayout; + + if(WrappedID3D11Shader::IsAlloc(ptr) || + WrappedID3D11Shader::IsAlloc(ptr) || + WrappedID3D11Shader::IsAlloc(ptr) || + WrappedID3D11Shader::IsAlloc(ptr) || + WrappedID3D11Shader::IsAlloc(ptr) || + WrappedID3D11Shader::IsAlloc(ptr)) + return Resource_Shader; + + if(WrappedID3D11Buffer::IsAlloc(ptr)) + return Resource_Buffer; + + if(WrappedID3D11Texture1D::IsAlloc(ptr)) + return Resource_Texture1D; + if(WrappedID3D11Texture2D::IsAlloc(ptr)) + return Resource_Texture2D; + if(WrappedID3D11Texture3D::IsAlloc(ptr)) + return Resource_Texture3D; + + if(WrappedID3D11RasterizerState::IsAlloc(ptr)) + return Resource_RasterizerState; + if(WrappedID3D11BlendState::IsAlloc(ptr)) + return Resource_BlendState; + if(WrappedID3D11RasterizerState1::IsAlloc(ptr)) + return Resource_RasterizerState1; + if(WrappedID3D11BlendState1::IsAlloc(ptr)) + return Resource_BlendState1; + if(WrappedID3D11DepthStencilState::IsAlloc(ptr)) + return Resource_DepthStencilState; + if(WrappedID3D11SamplerState::IsAlloc(ptr)) + return Resource_SamplerState; + + if(WrappedID3D11RenderTargetView::IsAlloc(ptr)) + return Resource_RenderTargetView; + if(WrappedID3D11ShaderResourceView::IsAlloc(ptr)) + return Resource_ShaderResourceView; + if(WrappedID3D11DepthStencilView::IsAlloc(ptr)) + return Resource_DepthStencilView; + if(WrappedID3D11UnorderedAccessView::IsAlloc(ptr)) + return Resource_UnorderedAccessView; + + if(WrappedID3D11Counter::IsAlloc(ptr)) + return Resource_Counter; + if(WrappedID3D11Query::IsAlloc(ptr)) + return Resource_Query; + if(WrappedID3D11Predicate::IsAlloc(ptr)) + return Resource_Predicate; + + if(WrappedID3D11ClassInstance::IsAlloc(ptr)) + return Resource_ClassInstance; + if(WrappedID3D11ClassLinkage::IsAlloc(ptr)) + return Resource_ClassLinkage; + + if(WrappedID3D11DeviceContext::IsAlloc(ptr)) + return Resource_DeviceContext; + if(WrappedID3D11CommandList::IsAlloc(ptr)) + return Resource_CommandList; + + RDCERR("Unknown type for ptr 0x%p", ptr); + + return Resource_Unknown; +} + +HRESULT STDMETHODCALLTYPE RefCounter::QueryInterface( + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + __RPC__deref_out void **ppvObject) +{ + return RefCountDXGIObject::WrapQueryInterface(m_pReal, riid, ppvObject); +} + +unsigned int RefCounter::SoftRef(WrappedID3D11Device *device) +{ + unsigned int ret = AddRef(); + device->SoftRef(); + return ret; +} + +unsigned int RefCounter::SoftRelease(WrappedID3D11Device *device) +{ + unsigned int ret = Release(); + device->SoftRelease(); + return ret; +} + +void RefCounter::AddDeviceSoftref(WrappedID3D11Device *device) +{ + device->SoftRef(); +} + +void RefCounter::ReleaseDeviceSoftref(WrappedID3D11Device *device) +{ + device->SoftRelease(); +} \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_resources.h b/renderdoc/driver/d3d11/d3d11_resources.h new file mode 100644 index 0000000000..51a4ab4884 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_resources.h @@ -0,0 +1,1420 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "driver/d3d11/d3d11_device.h" +#include "driver/d3d11/d3d11_manager.h" +#include "shaders/dxbc_inspect.h" +#include + +enum ResourceType +{ + Resource_Unknown = 0, + Resource_InputLayout, + Resource_Buffer, + Resource_Texture1D, + Resource_Texture2D, + Resource_Texture3D, + Resource_RasterizerState, + Resource_RasterizerState1, + Resource_BlendState, + Resource_BlendState1, + Resource_DepthStencilState, + Resource_SamplerState, + Resource_RenderTargetView, + Resource_ShaderResourceView, + Resource_DepthStencilView, + Resource_UnorderedAccessView, + Resource_Shader, + Resource_Counter, + Resource_Query, + Resource_Predicate, + Resource_ClassInstance, + Resource_ClassLinkage, + + Resource_DeviceContext, + Resource_CommandList, +}; + +ResourceType IdentifyTypeByPtr(IUnknown *ptr); +ResourceId GetIDForResource(ID3D11DeviceChild *ptr); + +UINT GetByteSize(int Width, int Height, int Depth, DXGI_FORMAT Format, int mip); +UINT GetByteSize(ID3D11Texture1D *tex, int SubResource); +UINT GetByteSize(ID3D11Texture2D *tex, int SubResource); +UINT GetByteSize(ID3D11Texture3D *tex, int SubResource); + +UINT CalcNumMips(int Width, int Height, int Depth); + +UINT GetMipForSubresource(ID3D11Resource *res, int Subresource); + +// returns block size for block-compressed formats +UINT GetFormatBPP(DXGI_FORMAT f); + +DXGI_FORMAT GetTypelessFormat(DXGI_FORMAT f); +DXGI_FORMAT GetTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetDepthTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetFloatTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetUnormTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetSnormTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetUIntTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetSIntTypedFormat(DXGI_FORMAT f); +DXGI_FORMAT GetSRGBFormat(DXGI_FORMAT f); +bool IsBlockFormat(DXGI_FORMAT f); +bool IsDepthFormat(DXGI_FORMAT f); + +bool IsUIntFormat(DXGI_FORMAT f); +bool IsIntFormat(DXGI_FORMAT f); +bool IsSRGBFormat(DXGI_FORMAT f); + +class TrackedResource +{ + public: + TrackedResource() + { + m_ID = GetNewUniqueID(); + } + + ResourceId GetResourceID() { return m_ID; } + + static void SetReplayResourceIDs() + { + globalIDCounter = RDCMAX(uint64_t(globalIDCounter), uint64_t(globalIDCounter|0x1000000000000000ULL)); + } + + private: + TrackedResource(const TrackedResource &); + TrackedResource &operator =(const TrackedResource &); + + ResourceId GetNewUniqueID() + { + uint64_t newID = (uint64_t)InterlockedIncrement64(&globalIDCounter); + + return ResourceId(newID, true); // bool to make explicit + } + + static volatile LONGLONG globalIDCounter; + ResourceId m_ID; +}; + +template +class WrappedDXGIInterface : public RefCounter, public IDXGISurface2, public IDXGIKeyedMutex, public IDXGIResource1 +{ +public: + WrappedID3D11Device* m_pDevice; + NestedType* m_pWrapped; + + WrappedDXGIInterface(NestedType* wrapped, WrappedID3D11Device* device) + : RefCounter(NULL), + m_pDevice(device), + m_pWrapped(wrapped) + { + m_pWrapped->AddRef(); + m_pDevice->AddRef(); + } + + virtual ~WrappedDXGIInterface() + { + m_pWrapped->Release(); + m_pDevice->Release(); + } + + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter::Release(); } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IDXGIObject)) + { + *ppvObject = (IDXGIObject *)(IDXGIKeyedMutex *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGIDeviceSubObject)) + { + *ppvObject = (IDXGIDeviceSubObject *)(IDXGIKeyedMutex *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGIResource)) + { + *ppvObject = (IDXGIResource *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGIResource1)) + { + *ppvObject = (IDXGIResource1 *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGIKeyedMutex)) + { + *ppvObject = (IDXGIKeyedMutex *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGISurface)) + { + *ppvObject = (IDXGISurface *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGISurface1)) + { + *ppvObject = (IDXGISurface1 *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(IDXGISurface2)) + { + *ppvObject = (IDXGISurface2 *)this; + AddRef(); + return S_OK; + } + + return m_pWrapped->QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // Implement IDXGIObject + HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID Name, UINT DataSize, const void *pData) + { return m_pWrapped->SetPrivateData(Name, DataSize, pData); } + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID Name, const IUnknown *pUnknown) + { return m_pWrapped->SetPrivateDataInterface(Name, pUnknown); } + + HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID Name, UINT *pDataSize, void *pData) + { return m_pWrapped->GetPrivateData(Name, pDataSize, pData); } + + // this should only be called for adapters, devices, factories etc + // so we pass it onto the device + HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void **ppParent) + { + return m_pDevice->QueryInterface(riid, ppParent); + } + + ////////////////////////////// + // Implement IDXGIDeviceSubObject + + // same as GetParent + HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, void **ppDevice) + { + return m_pDevice->QueryInterface(riid, ppDevice); + } + + ////////////////////////////// + // Implement IDXGIKeyedMutex + HRESULT STDMETHODCALLTYPE AcquireSync(UINT64 Key, DWORD dwMilliseconds) + { + // temporarily get the real interface + IDXGIKeyedMutex *mutex = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)&mutex); + if(FAILED(hr)) + { + SAFE_RELEASE(mutex); + return hr; + } + + hr = mutex->AcquireSync(Key, dwMilliseconds); + SAFE_RELEASE(mutex); + return hr; + } + + HRESULT STDMETHODCALLTYPE ReleaseSync(UINT64 Key) + { + // temporarily get the real interface + IDXGIKeyedMutex *mutex = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)&mutex); + if(FAILED(hr)) + { + SAFE_RELEASE(mutex); + return hr; + } + + hr = mutex->ReleaseSync(Key); + SAFE_RELEASE(mutex); + return hr; + } + + ////////////////////////////// + // Implement IDXGIResource + virtual HRESULT STDMETHODCALLTYPE GetSharedHandle(HANDLE *pSharedHandle) + { + // temporarily get the real interface + IDXGIResource *res = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIResource), (void **)&res); + if(FAILED(hr)) + { + SAFE_RELEASE(res); + return hr; + } + + hr = res->GetSharedHandle(pSharedHandle); + SAFE_RELEASE(res); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE GetUsage(DXGI_USAGE *pUsage) + { + // temporarily get the real interface + IDXGIResource *res = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIResource), (void **)&res); + if(FAILED(hr)) + { + SAFE_RELEASE(res); + return hr; + } + + hr = res->GetUsage(pUsage); + SAFE_RELEASE(res); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) + { + // temporarily get the real interface + IDXGIResource *res = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIResource), (void **)&res); + if(FAILED(hr)) + { + SAFE_RELEASE(res); + return hr; + } + + hr = res->SetEvictionPriority(EvictionPriority); + SAFE_RELEASE(res); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE GetEvictionPriority(UINT *pEvictionPriority) + { + // temporarily get the real interface + IDXGIResource *res = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIResource), (void **)&res); + if(FAILED(hr)) + { + SAFE_RELEASE(res); + return hr; + } + + hr = res->GetEvictionPriority(pEvictionPriority); + SAFE_RELEASE(res); + return hr; + } + + ////////////////////////////// + // Implement IDXGIResource1 + virtual HRESULT STDMETHODCALLTYPE CreateSubresourceSurface(UINT index, IDXGISurface2 **ppSurface) + { + if(ppSurface == NULL) return E_INVALIDARG; + + // maybe this will work?!? + AddRef(); + *ppSurface = (IDXGISurface2 *)this; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateSharedHandle(const SECURITY_ATTRIBUTES *pAttributes, DWORD dwAccess, LPCWSTR lpName, HANDLE *pHandle) + { + // temporarily get the real interface + IDXGIResource1 *res = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGIResource1), (void **)&res); + if(FAILED(hr)) + { + SAFE_RELEASE(res); + return hr; + } + + hr = res->CreateSharedHandle(pAttributes, dwAccess, lpName, pHandle); + SAFE_RELEASE(res); + return hr; + } + + ////////////////////////////// + // Implement IDXGISurface + virtual HRESULT STDMETHODCALLTYPE GetDesc(DXGI_SURFACE_DESC *pDesc) + { + // temporarily get the real interface + IDXGISurface *surf = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGISurface), (void **)&surf); + if(FAILED(hr)) + { + SAFE_RELEASE(surf); + return hr; + } + + hr = surf->GetDesc(pDesc); + SAFE_RELEASE(surf); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE Map(DXGI_MAPPED_RECT *pLockedRect, UINT MapFlags) + { + // temporarily get the real interface + IDXGISurface *surf = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGISurface), (void **)&surf); + if(FAILED(hr)) + { + SAFE_RELEASE(surf); + return hr; + } + + hr = surf->Map(pLockedRect, MapFlags); + SAFE_RELEASE(surf); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE Unmap( void) + { + // temporarily get the real interface + IDXGISurface *surf = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGISurface), (void **)&surf); + if(FAILED(hr)) + { + SAFE_RELEASE(surf); + return hr; + } + + hr = surf->Unmap(); + SAFE_RELEASE(surf); + return hr; + } + + ////////////////////////////// + // Implement IDXGISurface1 + virtual HRESULT STDMETHODCALLTYPE GetDC(BOOL Discard, HDC *phdc) + { + // temporarily get the real interface + IDXGISurface1 *surf = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGISurface1), (void **)&surf); + if(FAILED(hr)) + { + SAFE_RELEASE(surf); + return hr; + } + + hr = surf->GetDC(Discard, phdc); + SAFE_RELEASE(surf); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE ReleaseDC(RECT *pDirtyRect) + { + // temporarily get the real interface + IDXGISurface1 *surf = NULL; + HRESULT hr = m_pWrapped->GetReal()->QueryInterface(__uuidof(IDXGISurface1), (void **)&surf); + if(FAILED(hr)) + { + SAFE_RELEASE(surf); + return hr; + } + + hr = surf->ReleaseDC(pDirtyRect); + SAFE_RELEASE(surf); + return hr; + } + + ////////////////////////////// + // Implement IDXGISurface2 + virtual HRESULT STDMETHODCALLTYPE GetResource(REFIID riid, void **ppParentResource, UINT *pSubresourceIndex) + { + // not really sure how to implement this :(. + if(pSubresourceIndex) pSubresourceIndex = 0; + return QueryInterface(riid, ppParentResource); + } +}; + +template +class WrappedDeviceChild : public RefCounter, public NestedType, public TrackedResource +{ +protected: + WrappedID3D11Device* m_pDevice; + NestedType* m_pReal; + + WrappedDeviceChild(NestedType* real, WrappedID3D11Device* device) + : RefCounter(real), + m_pDevice(device), + m_pReal(real) + { + m_pDevice->SoftRef(); + m_pDevice->GetResourceManager()->AddWrapper(this, real); + m_pDevice->GetResourceManager()->AddCurrentResource(GetResourceID(), this); + } + + virtual void Shutdown() + { + m_pDevice->GetResourceManager()->RemoveWrapper(m_pReal); + m_pDevice->GetResourceManager()->ReleaseCurrentResource(GetResourceID()); + m_pDevice->ReleaseResource((NestedType*)this); + SAFE_RELEASE(m_pReal); + m_pDevice = NULL; + } + + virtual ~WrappedDeviceChild() + { + // should have already called shutdown (needs to be called from child class to ensure + // vtables are still in place when we call ReleaseResource) + RDCASSERT(m_pDevice == NULL && m_pReal == NULL); + } + +public: + typedef NestedType InnerType; + + NestedType* GetReal() { return m_pReal; } + + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter::SoftRef(m_pDevice); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter::SoftRelease(m_pDevice); } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(NestedType)) + { + *ppvObject = (NestedType *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D11DeviceChild)) + { + *ppvObject = (ID3D11DeviceChild *)this; + AddRef(); + return S_OK; + } + + // for DXGI object queries, just make a new throw-away WrappedDXGIObject + // and return. + if(riid == __uuidof(IDXGIObject) || + riid == __uuidof(IDXGIDeviceSubObject) || + riid == __uuidof(IDXGIResource) || + riid == __uuidof(IDXGIResource1) || + riid == __uuidof(IDXGIKeyedMutex) || + riid == __uuidof(IDXGISurface) || + riid == __uuidof(IDXGISurface1) || + riid == __uuidof(IDXGISurface2) + ) + { + // ensure the real object has this interface + void *outObj; + HRESULT hr = m_pReal->QueryInterface(riid, &outObj); + + IUnknown *unk = (IUnknown *)outObj; + SAFE_RELEASE(unk); + + if(FAILED(hr)) + { + return hr; + } + + auto dxgiWrapper = new WrappedDXGIInterface< WrappedDeviceChild >(this, m_pDevice); + + // anything could happen outside of our wrapped ecosystem, so immediately mark dirty + m_pDevice->GetResourceManager()->MarkDirtyResource(GetResourceID()); + + if(riid == __uuidof(IDXGIObject)) *ppvObject = (IDXGIObject *)(IDXGIKeyedMutex *)dxgiWrapper; + else if(riid == __uuidof(IDXGIDeviceSubObject)) *ppvObject = (IDXGIDeviceSubObject *)(IDXGIKeyedMutex *)dxgiWrapper; + else if(riid == __uuidof(IDXGIResource)) *ppvObject = (IDXGIResource *)dxgiWrapper; + else if(riid == __uuidof(IDXGIResource1)) *ppvObject = (IDXGIResource1 *)dxgiWrapper; + else if(riid == __uuidof(IDXGIKeyedMutex)) *ppvObject = (IDXGIKeyedMutex *)dxgiWrapper; + else if(riid == __uuidof(IDXGISurface)) *ppvObject = (IDXGISurface *)dxgiWrapper; + else if(riid == __uuidof(IDXGISurface1)) *ppvObject = (IDXGISurface1 *)dxgiWrapper; + else if(riid == __uuidof(IDXGISurface2)) *ppvObject = (IDXGISurface2 *)dxgiWrapper; + + return S_OK; + } + + return RefCounter::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D11DeviceChild + + void STDMETHODCALLTYPE GetDevice( + /* [annotation] */ + __out ID3D11Device **ppDevice) + { + if(ppDevice) + { + *ppDevice = m_pDevice; + m_pDevice->AddRef(); + } + } + + HRESULT STDMETHODCALLTYPE GetPrivateData( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __inout UINT *pDataSize, + /* [annotation] */ + __out_bcount_opt( *pDataSize ) void *pData) + { + return m_pReal->GetPrivateData(guid, pDataSize, pData); + } + + HRESULT STDMETHODCALLTYPE SetPrivateData( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __in UINT DataSize, + /* [annotation] */ + __in_bcount_opt( DataSize ) const void *pData) + { + if(guid == WKPDID_D3DDebugObjectName) + m_pDevice->SetResourceName(this, (const char *)pData); + return m_pReal->SetPrivateData(guid, DataSize, pData); + } + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + /* [annotation] */ + __in REFGUID guid, + /* [annotation] */ + __in_opt const IUnknown *pData) + { + return m_pReal->SetPrivateDataInterface(guid, pData); + } +}; + +template +class WrappedResource : public WrappedDeviceChild +{ +private: + unsigned int m_ViewRefcount; // refcount from views (invisible to the end-user) + +protected: +#if !defined(RELEASE) + DescType m_Desc; +#endif + + WrappedResource(NestedType* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device), + m_ViewRefcount(0) + { +#if !defined(RELEASE) + real->GetDesc(&m_Desc); +#endif + + // we'll handle deleting on release, so we can check against m_ViewRefcount + RefCounter::SetSelfDeleting(false); + } + + virtual void Shutdown() + { + WrappedDeviceChild::Shutdown(); + } + + virtual ~WrappedResource() + { + } + +public: +#if !defined(RELEASE) + DescType& GetDescDirect() { return m_Desc; } +#endif + + void ViewAddRef() + { + InterlockedIncrement(&m_ViewRefcount); + + RefCounter::AddDeviceSoftref(m_pDevice); + } + + void ViewRelease() + { + unsigned int viewRefCount = InterlockedDecrement(&m_ViewRefcount); + unsigned int extRefCount = RefCounter::GetRefCount(); + + WrappedID3D11Device *dev = m_pDevice; + + if(extRefCount == 0 && m_ViewRefcount == 0) + delete this; + + RefCounter::ReleaseDeviceSoftref(dev); + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return RefCounter::SoftRef(m_pDevice); + } + + ULONG STDMETHODCALLTYPE Release() + { + unsigned int extRefCount = RefCounter::Release(); + + WrappedID3D11Device *dev = m_pDevice; + + if(extRefCount == 0 && m_ViewRefcount == 0) + delete this; + + RefCounter::ReleaseDeviceSoftref(dev); + + return extRefCount; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(ID3D11Resource)) + { + *ppvObject = (ID3D11Resource *)this; + AddRef(); + return S_OK; + } + + return WrappedDeviceChild::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D11Resource + + virtual void STDMETHODCALLTYPE GetType( + /* [annotation] */ + __out D3D11_RESOURCE_DIMENSION *pResourceDimension) + { + m_pReal->GetType(pResourceDimension); + } + + virtual void STDMETHODCALLTYPE SetEvictionPriority( + /* [annotation] */ + __in UINT EvictionPriority) + { + m_pReal->SetEvictionPriority(EvictionPriority); + } + + virtual UINT STDMETHODCALLTYPE GetEvictionPriority( void) + { + return m_pReal->GetEvictionPriority(); + } + + ////////////////////////////// + // implement NestedType + + virtual void STDMETHODCALLTYPE GetDesc( + /* [annotation] */ + __out DescType *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11Buffer : public WrappedResource +{ +public: + struct BufferEntry + { + BufferEntry(WrappedID3D11Buffer *b = NULL, uint32_t l = 0) : m_Buffer(b), length(l) { } + WrappedID3D11Buffer *m_Buffer; + uint32_t length; + }; + + static map m_BufferList; + + static const int AllocPoolCount = 128*1024; + static const int AllocPoolMaxByteSize = 11*1024*1024; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Buffer, AllocPoolCount, AllocPoolMaxByteSize); + + WrappedID3D11Buffer(ID3D11Buffer* real, uint32_t byteLength, WrappedID3D11Device* device) + : WrappedResource(real, device) + { + RDCASSERT(m_BufferList.find(GetResourceID()) == m_BufferList.end()); + m_BufferList[GetResourceID()] = BufferEntry(this, byteLength); + } + + virtual ~WrappedID3D11Buffer() + { + if(m_BufferList.find(GetResourceID()) != m_BufferList.end()) + m_BufferList.erase(GetResourceID()); + + Shutdown(); + } + + virtual void STDMETHODCALLTYPE GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) + { + if(pResourceDimension) *pResourceDimension = D3D11_RESOURCE_DIMENSION_BUFFER; + } +}; + +template +class WrappedTexture : public WrappedResource +{ +public: + struct TextureEntry + { + TextureEntry(NestedType *t = NULL, TextureDisplayType ty = TEXDISPLAY_UNKNOWN) : m_Texture(t), m_Type(ty) {} + NestedType *m_Texture; + TextureDisplayType m_Type; + }; + + static map m_TextureList; + + WrappedTexture(NestedType* real, WrappedID3D11Device* device, TextureDisplayType type) + : WrappedResource(real, device) + { + if(type != TEXDISPLAY_UNKNOWN) + { + RDCASSERT(m_TextureList.find(GetResourceID()) == m_TextureList.end()); + m_TextureList[GetResourceID()] = TextureEntry(this, type); + } + } + + virtual ~WrappedTexture() + { + if(m_TextureList.find(GetResourceID()) != m_TextureList.end()) + m_TextureList.erase(GetResourceID()); + + Shutdown(); + } +}; + +class WrappedID3D11Texture1D : public WrappedTexture +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Texture1D); + + WrappedID3D11Texture1D(ID3D11Texture1D* real, WrappedID3D11Device* device, TextureDisplayType type = TEXDISPLAY_SRV_COMPATIBLE) + : WrappedTexture(real, device, type) {} + virtual ~WrappedID3D11Texture1D() {} + + virtual void STDMETHODCALLTYPE GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) + { + if(pResourceDimension) *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE1D; + } +}; + +class WrappedID3D11Texture2D : public WrappedTexture +{ +public: + static const int AllocPoolCount = 32768; + static const int AllocPoolMaxByteSize = 4*1024*1024; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Texture2D, AllocPoolCount, AllocPoolMaxByteSize); + + WrappedID3D11Texture2D(ID3D11Texture2D* real, WrappedID3D11Device* device, TextureDisplayType type = TEXDISPLAY_SRV_COMPATIBLE) + : WrappedTexture(real, device, type) + { + m_RealDescriptor = NULL; + } + virtual ~WrappedID3D11Texture2D() + { + SAFE_DELETE(m_RealDescriptor); + } + + // for backbuffer textures they behave a little differently from every other texture in D3D11 + // as they can be cast from one type to another, whereas normally you need to declare as typeless + // and then cast to a type. To simulate this on our fake backbuffer textures I create them as + // typeless, HOWEVER this means if we try to create a view with a NULL descriptor then we need + // the real original type. + D3D11_TEXTURE2D_DESC *m_RealDescriptor; + + virtual void STDMETHODCALLTYPE GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) + { + if(pResourceDimension) *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; + } +}; + +class WrappedID3D11Texture3D : public WrappedTexture +{ +public: + static const int AllocPoolCount = 16384; + static const int AllocPoolMaxByteSize = 2*1024*1024; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Texture3D, AllocPoolCount, AllocPoolMaxByteSize); + + WrappedID3D11Texture3D(ID3D11Texture3D* real, WrappedID3D11Device* device, TextureDisplayType type = TEXDISPLAY_SRV_COMPATIBLE) + : WrappedTexture(real, device, type) {} + virtual ~WrappedID3D11Texture3D() {} + + virtual void STDMETHODCALLTYPE GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) + { + if(pResourceDimension) *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE3D; + } +}; + +class WrappedID3D11InputLayout : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11InputLayout); + + WrappedID3D11InputLayout(ID3D11InputLayout* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11InputLayout() { Shutdown(); } +}; + +class WrappedID3D11RasterizerState : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11RasterizerState); + + WrappedID3D11RasterizerState(ID3D11RasterizerState* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11RasterizerState() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11RasterizerState + + virtual void STDMETHODCALLTYPE GetDesc(D3D11_RASTERIZER_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11RasterizerState1 : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11RasterizerState1); + + WrappedID3D11RasterizerState1(ID3D11RasterizerState1* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11RasterizerState1() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11RasterizerStat1 + + virtual void STDMETHODCALLTYPE GetDesc(D3D11_RASTERIZER_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } + + ////////////////////////////// + // implement ID3D11RasterizerState1 + + virtual void STDMETHODCALLTYPE GetDesc1(D3D11_RASTERIZER_DESC1 *pDesc) + { + m_pReal->GetDesc1(pDesc); + } +}; + +class WrappedID3D11BlendState : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11BlendState); + + WrappedID3D11BlendState(ID3D11BlendState* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11BlendState() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11BlendState + + virtual void STDMETHODCALLTYPE GetDesc(D3D11_BLEND_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11BlendState1 : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11BlendState1); + + WrappedID3D11BlendState1(ID3D11BlendState1* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11BlendState1() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11BlendState + + virtual void STDMETHODCALLTYPE GetDesc(D3D11_BLEND_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } + + ////////////////////////////// + // implement ID3D11BlendState1 + + virtual void STDMETHODCALLTYPE GetDesc1(D3D11_BLEND_DESC1 *pDesc) + { + m_pReal->GetDesc1(pDesc); + } +}; + +class WrappedID3D11DepthStencilState : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11DepthStencilState); + + WrappedID3D11DepthStencilState(ID3D11DepthStencilState* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11DepthStencilState() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11DepthStencilState + + virtual void STDMETHODCALLTYPE GetDesc(D3D11_DEPTH_STENCIL_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11SamplerState : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11SamplerState); + + WrappedID3D11SamplerState(ID3D11SamplerState* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11SamplerState() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11SamplerState + + virtual void STDMETHODCALLTYPE GetDesc(D3D11_SAMPLER_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +template +class WrappedView : public WrappedDeviceChild +{ +protected: + ID3D11Resource *m_pResource; + D3D11ResourceRecord *m_pResourceRecord; + ResourceId m_ResourceResID; + + WrappedView(NestedType* real, WrappedID3D11Device* device, ID3D11Resource* res) + : WrappedDeviceChild(real, device), + m_pResource(res), + m_pResourceRecord(NULL) + { + m_ResourceResID = GetIDForResource(m_pResource); + // cast is potentially invalid but functions in WrappedResource will be identical across each + ((WrappedID3D11Buffer *)m_pResource)->ViewAddRef(); + } + + virtual void Shutdown() + { + WrappedDeviceChild::Shutdown(); + // cast is potentially invalid but functions in WrappedResource will be identical across each + ((WrappedID3D11Buffer *)m_pResource)->ViewRelease(); + m_pResource = NULL; + } + + virtual ~WrappedView() + { + } + +public: + D3D11ResourceRecord *GetResourceRecord() { return m_pResourceRecord; } + void SetResourceRecord(D3D11ResourceRecord *r) { m_pResourceRecord = r; } + + ResourceId GetResourceResID() { return m_ResourceResID; } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(ID3D11View)) + { + *ppvObject = (ID3D11View *)this; + AddRef(); + return S_OK; + } + + return WrappedDeviceChild::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D11View + + void STDMETHODCALLTYPE GetResource( + /* [annotation] */ + __out ID3D11Resource **pResource) + { + RDCASSERT(m_pResource); + if(pResource) + *pResource = m_pResource; + m_pResource->AddRef(); + } + + ////////////////////////////// + // implement NestedType + + void STDMETHODCALLTYPE GetDesc( + /* [annotation] */ + __out DescType *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11RenderTargetView : public WrappedView +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11RenderTargetView); + + WrappedID3D11RenderTargetView(ID3D11RenderTargetView* real, ID3D11Resource* res, WrappedID3D11Device* device) + : WrappedView(real, device, res) {} + virtual ~WrappedID3D11RenderTargetView() { Shutdown(); } +}; + +class WrappedID3D11ShaderResourceView : public WrappedView +{ +public: + static const int AllocPoolCount = 65535; + static const int AllocPoolMaxByteSize = 5*1024*1024; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11ShaderResourceView, AllocPoolCount, AllocPoolMaxByteSize); + + WrappedID3D11ShaderResourceView(ID3D11ShaderResourceView* real, ID3D11Resource* res, WrappedID3D11Device* device) + : WrappedView(real, device, res) {} + virtual ~WrappedID3D11ShaderResourceView() { Shutdown(); } +}; + +class WrappedID3D11DepthStencilView : public WrappedView +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11DepthStencilView); + + WrappedID3D11DepthStencilView(ID3D11DepthStencilView* real, ID3D11Resource* res, WrappedID3D11Device* device) + : WrappedView(real, device, res) {} + virtual ~WrappedID3D11DepthStencilView() { Shutdown(); } +}; + +class WrappedID3D11UnorderedAccessView : public WrappedView +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11UnorderedAccessView); + + WrappedID3D11UnorderedAccessView(ID3D11UnorderedAccessView* real, ID3D11Resource* res, WrappedID3D11Device* device) + : WrappedView(real, device, res) {} + virtual ~WrappedID3D11UnorderedAccessView() { Shutdown(); } +}; + +class WrappedShader +{ +public: + struct ShaderEntry + { + ShaderEntry() : m_DXBCFile(NULL), m_Details(NULL) {} + ShaderEntry(const DXBC::DXBCFile &file) + { + m_DXBCFile = new DXBC::DXBCFile(file); + m_Details = MakeShaderReflection(m_DXBCFile); + } + ShaderEntry(const ShaderEntry &e) + { + *this = e; + } + ShaderEntry &operator =(const ShaderEntry &e) + { + m_DXBCFile = NULL; + if(e.m_DXBCFile) + m_DXBCFile = new DXBC::DXBCFile(*e.m_DXBCFile); + m_Details = MakeShaderReflection(m_DXBCFile); + + return *this; + } + ~ShaderEntry() + { + SAFE_DELETE(m_DXBCFile); + SAFE_DELETE(m_Details); + } + + DXBC::DXBCFile *m_DXBCFile; + ShaderReflection *m_Details; + }; + + static map m_ShaderList; + + WrappedShader(ResourceId id, const DXBC::DXBCFile &file) : m_ID(id) + { + RDCASSERT(m_ShaderList.find(m_ID) == m_ShaderList.end()); + m_ShaderList[m_ID] = ShaderEntry(file); + } + virtual ~WrappedShader() + { + if(m_ShaderList.find(m_ID) != m_ShaderList.end()) m_ShaderList.erase(m_ID); + } + + DXBC::DXBCFile *GetDXBC() { return m_ShaderList[m_ID].m_DXBCFile; } + ShaderReflection *GetDetails() { return m_ShaderList[m_ID].m_Details; } +private: + ResourceId m_ID; +}; + +template +class WrappedID3D11Shader : public WrappedDeviceChild, public WrappedShader +{ +public: + static const int AllocPoolCount = 32*1024; + static const int AllocPoolMaxByteSize = 3*1024*1024; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Shader, AllocPoolCount, AllocPoolMaxByteSize); + + WrappedID3D11Shader(RealShaderType* real, const DXBC::DXBCFile &file, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device), WrappedShader(GetResourceID(), file) {} + virtual ~WrappedID3D11Shader() { Shutdown(); } +}; + +class WrappedID3D11Counter : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Counter); + + WrappedID3D11Counter(ID3D11Counter* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11Counter() { Shutdown(); } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(ID3D11Asynchronous)) + { + *ppvObject = (ID3D11Asynchronous *)this; + AddRef(); + return S_OK; + } + + return WrappedDeviceChild::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D11Asynchronous + + UINT STDMETHODCALLTYPE GetDataSize( void) + { + return m_pReal->GetDataSize(); + } + + ////////////////////////////// + // implement ID3D11Counter + + void STDMETHODCALLTYPE GetDesc(__out D3D11_COUNTER_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11Query : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Query); + + WrappedID3D11Query(ID3D11Query* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11Query() { Shutdown(); } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(ID3D11Asynchronous)) + { + *ppvObject = (ID3D11Asynchronous *)this; + AddRef(); + return S_OK; + } + + return WrappedDeviceChild::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D11Asynchronous + + UINT STDMETHODCALLTYPE GetDataSize( void) + { + return m_pReal->GetDataSize(); + } + + ////////////////////////////// + // implement ID3D11Query + + void STDMETHODCALLTYPE GetDesc(__out D3D11_QUERY_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11Predicate : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11Predicate); + + WrappedID3D11Predicate(ID3D11Predicate* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) {} + virtual ~WrappedID3D11Predicate() { Shutdown(); } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(ID3D11Asynchronous)) + { + *ppvObject = (ID3D11Asynchronous *)this; + AddRef(); + return S_OK; + } + + return WrappedDeviceChild::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D11Asynchronous + + UINT STDMETHODCALLTYPE GetDataSize( void) + { + return m_pReal->GetDataSize(); + } + + ////////////////////////////// + // implement ID3D11Query + + void STDMETHODCALLTYPE GetDesc(__out D3D11_QUERY_DESC *pDesc) + { + m_pReal->GetDesc(pDesc); + } +}; + +class WrappedID3D11ClassInstance : public WrappedDeviceChild +{ +private: + ID3D11ClassLinkage *m_pLinkage; +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11ClassInstance); + + WrappedID3D11ClassInstance(ID3D11ClassInstance* real, ID3D11ClassLinkage *linkage, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device), m_pLinkage(linkage) { SAFE_ADDREF(m_pLinkage);} + virtual ~WrappedID3D11ClassInstance() { SAFE_RELEASE(m_pLinkage); Shutdown(); } + + ////////////////////////////// + // implement ID3D11ClassInstance + + virtual void STDMETHODCALLTYPE GetClassLinkage( + /* [annotation] */ + __out ID3D11ClassLinkage **ppLinkage) + { if(ppLinkage) { SAFE_ADDREF(m_pLinkage); *ppLinkage = m_pLinkage; } } + + virtual void STDMETHODCALLTYPE GetDesc( + /* [annotation] */ + __out D3D11_CLASS_INSTANCE_DESC *pDesc) + { m_pReal->GetDesc(pDesc); } + + virtual void STDMETHODCALLTYPE GetInstanceName( + /* [annotation] */ + __out_ecount_opt(*pBufferLength) LPSTR pInstanceName, + /* [annotation] */ + __inout SIZE_T *pBufferLength) + { m_pReal->GetInstanceName(pInstanceName, pBufferLength); } + + virtual void STDMETHODCALLTYPE GetTypeName( + /* [annotation] */ + __out_ecount_opt(*pBufferLength) LPSTR pTypeName, + /* [annotation] */ + __inout SIZE_T *pBufferLength) + { m_pReal->GetTypeName(pTypeName, pBufferLength); } +}; + + +class WrappedID3D11ClassLinkage : public WrappedDeviceChild +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11ClassLinkage); + + WrappedID3D11ClassLinkage(ID3D11ClassLinkage* real, WrappedID3D11Device* device) + : WrappedDeviceChild(real, device) { } + virtual ~WrappedID3D11ClassLinkage() { Shutdown(); } + + ////////////////////////////// + // implement ID3D11ClassLinkage + + virtual HRESULT STDMETHODCALLTYPE GetClassInstance( + /* [annotation] */ + __in LPCSTR pClassInstanceName, + /* [annotation] */ + __in UINT InstanceIndex, + /* [annotation] */ + __out ID3D11ClassInstance **ppInstance) + { + if(ppInstance == NULL) return E_INVALIDARG; + + ID3D11ClassInstance *real = NULL; + HRESULT hr = m_pReal->GetClassInstance(pClassInstanceName, InstanceIndex, &real); + + if(SUCCEEDED(hr) && real) + { + *ppInstance = m_pDevice->GetClassInstance(pClassInstanceName, InstanceIndex, this, real); + } + else + { + SAFE_RELEASE(real); + } + + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE CreateClassInstance( + /* [annotation] */ + __in LPCSTR pClassTypeName, + /* [annotation] */ + __in UINT ConstantBufferOffset, + /* [annotation] */ + __in UINT ConstantVectorOffset, + /* [annotation] */ + __in UINT TextureOffset, + /* [annotation] */ + __in UINT SamplerOffset, + /* [annotation] */ + __out ID3D11ClassInstance **ppInstance) + { + if(ppInstance == NULL) return E_INVALIDARG; + + ID3D11ClassInstance *real = NULL; + HRESULT hr = m_pReal->CreateClassInstance(pClassTypeName, ConstantBufferOffset, ConstantVectorOffset, TextureOffset, SamplerOffset, &real); + + if(SUCCEEDED(hr) && real) + { + *ppInstance = m_pDevice->CreateClassInstance(pClassTypeName, ConstantBufferOffset, ConstantVectorOffset, TextureOffset, SamplerOffset, this, real); + } + else + { + SAFE_RELEASE(real); + } + + return hr; + } +}; + +class WrappedID3D11DeviceContext; + +class WrappedID3D11CommandList : public WrappedDeviceChild +{ + WrappedID3D11DeviceContext* m_pContext; + bool m_Successful; // indicates whether we have all of the commands serialised for this command list +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11CommandList); + + WrappedID3D11CommandList(ID3D11CommandList* real, WrappedID3D11Device* device, + WrappedID3D11DeviceContext* context, bool success) + : WrappedDeviceChild(real, device), m_pContext(context), m_Successful(success) + { + // context isn't defined type at this point. + } + virtual ~WrappedID3D11CommandList() + { + // context isn't defined type at this point. + Shutdown(); + } + + WrappedID3D11DeviceContext *GetContext() { return m_pContext; } + bool IsCaptured() { return m_Successful; } + + ////////////////////////////// + // implement ID3D11CommandList + + virtual UINT STDMETHODCALLTYPE GetContextFlags( void) + { + return m_pReal->GetContextFlags(); + } +}; diff --git a/renderdoc/driver/d3d11/shaders/dxbc_debug.cpp b/renderdoc/driver/d3d11/shaders/dxbc_debug.cpp new file mode 100644 index 0000000000..35d5dae278 --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_debug.cpp @@ -0,0 +1,3366 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +// TODO remove me +#include "driver/d3d11/d3d11_device.h" +#include + +#include + +#include "common/common.h" +#include "maths/formatpacking.h" +#include "dxbc_debug.h" +#include "dxbc_inspect.h" + +#include "replay/renderdoc.h" + +using namespace DXBC; + +namespace ShaderDebug +{ + +static float round_ne(float x) +{ + // if on 0.5 boundary + if(int(x + 0.5f) != int(x)) + return int(x)%2 == 0 ? float(int(x)) : float(int(x+1)); + + // normal round + return x < 0 ? x + 0.5f : x; +} + +VarType State::OperationType(const OpcodeType &op) const +{ + switch(op) + { + // non typed operations, just return float + case OPCODE_LOOP: + case OPCODE_CONTINUE: + case OPCODE_CONTINUEC: + case OPCODE_ENDLOOP: + case OPCODE_SWITCH: + case OPCODE_CASE: + case OPCODE_DEFAULT: + case OPCODE_ENDSWITCH: + case OPCODE_ELSE: + case OPCODE_ENDIF: + case OPCODE_RET: + case OPCODE_RETC: + case OPCODE_DISCARD: + case OPCODE_NOP: + case OPCODE_CUSTOMDATA: + case OPCODE_SYNC: + case OPCODE_STORE_UAV_TYPED: + case OPCODE_STORE_RAW: + case OPCODE_STORE_STRUCTURED: + return eVar_Float; + + // operations that can be either type, also just return float (fixed up later) + case OPCODE_SAMPLE: + case OPCODE_SAMPLE_L: + case OPCODE_SAMPLE_B: + case OPCODE_SAMPLE_C: + case OPCODE_SAMPLE_C_LZ: + case OPCODE_SAMPLE_D: + case OPCODE_RESINFO: + case OPCODE_BUFINFO: + case OPCODE_LD: + case OPCODE_LD_MS: + return eVar_Float; + + case OPCODE_ADD: + case OPCODE_MUL: + case OPCODE_DIV: + case OPCODE_MOV: + case OPCODE_MOVC: + case OPCODE_MAX: + case OPCODE_MIN: + case OPCODE_MAD: + case OPCODE_DP2: + case OPCODE_DP3: + case OPCODE_DP4: + case OPCODE_SINCOS: + case OPCODE_F16TOF32: + case OPCODE_F32TOF16: + case OPCODE_FRC: + case OPCODE_FTOI: + case OPCODE_FTOU: + case OPCODE_FTOD: + case OPCODE_ROUND_PI: + case OPCODE_ROUND_Z: + case OPCODE_ROUND_NE: + case OPCODE_ROUND_NI: + case OPCODE_RCP: + case OPCODE_RSQ: + case OPCODE_SQRT: + case OPCODE_LOG: + case OPCODE_EXP: + case OPCODE_LT: + case OPCODE_GE: + case OPCODE_EQ: + case OPCODE_NE: + case OPCODE_DERIV_RTX: + case OPCODE_DERIV_RTX_COARSE: + case OPCODE_DERIV_RTX_FINE: + case OPCODE_DERIV_RTY: + case OPCODE_DERIV_RTY_COARSE: + case OPCODE_DERIV_RTY_FINE: + return eVar_Float; + + case OPCODE_AND: + case OPCODE_OR: + case OPCODE_IADD: + case OPCODE_IMUL: + case OPCODE_IMAD: + case OPCODE_ISHL: + case OPCODE_IGE: + case OPCODE_IEQ: + case OPCODE_ILT: + case OPCODE_ISHR: + case OPCODE_IBFE: + case OPCODE_INE: + case OPCODE_INEG: + case OPCODE_IMAX: + case OPCODE_IMIN: + case OPCODE_SWAPC: + case OPCODE_BREAK: + case OPCODE_BREAKC: + case OPCODE_IF: + case OPCODE_ITOF: + return eVar_Int; + + case OPCODE_BFREV: + case OPCODE_COUNTBITS: + case OPCODE_FIRSTBIT_HI: + case OPCODE_FIRSTBIT_LO: + case OPCODE_FIRSTBIT_SHI: + case OPCODE_UADDC: + case OPCODE_USUBB: + case OPCODE_UMAD: + case OPCODE_UMUL: + case OPCODE_UMIN: + case OPCODE_IMM_ATOMIC_ALLOC: + case OPCODE_IMM_ATOMIC_CONSUME: + case OPCODE_UMAX: + case OPCODE_UDIV: + case OPCODE_UTOF: + case OPCODE_USHR: + case OPCODE_ULT: + case OPCODE_UGE: + case OPCODE_BFI: + case OPCODE_UBFE: + case OPCODE_NOT: + case OPCODE_XOR: + case OPCODE_LD_RAW: + case OPCODE_LD_UAV_TYPED: + case OPCODE_LD_STRUCTURED: + return eVar_UInt; + + case OPCODE_DADD: + case OPCODE_DMAX: + case OPCODE_DMIN: + case OPCODE_DMUL: + case OPCODE_DEQ: + case OPCODE_DNE: + case OPCODE_DGE: + case OPCODE_DLT: + case OPCODE_DMOV: + case OPCODE_DMOVC: + case OPCODE_DTOF: + return eVar_Double; + + default: + RDCERR("Unhandled operation %d in shader debugging", op); + return eVar_Float; + } +} + +void DoubleSet(ShaderVariable &var, const double in[2]) +{ + uint64_t *din = (uint64_t *)in; + uint64_t a = din[0], + b = din[1]; + + // LSB + var.value.u.x = (uint32_t)(a & 0xffffffff); + var.value.u.z = (uint32_t)(b & 0xffffffff); + + a >>= 32; + b >>= 32; + + // MSB + var.value.u.y = (uint32_t)(a & 0xffffffff); + var.value.u.w = (uint32_t)(b & 0xffffffff); + + var.type = eVar_Double; +} + +void DoubleGet(const ShaderVariable &var, double out[2]) +{ + uint64_t a, b; + + // MSB + a = var.value.u.y; + b = var.value.u.w; + + a <<= 32; + b <<= 32; + + // LSB + a |= var.value.u.x; + b |= var.value.u.z; + + double *da = (double *)&a; + double *db = (double *)&b; + + out[0] = *da; + out[1] = *db; +} + +ShaderVariable sat(const ShaderVariable &v, const VarType type) +{ + ShaderVariable r = v; + + switch(type) + { + case eVar_Int: + { + for(size_t i=0; i < v.columns; i++) + r.value.iv[i] = v.value.iv[i] < 0 ? 0 : (v.value.iv[i] > 1 ? 1 : v.value.iv[i]); + break; + } + case eVar_UInt: + { + for(size_t i=0; i < v.columns; i++) + r.value.uv[i] = v.value.uv[i] ? 1 : 0; + break; + } + case eVar_Float: + { + for(size_t i=0; i < v.columns; i++) + r.value.fv[i] = v.value.fv[i] < 0 ? 0 : (v.value.fv[i] > 1 ? 1 : v.value.fv[i]); + break; + } + case eVar_Double: + { + double src[2]; + DoubleGet(v, src); + + double dst[2]; + dst[0] = src[0] < 0 ? 0 : (src[0] > 1 ? 1 : src[0]); + dst[1] = src[1] < 0 ? 0 : (src[1] > 1 ? 1 : src[1]); + + DoubleSet(r, dst); + break; + } + default: + RDCFATAL("Unsupported type of variable %d in math operation.\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc.", type); + } + + return r; +} + +ShaderVariable abs(const ShaderVariable &v, const VarType type) +{ + ShaderVariable r = v; + + switch(type) + { + case eVar_Int: + { + for(size_t i=0; i < v.columns; i++) + r.value.iv[i] = v.value.iv[i] > 0 ? v.value.iv[i] : -v.value.iv[i]; + break; + } + case eVar_UInt: + { + break; + } + case eVar_Float: + { + for(size_t i=0; i < v.columns; i++) + r.value.fv[i] = v.value.fv[i] > 0 ? v.value.fv[i] : -v.value.fv[i]; + break; + } + case eVar_Double: + { + double src[2]; + DoubleGet(v, src); + + double dst[2]; + dst[0] = src[0] > 0 ? src[0] : src[0]; + dst[1] = src[1] > 0 ? src[1] : src[1]; + + DoubleSet(r, dst); + break; + } + default: + RDCFATAL("Unsupported type of variable %d in math operation.\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc.", type); + } + + return r; +} + +ShaderVariable neg(const ShaderVariable &v, const VarType type) +{ + ShaderVariable r = v; + + switch(type) + { + case eVar_Int: + { + for(size_t i=0; i < v.columns; i++) + r.value.iv[i] = -v.value.iv[i]; + break; + } + case eVar_UInt: + { + break; + } + case eVar_Float: + { + for(size_t i=0; i < v.columns; i++) + r.value.fv[i] = -v.value.fv[i]; + break; + } + case eVar_Double: + { + double src[2]; + DoubleGet(v, src); + + double dst[2]; + dst[0] = -src[0]; + dst[1] = -src[1]; + + DoubleSet(r, dst); + break; + } + default: + RDCFATAL("Unsupported type of variable %d in math operation.\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc.", type); + } + + return r; +} + +ShaderVariable mul(const ShaderVariable &a, const ShaderVariable &b, const VarType type) +{ + ShaderVariable r = a; + + switch(type) + { + case eVar_Int: + { + for(size_t i=0; i < a.columns; i++) + r.value.iv[i] = a.value.iv[i] * b.value.iv[i]; + break; + } + case eVar_UInt: + { + for(size_t i=0; i < a.columns; i++) + r.value.uv[i] = a.value.uv[i] * b.value.uv[i]; + break; + } + case eVar_Float: + { + for(size_t i=0; i < a.columns; i++) + r.value.fv[i] = a.value.fv[i] * b.value.fv[i]; + break; + } + case eVar_Double: + { + double src0[2], src1[2]; + DoubleGet(a, src0); DoubleGet(b, src1); + + double dst[2]; + dst[0] = src0[0] * src1[0]; + dst[1] = src0[1] * src1[1]; + + DoubleSet(r, dst); + break; + } + default: + RDCFATAL("Unsupported type of variable %d in math operation.\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc.", type); + } + + return r; +} + +ShaderVariable div(const ShaderVariable &a, const ShaderVariable &b, const VarType type) +{ + ShaderVariable r = a; + + switch(type) + { + case eVar_Int: + { + for(size_t i=0; i < a.columns; i++) + r.value.iv[i] = a.value.iv[i] / b.value.iv[i]; + break; + } + case eVar_UInt: + { + for(size_t i=0; i < a.columns; i++) + r.value.uv[i] = a.value.uv[i] / b.value.uv[i]; + break; + } + case eVar_Float: + { + for(size_t i=0; i < a.columns; i++) + r.value.fv[i] = a.value.fv[i] / b.value.fv[i]; + break; + } + case eVar_Double: + { + double src0[2], src1[2]; + DoubleGet(a, src0); DoubleGet(b, src1); + + double dst[2]; + dst[0] = src0[0] / src1[0]; + dst[1] = src0[1] / src1[1]; + + DoubleSet(r, dst); + break; + } + default: + RDCFATAL("Unsupported type of variable %d in math operation.\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc.", type); + } + + return r; +} + +ShaderVariable add(const ShaderVariable &a, const ShaderVariable &b, const VarType type) +{ + ShaderVariable r = a; + + switch(type) + { + case eVar_Int: + { + for(size_t i=0; i < a.columns; i++) + r.value.iv[i] = a.value.iv[i] + b.value.iv[i]; + break; + } + case eVar_UInt: + { + for(size_t i=0; i < a.columns; i++) + r.value.uv[i] = a.value.uv[i] + b.value.uv[i]; + break; + } + case eVar_Float: + { + for(size_t i=0; i < a.columns; i++) + r.value.fv[i] = a.value.fv[i] + b.value.fv[i]; + break; + } + case eVar_Double: + { + double src0[2], src1[2]; + DoubleGet(a, src0); DoubleGet(b, src1); + + double dst[2]; + dst[0] = src0[0] + src1[0]; + dst[1] = src0[1] + src1[1]; + + DoubleSet(r, dst); + break; + } + default: + RDCFATAL("Unsupported type of variable %d in math operation.\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc.", type); + } + + return r; +} + +ShaderVariable sub(const ShaderVariable &a, const ShaderVariable &b, const VarType type) +{ + return add(a, neg(b, type), type); +} + +void State::Init() +{ + for(size_t i=0; i < dxbc->m_Declarations.size(); i++) + { + if(dxbc->m_Declarations[i].declaration == OPCODE_DCL_TEMPS) + { + create_array_uninit(registers, dxbc->m_Declarations[i].numTemps); + + for(uint32_t t=0; t < dxbc->m_Declarations[i].numTemps; t++) + { + char buf[64] = {0}; + + StringFormat::snprintf(buf, 63, "r%d", t); + + registers[t] = ShaderVariable(buf, 0l, 0l, 0l, 0l); + } + + break; + } + } +} + +bool State::Finished() +{ + return dxbc && (done || nextInstruction >= (int)dxbc->m_Instructions.size()); +} + +void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const ShaderVariable &val) +{ + ShaderVariable *v = NULL; + + switch(dstoper.type) + { + case TYPE_TEMP: + { + RDCASSERT(dstoper.indices[0].index < (uint32_t)registers.count); + v = ®isters[(size_t)dstoper.indices[0].index]; + break; + } + case TYPE_OUTPUT: + { + RDCASSERT(dstoper.indices[0].index < (uint32_t)outputs.count); + v = &outputs[(size_t)dstoper.indices[0].index]; + break; + } + case TYPE_INPUT: + case TYPE_CONSTANT_BUFFER: + { + RDCFATAL("Attempt to write to read-only operand (input, cbuffer, etc).\n" + "This is likely a bug in the asm extraction as such code isn't likely to be produced by fxc."); + break; + } + case TYPE_NULL: + { + // nothing to do! + return; + } + default: + { + string name = dstoper.toString(); + for(int32_t i=0; i < outputs.count; i++) + { + if(!strcmp(name.c_str(), outputs[i].name.elems)) + { + v = &outputs[i]; + break; + } + } + + if(v) + break; + + RDCERR("Currently unsupported destination operand type %d!", dstoper.type); + break; + } + } + + RDCASSERT(v); + + if(v) + { + ShaderVariable right = val; + + RDCASSERT(v->rows == 1 && right.rows == 1); + RDCASSERT(right.columns <= 4); + + // behaviour for scalar and vector masks are slightly different. + // in a scalar operation like r0.z = r4.x + r6.y + // then when doing the set to dest we must write into the .z + // from the only component - x - since the result is scalar. + // in a vector operation like r0.zw = r4.xxxy + r6.yyyz + // then we must write from matching component to matching component + + if(op.saturate) + right = sat(right, OperationType(op.operation)); + + if(dstoper.comps[0] != 0xff && dstoper.comps[1] == 0xff && dstoper.comps[2] == 0xff && dstoper.comps[3] == 0xff) + { + RDCASSERT(dstoper.comps[0] != 0xff); + + v->value.uv[ dstoper.comps[0] ] = right.value.u.x; + } + else + { + int compsWritten = 0; + for(size_t i=0; i < 4; i++) + { + // if comps value is 0xff, we should not write to this component + if(dstoper.comps[i] != 0xff) + { + RDCASSERT(dstoper.comps[i] < v->columns); + v->value.uv[ dstoper.comps[i] ] = right.value.uv[ dstoper.comps[i] ]; + compsWritten++; + } + } + + if(compsWritten == 0) + v->value.uv[0] = right.value.uv[0]; + } + } +} + +ShaderVariable State::DDX(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const +{ + ShaderVariable ret; + + VarType optype = OperationType(op.operation); + + // left pixel in the quad + if(quadIndex % 2 == 0) + { + ret = + sub(quad[quadIndex+1].GetSrc(oper, op), quad[quadIndex].GetSrc(oper, op), optype); + } + else + { + ret = + sub(quad[quadIndex].GetSrc(oper, op), quad[quadIndex-1].GetSrc(oper, op), optype); + } + + return ret; +} + +ShaderVariable State::DDY(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const +{ + ShaderVariable ret; + + VarType optype = OperationType(op.operation); + + // top pixel in the quad + if(quadIndex / 2 == 0) + { + ret = + sub(quad[quadIndex+2].GetSrc(oper, op), quad[quadIndex].GetSrc(oper, op), optype); + } + else + { + ret = + sub(quad[quadIndex].GetSrc(oper, op), quad[quadIndex-2].GetSrc(oper, op), optype); + } + + return ret; +} + +ShaderVariable State::GetSrc(const ASMOperand &oper, const ASMOperation &op) const +{ + ShaderVariable v, s; + + uint32_t indices[4]; + + RDCASSERT(oper.indices.size() <= 4); + + for(size_t i=0; i < oper.indices.size(); i++) + { + if(oper.indices[i].absolute) + indices[i] = (uint32_t)oper.indices[i].index; + else + indices[i] = 0; + + if(oper.indices[i].relative) + { + ShaderVariable idx = GetSrc(oper.indices[i].operand, op); + + indices[i] += idx.value.i.x; + } + } + + switch(oper.type) + { + case TYPE_TEMP: + { + // we assume we never write to an uninitialised register + RDCASSERT(indices[0] < (uint32_t)registers.count); + + if(indices[0] < (uint32_t)registers.count) + v = s = registers[indices[0]]; + else + v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + + break; + } + case TYPE_INPUT: + { + RDCASSERT(indices[0] < (uint32_t)trace->inputs.count); + + if(indices[0] < (uint32_t)trace->inputs.count) + v = s = trace->inputs[indices[0]]; + else + v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + + break; + } + case TYPE_OUTPUT: + { + RDCASSERT(indices[0] < (uint32_t)outputs.count); + + if(indices[0] < (uint32_t)outputs.count) + v = s = outputs[indices[0]]; + else + v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + + break; + } + case TYPE_RESOURCE: + case TYPE_SAMPLER: + case TYPE_UNORDERED_ACCESS_VIEW: + case TYPE_NULL: + { + // should be handled specially by instructions that expect these types of + // argument but let's be sane and include the index + v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + break; + } + case TYPE_IMMEDIATE32: + case TYPE_IMMEDIATE64: + { + s.name = "Immediate"; + + if(oper.numComponents == NUMCOMPS_1) + { s.rows = 1; s.columns = 1; } + else if(oper.numComponents == NUMCOMPS_4) + { s.rows = 1; s.columns = 4; } + else + { RDCFATAL("N-wide vectors not supported (per hlsl spec)"); } + + if(oper.type == TYPE_IMMEDIATE32) + { + for(size_t i=0; i < s.columns; i++) + { + s.value.iv[i] = (int32_t)oper.values[i]; + } + } + else + { + RDCUNIMPLEMENTED("Encountered immediate 64bit value!"); // need to figure out what to do here. + } + + v = s; + + break; + } + case TYPE_CONSTANT_BUFFER: + { + RDCASSERT(indices[0] < (uint32_t)trace->cbuffers.count && indices[1] < (uint32_t)trace->cbuffers[indices[0]].count); + + if(indices[0] < (uint32_t)trace->cbuffers.count && indices[1] < (uint32_t)trace->cbuffers[indices[0]].count) + v = s = trace->cbuffers[indices[0]][indices[1]]; + else + v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + + break; + } + case TYPE_IMMEDIATE_CONSTANT_BUFFER: + { + RDCASSERT(indices[0]*4 + 4 < dxbc->m_Immediate.size()); + + v = s = ShaderVariable("", 0, 0, 0, 0); + + if(indices[0]*4 + 4 < dxbc->m_Immediate.size()) + memcpy(s.value.uv, &dxbc->m_Immediate[indices[0]*4], 16); + + break; + } + case TYPE_INPUT_THREAD_GROUP_ID: + { + v = s = ShaderVariable("vThreadGroupID", semantics.GroupID[0], semantics.GroupID[1], semantics.GroupID[2], (uint32_t)0); + + break; + } + case TYPE_INPUT_THREAD_ID: + { + uint32_t numthreads[3] = {0, 0, 0}; + + for(size_t i=0; i < dxbc->m_Declarations.size(); i++) + { + ASMDecl &decl = dxbc->m_Declarations[i]; + + if(decl.declaration == OPCODE_DCL_THREAD_GROUP) + { + numthreads[0] = decl.groupSize[0]; + numthreads[1] = decl.groupSize[1]; + numthreads[2] = decl.groupSize[2]; + } + } + + RDCASSERT(numthreads[0] >= 1 && numthreads[0] <= 1024); + RDCASSERT(numthreads[1] >= 1 && numthreads[1] <= 1024); + RDCASSERT(numthreads[2] >= 1 && numthreads[2] <= 64); + RDCASSERT(numthreads[0]*numthreads[1]*numthreads[2] <= 1024); + + v = s = ShaderVariable("vThreadID", semantics.GroupID[0]*numthreads[0] + semantics.ThreadID[0], + semantics.GroupID[1]*numthreads[1] + semantics.ThreadID[1], + semantics.GroupID[2]*numthreads[2] + semantics.ThreadID[2], (uint32_t)0); + + break; + } + case TYPE_INPUT_THREAD_ID_IN_GROUP: + { + v = s = ShaderVariable("vThreadIDInGroup", semantics.ThreadID[0], semantics.ThreadID[1], semantics.ThreadID[2], (uint32_t)0); + + break; + } + case TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED: + { + uint32_t numthreads[3] = {0, 0, 0}; + + for(size_t i=0; i < dxbc->m_Declarations.size(); i++) + { + ASMDecl &decl = dxbc->m_Declarations[i]; + + if(decl.declaration == OPCODE_DCL_THREAD_GROUP) + { + numthreads[0] = decl.groupSize[0]; + numthreads[1] = decl.groupSize[1]; + numthreads[2] = decl.groupSize[2]; + } + } + + RDCASSERT(numthreads[0] >= 1 && numthreads[0] <= 1024); + RDCASSERT(numthreads[1] >= 1 && numthreads[1] <= 1024); + RDCASSERT(numthreads[2] >= 1 && numthreads[2] <= 64); + RDCASSERT(numthreads[0]*numthreads[1]*numthreads[2] <= 1024); + + uint32_t flattened = semantics.ThreadID[2]*numthreads[0]*numthreads[1] + + semantics.ThreadID[1]*numthreads[0] + + semantics.ThreadID[0]; + + v = s = ShaderVariable("vThreadIDInGroupFlattened", flattened, flattened, flattened, flattened); + break; + } + default: + { + RDCERR("Currently unsupported operand type %d!", oper.type); + + v = s = ShaderVariable("vUnsupported", (uint32_t)0, (uint32_t)0, (uint32_t)0, (uint32_t)0); + + break; + } + } + + // perform swizzling + v.value.uv[0] = s.value.uv[ oper.comps[0] == 0xff ? 0 : oper.comps[0] ]; + v.value.uv[1] = s.value.uv[ oper.comps[1] == 0xff ? 1 : oper.comps[1] ]; + v.value.uv[2] = s.value.uv[ oper.comps[2] == 0xff ? 2 : oper.comps[2] ]; + v.value.uv[3] = s.value.uv[ oper.comps[3] == 0xff ? 3 : oper.comps[3] ]; + + if(oper.comps[0] != 0xff && oper.comps[1] == 0xff && oper.comps[2] == 0xff && oper.comps[3] == 0xff) + v.columns = 1; + else + v.columns = 4; + + if(oper.modifier == OPERAND_MODIFIER_ABS || oper.modifier == OPERAND_MODIFIER_ABSNEG) + { + v = abs(v, OperationType(op.operation)); + } + + if(oper.modifier == OPERAND_MODIFIER_NEG || oper.modifier == OPERAND_MODIFIER_ABSNEG) + { + v = neg(v, OperationType(op.operation)); + } + + return v; +} + +State State::GetNext(GlobalState &global, State quad[4]) const +{ + State s = *this; + + if(s.Finished()) + return s; + + ASMOperation &op = s.dxbc->m_Instructions[s.nextInstruction]; + + s.nextInstruction++; + + vector srcOpers; + + size_t numOperands = s.dxbc->NumOperands(op.operation); + + VarType optype = OperationType(op.operation); + + RDCASSERT(op.operands.size() == numOperands); + + for(size_t i=1; i < numOperands; i++) + srcOpers.push_back(GetSrc(op.operands[i], op)); + + switch(op.operation) + { + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Math operations + + case OPCODE_DADD: + case OPCODE_IADD: + case OPCODE_ADD: + s.SetDst(op.operands[0], op, add(srcOpers[0], srcOpers[1], optype)); + break; + case OPCODE_DIV: + s.SetDst(op.operands[0], op, div(srcOpers[0], srcOpers[1], optype)); + break; + case OPCODE_UDIV: + { + ShaderVariable quot("", (uint32_t)0xffffffff, (uint32_t)0xffffffff, (uint32_t)0xffffffff, (uint32_t)0xffffffff); + ShaderVariable rem("", (uint32_t)0xffffffff, (uint32_t)0xffffffff, (uint32_t)0xffffffff, (uint32_t)0xffffffff); + + for(size_t i=0; i < 4; i++) + { + if(srcOpers[2].value.uv[i] != 0) + { + quot.value.uv[i] = srcOpers[1].value.uv[i] / srcOpers[2].value.uv[i]; + rem.value.uv[i] = srcOpers[1].value.uv[i] - (quot.value.uv[i] * srcOpers[2].value.uv[i]); + } + } + + if(op.operands[0].type != TYPE_NULL) + { + s.SetDst(op.operands[0], op, quot); + } + if(op.operands[1].type != TYPE_NULL) + { + s.SetDst(op.operands[1], op, rem); + } + break; + } + case OPCODE_BFREV: + { + ShaderVariable ret("", 0U, 0U, 0U, 0U); + + // do a bitwise reverse + for(size_t i=0; i < 4; i++) + { + for(size_t b=0; b < 32; b++) + { + ret.value.uv[i] |= (srcOpers[0].value.uv[i] & (1<> 1) & 0x55555555); + bf = (bf & 0x33333333) + ((bf >> 2) & 0x33333333); + ret.value.uv[i] = (((bf + (bf >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; + } + + s.SetDst(op.operands[0], op, ret); + break; + } + case OPCODE_FIRSTBIT_HI: + { + ShaderVariable ret("", 0U, 0U, 0U, 0U); + + for(size_t i=0; i < 4; i++) + ret.value.uv[i] = BitScanReverse((DWORD *)&srcOpers[0].value.uv[i], ~0U); + + s.SetDst(op.operands[0], op, ret); + break; + } + case OPCODE_FIRSTBIT_LO: + { + ShaderVariable ret("", 0U, 0U, 0U, 0U); + + for(size_t i=0; i < 4; i++) + ret.value.uv[i] = BitScanForward((DWORD *)&srcOpers[0].value.uv[i], ~0U); + + s.SetDst(op.operands[0], op, ret); + break; + } + case OPCODE_FIRSTBIT_SHI: + { + ShaderVariable ret("", 0U, 0U, 0U, 0U); + + for(size_t i=0; i < 4; i++) + { + uint32_t u = srcOpers[0].value.uv[i]; + if(srcOpers[0].value.iv[i] < 0) + u = ~u; + + ret.value.uv[i] = BitScanReverse((DWORD *)&u, ~0U); + } + + s.SetDst(op.operands[0], op, ret); + break; + } + case OPCODE_IMUL: + case OPCODE_UMUL: + { + ShaderVariable hi("", 0U, 0U, 0U, 0U); + ShaderVariable lo("", 0U, 0U, 0U, 0U); + + for(size_t i=0; i < 4; i++) + { + if(op.operation == OPCODE_UMUL) + { + uint64_t res = uint64_t(srcOpers[1].value.uv[i])*uint64_t(srcOpers[2].value.uv[i]); + + hi.value.uv[i] = uint32_t((res>>32)&0xffffffff); + lo.value.uv[i] = uint32_t(res&0xffffffff); + } + else if(op.operation == OPCODE_IMUL) + { + int64_t res = int64_t(srcOpers[1].value.iv[i])*int64_t(srcOpers[2].value.iv[i]); + + hi.value.uv[i] = uint32_t((res>>32)&0xffffffff); + lo.value.uv[i] = uint32_t(res&0xffffffff); + } + } + + if(op.operands[0].type != TYPE_NULL) + { + s.SetDst(op.operands[0], op, hi); + } + if(op.operands[1].type != TYPE_NULL) + { + s.SetDst(op.operands[1], op, lo); + } + break; + } + case OPCODE_DMUL: + case OPCODE_MUL: + s.SetDst(op.operands[0], op, mul(srcOpers[0], srcOpers[1], optype)); + break; + case OPCODE_UADDC: + { + uint64_t src[4]; + for(int i=0; i < 4; i++) src[i] = (uint64_t)srcOpers[1].value.uv[i]; + for(int i=0; i < 4; i++) src[i] = (uint64_t)srcOpers[2].value.uv[i]; + + // set the rounded result + uint32_t dst[4]; + + for(int i=0; i < 4; i++) dst[i] = (uint32_t)(src[i]&0xffffffff); + + s.SetDst(op.operands[0], op, ShaderVariable("", dst[0], dst[1], dst[2], dst[3])); + + // if not null, set the carry bits + if(op.operands[1].type != TYPE_NULL) + s.SetDst(op.operands[1], op, ShaderVariable("", + src[0] > 0xffffffff ? 1U : 0U, + src[1] > 0xffffffff ? 1U : 0U, + src[2] > 0xffffffff ? 1U : 0U, + src[3] > 0xffffffff ? 1U : 0U)); + + break; + } + case OPCODE_USUBB: + { + uint64_t src0[4]; + uint64_t src1[4]; + + // add on a 'borrow' bit + for(int i=0; i < 4; i++) src0[i] = 0x100000000 | (uint64_t)srcOpers[1].value.uv[i]; + for(int i=0; i < 4; i++) src1[i] = (uint64_t)srcOpers[2].value.uv[i]; + + // do the subtract + uint64_t result[4]; + for(int i=0; i < 4; i++) result[i] = src0[i] - src1[i]; + + uint32_t dst[4]; + for(int i=0; i < 4; i++) dst[i] = (uint32_t)(result[0]&0xffffffff); + + s.SetDst(op.operands[0], op, ShaderVariable("", dst[0], dst[1], dst[2], dst[3])); + + // if not null, mark where the borrow bits were used + if(op.operands[1].type != TYPE_NULL) + s.SetDst(op.operands[1], op, ShaderVariable("", + result[0] <= 0xffffffff ? 1U : 0U, + result[1] <= 0xffffffff ? 1U : 0U, + result[2] <= 0xffffffff ? 1U : 0U, + result[3] <= 0xffffffff ? 1U : 0U)); + + break; + } + case OPCODE_IMAD: + case OPCODE_UMAD: + case OPCODE_MAD: + s.SetDst(op.operands[0], op, add(mul(srcOpers[0], srcOpers[1], optype), srcOpers[2], optype)); + break; + case OPCODE_DP2: + case OPCODE_DP3: + case OPCODE_DP4: + { + ShaderVariable dot = mul(srcOpers[0], srcOpers[1], optype); + + float sum = dot.value.f.x; + if(op.operation >= OPCODE_DP2) + sum += dot.value.f.y; + if(op.operation >= OPCODE_DP3) + sum += dot.value.f.z; + if(op.operation >= OPCODE_DP4) + sum += dot.value.f.w; + + s.SetDst(op.operands[0], op, ShaderVariable("", sum, sum, sum, sum)); + break; + } + case OPCODE_F16TOF32: + { + s.SetDst(op.operands[0], op, ShaderVariable("", + ConvertFromHalf(srcOpers[0].value.u.x&0xffff), + ConvertFromHalf(srcOpers[0].value.u.y&0xffff), + ConvertFromHalf(srcOpers[0].value.u.z&0xffff), + ConvertFromHalf(srcOpers[0].value.u.w&0xffff))); + break; + } + case OPCODE_F32TOF16: + { + s.SetDst(op.operands[0], op, ShaderVariable("", + (uint32_t)ConvertToHalf(srcOpers[0].value.f.x), + (uint32_t)ConvertToHalf(srcOpers[0].value.f.y), + (uint32_t)ConvertToHalf(srcOpers[0].value.f.z), + (uint32_t)ConvertToHalf(srcOpers[0].value.f.w))); + break; + } + case OPCODE_FRC: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.f.x - floor(srcOpers[0].value.f.x), + srcOpers[0].value.f.y - floor(srcOpers[0].value.f.y), + srcOpers[0].value.f.z - floor(srcOpers[0].value.f.z), + srcOpers[0].value.f.w - floor(srcOpers[0].value.f.w) )); + break; + // positive infinity + case OPCODE_ROUND_PI: + s.SetDst(op.operands[0], op, ShaderVariable("", ceil(srcOpers[0].value.f.x), + ceil(srcOpers[0].value.f.y), + ceil(srcOpers[0].value.f.z), + ceil(srcOpers[0].value.f.w) )); + break; + // negative infinity + case OPCODE_ROUND_NI: + s.SetDst(op.operands[0], op, ShaderVariable("", floor(srcOpers[0].value.f.x), + floor(srcOpers[0].value.f.y), + floor(srcOpers[0].value.f.z), + floor(srcOpers[0].value.f.w) )); + break; + // towards zero + case OPCODE_ROUND_Z: + s.SetDst(op.operands[0], op, ShaderVariable("", floor(srcOpers[0].value.f.x < 0 ? srcOpers[0].value.f.x + 0.5f : srcOpers[0].value.f.x), + floor(srcOpers[0].value.f.y < 0 ? srcOpers[0].value.f.y + 0.5f : srcOpers[0].value.f.y), + floor(srcOpers[0].value.f.z < 0 ? srcOpers[0].value.f.z + 0.5f : srcOpers[0].value.f.z), + floor(srcOpers[0].value.f.w < 0 ? srcOpers[0].value.f.w + 0.5f : srcOpers[0].value.f.w) )); + break; + // to nearest even int (banker's rounding) + case OPCODE_ROUND_NE: + s.SetDst(op.operands[0], op, ShaderVariable("", round_ne(srcOpers[0].value.f.x), + round_ne(srcOpers[0].value.f.y), + round_ne(srcOpers[0].value.f.z), + round_ne(srcOpers[0].value.f.w) )); + break; + case OPCODE_INEG: + s.SetDst(op.operands[0], op, neg(srcOpers[0], optype)); + break; + case OPCODE_IMIN: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x < srcOpers[1].value.i.x ? srcOpers[0].value.i.x : srcOpers[1].value.i.x, + srcOpers[0].value.i.y < srcOpers[1].value.i.y ? srcOpers[0].value.i.y : srcOpers[1].value.i.y, + srcOpers[0].value.i.z < srcOpers[1].value.i.z ? srcOpers[0].value.i.z : srcOpers[1].value.i.z, + srcOpers[0].value.i.w < srcOpers[1].value.i.w ? srcOpers[0].value.i.w : srcOpers[1].value.i.w)); + break; + case OPCODE_UMIN: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.u.x < srcOpers[1].value.u.x ? srcOpers[0].value.u.x : srcOpers[1].value.u.x, + srcOpers[0].value.u.y < srcOpers[1].value.u.y ? srcOpers[0].value.u.y : srcOpers[1].value.u.y, + srcOpers[0].value.u.z < srcOpers[1].value.u.z ? srcOpers[0].value.u.z : srcOpers[1].value.u.z, + srcOpers[0].value.u.w < srcOpers[1].value.u.w ? srcOpers[0].value.u.w : srcOpers[1].value.u.w)); + break; + case OPCODE_DMIN: + { + double src0[2], src1[2]; + DoubleGet(srcOpers[0], src0); DoubleGet(srcOpers[1], src1); + + double dst[2]; + dst[0] = src0[0] < src1[0] ? src0[0] : src1[0]; + dst[1] = src0[1] < src1[1] ? src0[1] : src1[1]; + + ShaderVariable r("", 0U, 0U, 0U, 0U); + DoubleSet(r, dst); + + s.SetDst(op.operands[0], op, r); + break; + } + case OPCODE_MIN: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.f.x < srcOpers[1].value.f.x ? srcOpers[0].value.f.x : srcOpers[1].value.f.x, + srcOpers[0].value.f.y < srcOpers[1].value.f.y ? srcOpers[0].value.f.y : srcOpers[1].value.f.y, + srcOpers[0].value.f.z < srcOpers[1].value.f.z ? srcOpers[0].value.f.z : srcOpers[1].value.f.z, + srcOpers[0].value.f.w < srcOpers[1].value.f.w ? srcOpers[0].value.f.w : srcOpers[1].value.f.w)); + break; + case OPCODE_UMAX: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.u.x >= srcOpers[1].value.u.x ? srcOpers[0].value.u.x : srcOpers[1].value.u.x, + srcOpers[0].value.u.y >= srcOpers[1].value.u.y ? srcOpers[0].value.u.y : srcOpers[1].value.u.y, + srcOpers[0].value.u.z >= srcOpers[1].value.u.z ? srcOpers[0].value.u.z : srcOpers[1].value.u.z, + srcOpers[0].value.u.w >= srcOpers[1].value.u.w ? srcOpers[0].value.u.w : srcOpers[1].value.u.w)); + break; + case OPCODE_IMAX: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x >= srcOpers[1].value.i.x ? srcOpers[0].value.i.x : srcOpers[1].value.i.x, + srcOpers[0].value.i.y >= srcOpers[1].value.i.y ? srcOpers[0].value.i.y : srcOpers[1].value.i.y, + srcOpers[0].value.i.z >= srcOpers[1].value.i.z ? srcOpers[0].value.i.z : srcOpers[1].value.i.z, + srcOpers[0].value.i.w >= srcOpers[1].value.i.w ? srcOpers[0].value.i.w : srcOpers[1].value.i.w)); + break; + case OPCODE_DMAX: + { + double src0[2], src1[2]; + DoubleGet(srcOpers[0], src0); DoubleGet(srcOpers[1], src1); + + double dst[2]; + dst[0] = src0[0] >= src1[0] ? src0[0] : src1[0]; + dst[1] = src0[1] >= src1[1] ? src0[1] : src1[1]; + + ShaderVariable r("", 0U, 0U, 0U, 0U); + DoubleSet(r, dst); + + s.SetDst(op.operands[0], op, r); + break; + } + case OPCODE_MAX: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.f.x >= srcOpers[1].value.f.x ? srcOpers[0].value.f.x : srcOpers[1].value.f.x, + srcOpers[0].value.f.y >= srcOpers[1].value.f.y ? srcOpers[0].value.f.y : srcOpers[1].value.f.y, + srcOpers[0].value.f.z >= srcOpers[1].value.f.z ? srcOpers[0].value.f.z : srcOpers[1].value.f.z, + srcOpers[0].value.f.w >= srcOpers[1].value.f.w ? srcOpers[0].value.f.w : srcOpers[1].value.f.w)); + break; + case OPCODE_SQRT: + s.SetDst(op.operands[0], op, ShaderVariable("", sqrtf(srcOpers[0].value.f.x), + sqrtf(srcOpers[0].value.f.y), + sqrtf(srcOpers[0].value.f.z), + sqrtf(srcOpers[0].value.f.w) )); + break; + case OPCODE_RCP: + s.SetDst(op.operands[0], op, ShaderVariable("", 1.0f/srcOpers[0].value.f.x, + 1.0f/srcOpers[0].value.f.y, + 1.0f/srcOpers[0].value.f.z, + 1.0f/srcOpers[0].value.f.w )); + break; + case OPCODE_RSQ: + s.SetDst(op.operands[0], op, ShaderVariable("", 1.0f/sqrtf(srcOpers[0].value.f.x), + 1.0f/sqrtf(srcOpers[0].value.f.y), + 1.0f/sqrtf(srcOpers[0].value.f.z), + 1.0f/sqrtf(srcOpers[0].value.f.w) )); + break; + case OPCODE_EXP: + s.SetDst(op.operands[0], op, ShaderVariable("", powf(2.0f, srcOpers[0].value.f.x), + powf(2.0f, srcOpers[0].value.f.y), + powf(2.0f, srcOpers[0].value.f.z), + powf(2.0f, srcOpers[0].value.f.w) )); + break; + case OPCODE_LOG: + s.SetDst(op.operands[0], op, ShaderVariable("", logf(srcOpers[0].value.f.x)/logf(2.0f), + logf(srcOpers[0].value.f.y)/logf(2.0f), + logf(srcOpers[0].value.f.z)/logf(2.0f), + logf(srcOpers[0].value.f.w)/logf(2.0f) )); + break; + case OPCODE_SINCOS: + if(op.operands[0].type != TYPE_NULL) + { + s.SetDst(op.operands[0], op, ShaderVariable("", sinf(srcOpers[1].value.f.x), + sinf(srcOpers[1].value.f.y), + sinf(srcOpers[1].value.f.z), + sinf(srcOpers[1].value.f.w) )); + } + if(op.operands[1].type != TYPE_NULL) + { + s.SetDst(op.operands[1], op, ShaderVariable("", cosf(srcOpers[1].value.f.x), + cosf(srcOpers[1].value.f.y), + cosf(srcOpers[1].value.f.z), + cosf(srcOpers[1].value.f.w) )); + } + break; + + case OPCODE_ISHL: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x << srcOpers[1].value.i.x, + srcOpers[0].value.i.y << srcOpers[1].value.i.x, + srcOpers[0].value.i.z << srcOpers[1].value.i.x, + srcOpers[0].value.i.w << srcOpers[1].value.i.x)); + break; + case OPCODE_IBFE: + { + // bottom 5 bits + ShaderVariable width("", (int32_t)(srcOpers[0].value.i.x & 0x1f), + (int32_t)(srcOpers[0].value.i.y & 0x1f), + (int32_t)(srcOpers[0].value.i.z & 0x1f), + (int32_t)(srcOpers[0].value.i.w & 0x1f)); + ShaderVariable offset("", (int32_t)(srcOpers[1].value.i.x & 0x1f), + (int32_t)(srcOpers[1].value.i.y & 0x1f), + (int32_t)(srcOpers[1].value.i.z & 0x1f), + (int32_t)(srcOpers[1].value.i.w & 0x1f)); + + ShaderVariable dest("", (int32_t)0, (int32_t)0, (int32_t)0, (int32_t)0); + + for(int comp=0; comp < 4; comp++) + { + if(width.value.iv[comp] == 0) + { + dest.value.iv[comp] = 0; + } + else if(width.value.iv[comp] + offset.value.iv[comp] < 32) + { + dest.value.iv[comp] = srcOpers[2].value.iv[comp] << (32-(width.value.iv[comp]+offset.value.iv[comp])); + dest.value.iv[comp] = dest.value.iv[comp] >> (32-width.value.iv[comp]); + } + else + { + dest.value.iv[comp] = srcOpers[2].value.iv[comp] >> offset.value.iv[comp]; + } + } + + s.SetDst(op.operands[0], op, dest); + break; + } + case OPCODE_UBFE: + { + // bottom 5 bits + ShaderVariable width("", (uint32_t)(srcOpers[0].value.u.x & 0x1f), + (uint32_t)(srcOpers[0].value.u.y & 0x1f), + (uint32_t)(srcOpers[0].value.u.z & 0x1f), + (uint32_t)(srcOpers[0].value.u.w & 0x1f)); + ShaderVariable offset("", (uint32_t)(srcOpers[1].value.u.x & 0x1f), + (uint32_t)(srcOpers[1].value.u.y & 0x1f), + (uint32_t)(srcOpers[1].value.u.z & 0x1f), + (uint32_t)(srcOpers[1].value.u.w & 0x1f)); + + ShaderVariable dest("", (uint32_t)0, (uint32_t)0, (uint32_t)0, (uint32_t)0); + + for(int comp=0; comp < 4; comp++) + { + if(width.value.uv[comp] == 0) + { + dest.value.uv[comp] = 0; + } + else if(width.value.uv[comp] + offset.value.uv[comp] < 32) + { + dest.value.uv[comp] = srcOpers[2].value.uv[comp] << (32-(width.value.uv[comp]+offset.value.uv[comp])); + dest.value.uv[comp] = dest.value.uv[comp] >> (32-width.value.uv[comp]); + } + else + { + dest.value.uv[comp] = srcOpers[2].value.uv[comp] >> offset.value.uv[comp]; + } + } + + s.SetDst(op.operands[0], op, dest); + break; + } + case OPCODE_BFI: + { + // bottom 5 bits + ShaderVariable width("", (uint32_t)(srcOpers[0].value.u.x & 0x1f), + (uint32_t)(srcOpers[0].value.u.y & 0x1f), + (uint32_t)(srcOpers[0].value.u.z & 0x1f), + (uint32_t)(srcOpers[0].value.u.w & 0x1f)); + ShaderVariable offset("", (uint32_t)(srcOpers[1].value.u.x & 0x1f), + (uint32_t)(srcOpers[1].value.u.y & 0x1f), + (uint32_t)(srcOpers[1].value.u.z & 0x1f), + (uint32_t)(srcOpers[1].value.u.w & 0x1f)); + + ShaderVariable dest("", (uint32_t)0, (uint32_t)0, (uint32_t)0, (uint32_t)0); + + for(int comp=0; comp < 4; comp++) + { + uint32_t bitmask = (((1 << width.value.uv[comp])-1) << offset.value.uv[comp]) & 0xffffffff; + dest.value.uv[comp] = (uint32_t)(((srcOpers[2].value.uv[comp] << offset.value.uv[comp]) & bitmask) | + (srcOpers[3].value.uv[comp] & ~bitmask)); + } + + s.SetDst(op.operands[0], op, dest); + break; + } + case OPCODE_USHR: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.u.x >> (srcOpers[1].value.u.x&0x1f), + srcOpers[0].value.u.y >> (srcOpers[1].value.u.x&0x1f), + srcOpers[0].value.u.z >> (srcOpers[1].value.u.x&0x1f), + srcOpers[0].value.u.w >> (srcOpers[1].value.u.x&0x1f))); + break; + case OPCODE_ISHR: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x >> (srcOpers[1].value.u.x&0x1f), + srcOpers[0].value.i.y >> (srcOpers[1].value.u.x&0x1f), + srcOpers[0].value.i.z >> (srcOpers[1].value.u.x&0x1f), + srcOpers[0].value.i.w >> (srcOpers[1].value.u.x&0x1f))); + break; + case OPCODE_AND: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x & srcOpers[1].value.i.x, + srcOpers[0].value.i.y & srcOpers[1].value.i.y, + srcOpers[0].value.i.z & srcOpers[1].value.i.z, + srcOpers[0].value.i.w & srcOpers[1].value.i.w)); + break; + case OPCODE_OR: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x | srcOpers[1].value.i.x, + srcOpers[0].value.i.y | srcOpers[1].value.i.y, + srcOpers[0].value.i.z | srcOpers[1].value.i.z, + srcOpers[0].value.i.w | srcOpers[1].value.i.w)); + break; + case OPCODE_XOR: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.u.x ^ srcOpers[1].value.u.x, + srcOpers[0].value.u.y ^ srcOpers[1].value.u.y, + srcOpers[0].value.u.z ^ srcOpers[1].value.u.z, + srcOpers[0].value.u.w ^ srcOpers[1].value.u.w)); + break; + case OPCODE_NOT: + s.SetDst(op.operands[0], op, ShaderVariable("", ~srcOpers[0].value.u.x, + ~srcOpers[0].value.u.y, + ~srcOpers[0].value.u.z, + ~srcOpers[0].value.u.w)); + break; + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Misc + + case OPCODE_STORE_UAV_TYPED: + case OPCODE_STORE_RAW: + case OPCODE_STORE_STRUCTURED: + // should really implement this but assume threads/pixels are independent for now. + // for threads that sync or pixels (in a quad) it's not valid to assume no other thread + // has run far enough to interfere with stores/loads + + case OPCODE_NOP: + case OPCODE_CUSTOMDATA: + case OPCODE_SYNC: // might never need to implement this. Who knows! + break; + case OPCODE_DMOV: + case OPCODE_MOV: + s.SetDst(op.operands[0], op, srcOpers[0]); + break; + case OPCODE_DMOVC: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.u.x ? srcOpers[1].value.u.x : srcOpers[2].value.u.x, + srcOpers[0].value.u.x ? srcOpers[1].value.u.y : srcOpers[2].value.u.y, + srcOpers[0].value.u.y ? srcOpers[1].value.u.z : srcOpers[2].value.u.z, + srcOpers[0].value.u.y ? srcOpers[1].value.u.w : srcOpers[2].value.u.w)); + break; + case OPCODE_MOVC: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[0].value.i.x ? srcOpers[1].value.i.x : srcOpers[2].value.i.x, + srcOpers[0].value.i.y ? srcOpers[1].value.i.y : srcOpers[2].value.i.y, + srcOpers[0].value.i.z ? srcOpers[1].value.i.z : srcOpers[2].value.i.z, + srcOpers[0].value.i.w ? srcOpers[1].value.i.w : srcOpers[2].value.i.w)); + break; + case OPCODE_SWAPC: + s.SetDst(op.operands[0], op, ShaderVariable("", srcOpers[1].value.i.x ? srcOpers[3].value.i.x : srcOpers[2].value.i.x, + srcOpers[1].value.i.y ? srcOpers[3].value.i.y : srcOpers[2].value.i.y, + srcOpers[1].value.i.z ? srcOpers[3].value.i.z : srcOpers[2].value.i.z, + srcOpers[1].value.i.w ? srcOpers[3].value.i.w : srcOpers[2].value.i.w)); + + s.SetDst(op.operands[1], op, ShaderVariable("", srcOpers[1].value.i.x ? srcOpers[2].value.i.x : srcOpers[3].value.i.x, + srcOpers[1].value.i.y ? srcOpers[2].value.i.y : srcOpers[3].value.i.y, + srcOpers[1].value.i.z ? srcOpers[2].value.i.z : srcOpers[3].value.i.z, + srcOpers[1].value.i.w ? srcOpers[2].value.i.w : srcOpers[3].value.i.w)); + break; + case OPCODE_ITOF: + s.SetDst(op.operands[0], op, ShaderVariable("", (float)srcOpers[0].value.i.x, + (float)srcOpers[0].value.i.y, + (float)srcOpers[0].value.i.z, + (float)srcOpers[0].value.i.w )); + break; + case OPCODE_UTOF: + s.SetDst(op.operands[0], op, ShaderVariable("", (float)srcOpers[0].value.u.x, + (float)srcOpers[0].value.u.y, + (float)srcOpers[0].value.u.z, + (float)srcOpers[0].value.u.w )); + break; + case OPCODE_FTOI: + s.SetDst(op.operands[0], op, ShaderVariable("", (int)srcOpers[0].value.f.x, + (int)srcOpers[0].value.f.y, + (int)srcOpers[0].value.f.z, + (int)srcOpers[0].value.f.w )); + break; + case OPCODE_FTOU: + s.SetDst(op.operands[0], op, ShaderVariable("", (uint32_t)srcOpers[0].value.f.x, + (uint32_t)srcOpers[0].value.f.y, + (uint32_t)srcOpers[0].value.f.z, + (uint32_t)srcOpers[0].value.f.w )); + break; + case OPCODE_FTOD: + { + double res[2]; + + res[0] = (double)srcOpers[0].value.f.x; + res[1] = (double)srcOpers[0].value.f.y; + + // if we only did a 1-wide double op, copy .xy into .zw so we can then + // swizzle into .xy or .zw freely on the destination operand. + // e.g. ftod r0.zw, r0.z - if we didn't do this, there'd be nothing valid in .zw + if(op.operands[1].comps[2] == 0xff) + res[1] = res[0]; + + ShaderVariable r("", 0U, 0U, 0U, 0U); + DoubleSet(r, res); + + s.SetDst(op.operands[0], op, r); + break; + } + case OPCODE_DTOF: + { + double src[2]; + DoubleGet(srcOpers[0], src); + + // special behaviour for dest mask. if it's .xz then first comparison goes into .x, second into .z. + // if the mask is .y then the first comparison goes into .y and second goes nowhere. + // so we need to check the dest mask and put the comparison results into the right place + + ShaderVariable r("", 0U, 0U, 0U, 0U); + + if(op.operands[0].comps[1] == 0xff) // only one mask + { + r.value.fv[ op.operands[0].comps[0] ] = float(src[0]); + } + else + { + r.value.fv[ op.operands[0].comps[0] ] = float(src[0]); + r.value.fv[ op.operands[0].comps[1] ] = float(src[1]); + } + + s.SetDst(op.operands[0], op, r); + break; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Comparison + + case OPCODE_EQ: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.f.x == srcOpers[1].value.f.x ? ~0l : 0l), + (srcOpers[0].value.f.y == srcOpers[1].value.f.y ? ~0l : 0l), + (srcOpers[0].value.f.z == srcOpers[1].value.f.z ? ~0l : 0l), + (srcOpers[0].value.f.w == srcOpers[1].value.f.w ? ~0l : 0l) )); + break; + case OPCODE_NE: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.f.x != srcOpers[1].value.f.x ? ~0l : 0l), + (srcOpers[0].value.f.y != srcOpers[1].value.f.y ? ~0l : 0l), + (srcOpers[0].value.f.z != srcOpers[1].value.f.z ? ~0l : 0l), + (srcOpers[0].value.f.w != srcOpers[1].value.f.w ? ~0l : 0l) )); + break; + case OPCODE_LT: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.f.x < srcOpers[1].value.f.x ? ~0l : 0l), + (srcOpers[0].value.f.y < srcOpers[1].value.f.y ? ~0l : 0l), + (srcOpers[0].value.f.z < srcOpers[1].value.f.z ? ~0l : 0l), + (srcOpers[0].value.f.w < srcOpers[1].value.f.w ? ~0l : 0l) )); + break; + case OPCODE_GE: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.f.x >= srcOpers[1].value.f.x ? ~0l : 0l), + (srcOpers[0].value.f.y >= srcOpers[1].value.f.y ? ~0l : 0l), + (srcOpers[0].value.f.z >= srcOpers[1].value.f.z ? ~0l : 0l), + (srcOpers[0].value.f.w >= srcOpers[1].value.f.w ? ~0l : 0l) )); + break; + case OPCODE_DEQ: + case OPCODE_DNE: + case OPCODE_DGE: + case OPCODE_DLT: + { + double src0[2], src1[2]; + DoubleGet(srcOpers[0], src0); DoubleGet(srcOpers[1], src1); + + uint32_t cmp1 = 0; + uint32_t cmp2 = 0; + + switch(op.operation) + { + case OPCODE_DEQ: + cmp1 = (src0[0] == src1[0] ? ~0l : 0l); + cmp2 = (src0[1] == src1[1] ? ~0l : 0l); + break; + case OPCODE_DNE: + cmp1 = (src0[0] != src1[0] ? ~0l : 0l); + cmp2 = (src0[1] != src1[1] ? ~0l : 0l); + break; + case OPCODE_DGE: + cmp1 = (src0[0] >= src1[0] ? ~0l : 0l); + cmp2 = (src0[1] >= src1[1] ? ~0l : 0l); + break; + case OPCODE_DLT: + cmp1 = (src0[0] < src1[0] ? ~0l : 0l); + cmp2 = (src0[1] < src1[1] ? ~0l : 0l); + break; + } + + // special behaviour for dest mask. if it's .xz then first comparison goes into .x, second into .z. + // if the mask is .y then the first comparison goes into .y and second goes nowhere. + // so we need to check the dest mask and put the comparison results into the right place + + ShaderVariable r("", 0U, 0U, 0U, 0U); + + if(op.operands[0].comps[1] == 0xff) // only one mask + { + r.value.uv[ op.operands[0].comps[0] ] = cmp1; + } + else + { + r.value.uv[ op.operands[0].comps[0] ] = cmp1; + r.value.uv[ op.operands[0].comps[1] ] = cmp2; + } + + s.SetDst(op.operands[0], op, r); + break; + } + case OPCODE_IEQ: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.i.x == srcOpers[1].value.i.x ? ~0l : 0l), + (srcOpers[0].value.i.y == srcOpers[1].value.i.y ? ~0l : 0l), + (srcOpers[0].value.i.z == srcOpers[1].value.i.z ? ~0l : 0l), + (srcOpers[0].value.i.w == srcOpers[1].value.i.w ? ~0l : 0l) )); + break; + case OPCODE_INE: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.i.x != srcOpers[1].value.i.x ? ~0l : 0l), + (srcOpers[0].value.i.y != srcOpers[1].value.i.y ? ~0l : 0l), + (srcOpers[0].value.i.z != srcOpers[1].value.i.z ? ~0l : 0l), + (srcOpers[0].value.i.w != srcOpers[1].value.i.w ? ~0l : 0l) )); + break; + case OPCODE_IGE: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.i.x >= srcOpers[1].value.i.x ? ~0l : 0l), + (srcOpers[0].value.i.y >= srcOpers[1].value.i.y ? ~0l : 0l), + (srcOpers[0].value.i.z >= srcOpers[1].value.i.z ? ~0l : 0l), + (srcOpers[0].value.i.w >= srcOpers[1].value.i.w ? ~0l : 0l) )); + break; + case OPCODE_ILT: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.i.x < srcOpers[1].value.i.x ? ~0l : 0l), + (srcOpers[0].value.i.y < srcOpers[1].value.i.y ? ~0l : 0l), + (srcOpers[0].value.i.z < srcOpers[1].value.i.z ? ~0l : 0l), + (srcOpers[0].value.i.w < srcOpers[1].value.i.w ? ~0l : 0l) )); + break; + case OPCODE_ULT: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.u.x < srcOpers[1].value.u.x ? ~0l : 0l), + (srcOpers[0].value.u.y < srcOpers[1].value.u.y ? ~0l : 0l), + (srcOpers[0].value.u.z < srcOpers[1].value.u.z ? ~0l : 0l), + (srcOpers[0].value.u.w < srcOpers[1].value.u.w ? ~0l : 0l) )); + break; + case OPCODE_UGE: + s.SetDst(op.operands[0], op, ShaderVariable("", + (srcOpers[0].value.u.x >= srcOpers[1].value.u.x ? ~0l : 0l), + (srcOpers[0].value.u.y >= srcOpers[1].value.u.y ? ~0l : 0l), + (srcOpers[0].value.u.z >= srcOpers[1].value.u.z ? ~0l : 0l), + (srcOpers[0].value.u.w >= srcOpers[1].value.u.w ? ~0l : 0l) )); + break; + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Atomic instructions + + case OPCODE_IMM_ATOMIC_ALLOC: + { + uint32_t count = global.uavs[srcOpers[0].value.u.x].hiddenCounter++; + s.SetDst(op.operands[0], op, ShaderVariable("", count, count, count, count)); + break; + } + + case OPCODE_IMM_ATOMIC_CONSUME: + { + uint32_t count = global.uavs[srcOpers[0].value.u.x].hiddenCounter--; + s.SetDst(op.operands[0], op, ShaderVariable("", count, count, count, count)); + break; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Derivative instructions + + // don't differentiate, coarse, fine, whatever. The spec lets us implement it all as fine. + case OPCODE_DERIV_RTX: + case OPCODE_DERIV_RTX_COARSE: + case OPCODE_DERIV_RTX_FINE: + if(quad == NULL) + RDCERR("Attempt to use derivative instruction not in pixel shader. Undefined results will occur!"); + else + s.SetDst(op.operands[0], op, s.DDX(quad, op.operands[1], op)); + break; + case OPCODE_DERIV_RTY: + case OPCODE_DERIV_RTY_COARSE: + case OPCODE_DERIV_RTY_FINE: + if(quad == NULL) + RDCERR("Attempt to use derivative instruction not in pixel shader. Undefined results will occur!"); + else + s.SetDst(op.operands[0], op, s.DDY(quad, op.operands[1], op)); + break; + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Buffer/Texture sampling + + case OPCODE_LD_RAW: + case OPCODE_LD_UAV_TYPED: + case OPCODE_LD_STRUCTURED: + { + uint32_t resIndex = 0; + uint32_t elemOffset = 0; + uint32_t elemIdx = 0; + + uint32_t stride = 0; + + bool srv = true; + + if(op.operation == OPCODE_LD_STRUCTURED) + { + resIndex = srcOpers[2].value.u.x; + elemOffset = srcOpers[1].value.u.x; + elemIdx = srcOpers[0].value.u.x; + + for(size_t i=0; i < s.dxbc->m_Declarations.size(); i++) + { + ASMDecl &decl = s.dxbc->m_Declarations[i]; + + if(decl.operand.indices.size() == 1 && decl.operand.indices[0] == op.operands[3].indices[0]) + { + if(decl.declaration == OPCODE_DCL_RESOURCE_STRUCTURED && decl.operand.type == TYPE_RESOURCE) + { + stride = decl.stride; + srv = true; + } + if(decl.declaration == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED && decl.operand.type == TYPE_UNORDERED_ACCESS_VIEW) + { + stride = decl.stride; + srv = false; + } + } + } + } + else if(op.operation == OPCODE_LD_UAV_TYPED) + { + resIndex = (uint32_t)op.operands[2].indices[0].index; + elemIdx = srcOpers[0].value.u.x; + stride = 4; + srv = false; + } + else if(op.operation == OPCODE_LD_RAW) + { + resIndex = (uint32_t)op.operands[2].indices[0].index; + elemIdx = srcOpers[0].value.u.x; + stride = 1; + + if(op.operands[2].type == TYPE_UNORDERED_ACCESS_VIEW) + srv = false; + } + + RDCASSERT(stride != 0); + + uint32_t offset = srv ? global.srvs[resIndex].firstElement : global.uavs[resIndex].firstElement; + uint32_t numElems = srv ? global.srvs[resIndex].numElements : global.uavs[resIndex].numElements; + + byte *data = srv ? &global.srvs[resIndex].data[0] : &global.uavs[resIndex].data[0]; + + RDCASSERT(data); + + data += (offset + elemIdx)*stride; + data += elemOffset; + + if(offset + elemIdx >= numElems) + { + s.SetDst(op.operands[0], op, ShaderVariable("", 0U, 0U, 0U, 0U)); + } + else + { + uint32_t *srcData = (uint32_t *)data; + + ShaderVariable fetch("", 0U, 0U, 0U, 0U); + + for(int i=0; i < 4; i++) + { + uint8_t comp = op.operands[3].comps[i]; + if(op.operands[3].comps[i] == 0xff) + comp = 0; + + fetch.value.uv[i] = srcData[comp]; + } + + s.SetDst(op.operands[0], op, fetch); + } + + break; + } + + case OPCODE_BUFINFO: + { + ID3D11DeviceContext *context = NULL; + device->GetReal()->GetImmediateContext(&context); + + if(op.operands[1].indices.size() == 1 && + op.operands[1].indices[0].absolute && + !op.operands[1].indices[0].relative) + { + UINT slot = (UINT)(op.operands[1].indices[0].index&0xffffffff); + + ShaderVariable result("", 0U, 0U, 0U, 0U); + + if(op.operands[1].type == TYPE_UNORDERED_ACCESS_VIEW) + { + ID3D11UnorderedAccessView *uav = NULL; + if(s.dxbc->m_Type == D3D11_SHVER_PIXEL_SHADER) + context->OMGetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, slot, 1, &uav); + else if(s.dxbc->m_Type == D3D11_SHVER_COMPUTE_SHADER) + context->CSGetUnorderedAccessViews(slot, 1, &uav); + else + RDCERR("Trying to get UAV bufinfo in shader other than pixel and compute!"); + + if(uav) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uav->GetDesc(&uavDesc); + + if(uavDesc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER) + { + result.value.u.x = result.value.u.y = + result.value.u.z = result.value.u.w = uavDesc.Buffer.NumElements; + } + else + { + RDCERR("Unexpected UAV dimension %d passed to bufinfo", uavDesc.ViewDimension); + } + } + else + { + RDCERR("UAV is NULL being queried by bufinfo"); + } + + SAFE_RELEASE(uav); + } + else + { + ID3D11ShaderResourceView *srv = NULL; + if(s.dxbc->m_Type == D3D11_SHVER_VERTEX_SHADER) + context->VSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_HULL_SHADER) + context->HSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_DOMAIN_SHADER) + context->DSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_GEOMETRY_SHADER) + context->GSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_PIXEL_SHADER) + context->PSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_COMPUTE_SHADER) + context->CSGetShaderResources(slot, 1, &srv); + + if(srv) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srv->GetDesc(&srvDesc); + + if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_BUFFER) + { + result.value.u.x = result.value.u.y = + result.value.u.z = result.value.u.w = srvDesc.Buffer.NumElements; + } + else if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) + { + result.value.u.x = result.value.u.y = + result.value.u.z = result.value.u.w = srvDesc.BufferEx.NumElements; + } + else + { + RDCERR("Unexpected SRV dimension %d passed to bufinfo", srvDesc.ViewDimension); + } + } + else + { + RDCERR("SRV is NULL being queried by bufinfo"); + } + + SAFE_RELEASE(srv); + } + + // apply swizzle + ShaderVariable swizzled("", 0.0f, 0.0f, 0.0f, 0.0f); + + for(int i=0; i < 4; i++) + { + if(op.operands[2].comps[i] == 0xff) + swizzled.value.uv[i] = result.value.uv[0]; + else + swizzled.value.uv[i] = result.value.uv[op.operands[2].comps[i]]; + } + + // apply ret type + if(op.resinfoRetType == RETTYPE_FLOAT) + { + result.value.f.x = (float)swizzled.value.u.x; + result.value.f.y = (float)swizzled.value.u.y; + result.value.f.z = (float)swizzled.value.u.z; + result.value.f.w = (float)swizzled.value.u.w; + } + else if(op.resinfoRetType == RETTYPE_RCPFLOAT) + { + result.value.f.x = 1.0f/(float)swizzled.value.u.x; + result.value.f.y = 1.0f/(float)swizzled.value.u.y; + result.value.f.z = 1.0f/(float)swizzled.value.u.z; + result.value.f.w = 1.0f/(float)swizzled.value.u.w; + } + else if(op.resinfoRetType == RETTYPE_UINT) + { + result = swizzled; + } + + s.SetDst(op.operands[0], op, result); + } + else + { + RDCERR("Unexpected relative addressing"); + s.SetDst(op.operands[0], op, ShaderVariable("", 0.0f, 0.0f, 0.0f, 0.0f)); + } + + SAFE_RELEASE(context); + + break; + } + + case OPCODE_RESINFO: + { + // spec says "srcMipLevel is read as an unsigned integer scalar" + uint32_t mipLevel = srcOpers[0].value.u.x; + + ID3D11DeviceContext *context = NULL; + device->GetReal()->GetImmediateContext(&context); + + if(op.operands[2].indices.size() == 1 && + op.operands[2].indices[0].absolute && + !op.operands[2].indices[0].relative) + { + UINT slot = (UINT)(op.operands[2].indices[0].index&0xffffffff); + + ShaderVariable result("", 0.0f, 0.0f, 0.0f, 0.0f); + + int dim = 0; + + if(op.operands[2].type != TYPE_UNORDERED_ACCESS_VIEW) + { + ID3D11ShaderResourceView *srv = NULL; + if(s.dxbc->m_Type == D3D11_SHVER_VERTEX_SHADER) + context->VSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_HULL_SHADER) + context->HSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_DOMAIN_SHADER) + context->DSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_GEOMETRY_SHADER) + context->GSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_PIXEL_SHADER) + context->PSGetShaderResources(slot, 1, &srv); + else if(s.dxbc->m_Type == D3D11_SHVER_COMPUTE_SHADER) + context->CSGetShaderResources(slot, 1, &srv); + + if(srv) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srv->GetDesc(&srvDesc); + + switch(srvDesc.ViewDimension) + { + case D3D11_SRV_DIMENSION_BUFFER: + { + dim = 1; + + result.value.u.x = srvDesc.Buffer.NumElements; + result.value.u.y = 0; + result.value.u.z = 0; + result.value.u.w = 0; + break; + } + case D3D11_SRV_DIMENSION_BUFFEREX: + { + dim = 1; + + result.value.u.x = srvDesc.BufferEx.NumElements; + result.value.u.y = 0; + result.value.u.z = 0; + result.value.u.w = 0; + break; + } + case D3D11_SRV_DIMENSION_TEXTURE1D: + case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: + { + ID3D11Texture1D *tex = NULL; + srv->GetResource((ID3D11Resource **)&tex); + + dim = 1; + + if(tex) + { + bool isarray = srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY; + + D3D11_TEXTURE1D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = isarray ? srvDesc.Texture1DArray.ArraySize : 0; + result.value.u.z = 0; + result.value.u.w = isarray ? srvDesc.Texture1DArray.MipLevels : srvDesc.Texture1D.MipLevels; + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = 0; + + SAFE_RELEASE(tex); + } + break; + } + case D3D11_SRV_DIMENSION_TEXTURE2D: + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + case D3D11_SRV_DIMENSION_TEXTURE2DMS: + case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: + { + ID3D11Texture2D *tex = NULL; + srv->GetResource((ID3D11Resource **)&tex); + + dim = 2; + + if(tex) + { + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = RDCMAX(1U, desc.Height >> mipLevel); + + if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D) + { + result.value.u.z = 0; + result.value.u.w = srvDesc.Texture2D.MipLevels; + } + else if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DARRAY) + { + result.value.u.z = srvDesc.Texture2DArray.ArraySize; + result.value.u.w = srvDesc.Texture2DArray.MipLevels; + } + else if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMS) + { + result.value.u.z = 0; + result.value.u.w = 1; + } + else if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY) + { + result.value.u.z = srvDesc.Texture2DMSArray.ArraySize; + result.value.u.w = 1; + } + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = result.value.u.z = 0; + + SAFE_RELEASE(tex); + } + break; + } + case D3D11_SRV_DIMENSION_TEXTURE3D: + { + ID3D11Texture3D *tex = NULL; + srv->GetResource((ID3D11Resource **)&tex); + + dim = 3; + + if(tex) + { + D3D11_TEXTURE3D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = RDCMAX(1U, desc.Height >> mipLevel); + result.value.u.z = RDCMAX(1U, desc.Depth >> mipLevel); + result.value.u.w = srvDesc.Texture3D.MipLevels; + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = result.value.u.z = 0; + + SAFE_RELEASE(tex); + } + break; + } + case D3D11_SRV_DIMENSION_TEXTURECUBE: + case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: + { + ID3D11Texture2D *tex = NULL; + srv->GetResource((ID3D11Resource **)&tex); + + dim = 2; + + if(tex) + { + bool isarray = srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY; + + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = RDCMAX(1U, desc.Height >> mipLevel); + + // the spec says "If srcResource is a TextureCubeArray, [...]. dest.z is set to an undefined value." + // but that's stupid, and implementations seem to return the number of cubes + result.value.u.z = isarray ? srvDesc.TextureCubeArray.NumCubes : 0; + result.value.u.w = isarray ? srvDesc.TextureCubeArray.MipLevels : srvDesc.TextureCube.MipLevels; + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = result.value.u.z = 0; + + SAFE_RELEASE(tex); + } + break; + } + } + + SAFE_RELEASE(srv); + } + } + else + { + ID3D11UnorderedAccessView *uav = NULL; + if(s.dxbc->m_Type == D3D11_SHVER_COMPUTE_SHADER) + { + context->CSGetUnorderedAccessViews(slot, 1, &uav); + } + else + { + ID3D11RenderTargetView *rtvs[8] = {0}; + ID3D11DepthStencilView *dsv = NULL; + context->OMGetRenderTargetsAndUnorderedAccessViews(0, rtvs, &dsv, slot, 1, &uav); + + for(int i=0; i < 8; i++) + SAFE_RELEASE(rtvs[i]); + SAFE_RELEASE(dsv); + } + + if(uav) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uav->GetDesc(&uavDesc); + + switch(uavDesc.ViewDimension) + { + case D3D11_UAV_DIMENSION_BUFFER: + { + ID3D11Buffer *buf = NULL; + uav->GetResource((ID3D11Resource **)&buf); + + dim = 1; + + if(buf) + { + D3D11_BUFFER_DESC desc; + buf->GetDesc(&desc); + result.value.u.x = desc.ByteWidth; + result.value.u.y = 0; + result.value.u.z = 0; + result.value.u.w = 0; + + SAFE_RELEASE(buf); + } + break; + } + case D3D11_UAV_DIMENSION_TEXTURE1D: + case D3D11_UAV_DIMENSION_TEXTURE1DARRAY: + { + ID3D11Texture1D *tex = NULL; + uav->GetResource((ID3D11Resource **)&tex); + + dim = 1; + + if(tex) + { + bool isarray = uavDesc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1DARRAY; + + D3D11_TEXTURE1D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = isarray ? uavDesc.Texture1DArray.ArraySize : 0; + result.value.u.z = 0; + + // spec says "For UAVs (u#), the number of mip levels is always 1." + result.value.u.w = 1; + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = 0; + + SAFE_RELEASE(tex); + } + break; + } + case D3D11_UAV_DIMENSION_TEXTURE2D: + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + { + ID3D11Texture2D *tex = NULL; + uav->GetResource((ID3D11Resource **)&tex); + + dim = 2; + + if(tex) + { + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = RDCMAX(1U, desc.Height >> mipLevel); + + if(uavDesc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2D) + result.value.u.z = 0; + else if(uavDesc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2DARRAY) + result.value.u.z = uavDesc.Texture2DArray.ArraySize; + + // spec says "For UAVs (u#), the number of mip levels is always 1." + result.value.u.w = 1; + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = result.value.u.z = 0; + + SAFE_RELEASE(tex); + } + break; + } + case D3D11_UAV_DIMENSION_TEXTURE3D: + { + ID3D11Texture3D *tex = NULL; + uav->GetResource((ID3D11Resource **)&tex); + + dim = 3; + + if(tex) + { + D3D11_TEXTURE3D_DESC desc; + tex->GetDesc(&desc); + result.value.u.x = RDCMAX(1U, desc.Width >> mipLevel); + result.value.u.y = RDCMAX(1U, desc.Height >> mipLevel); + result.value.u.z = RDCMAX(1U, desc.Depth >> mipLevel); + + // spec says "For UAVs (u#), the number of mip levels is always 1." + result.value.u.w = 1; + + if(mipLevel >= result.value.u.w) + result.value.u.x = result.value.u.y = result.value.u.z = 0; + + SAFE_RELEASE(tex); + } + break; + } + } + + SAFE_RELEASE(uav); + } + } + + // need a valid dimension even if the resource was unbound, so + // search for the declaration + if(dim == 0) + { + for(size_t i=0; i < s.dxbc->m_Declarations.size(); i++) + { + ASMDecl &decl = s.dxbc->m_Declarations[i]; + + if(decl.declaration == OPCODE_DCL_RESOURCE && decl.operand.type == TYPE_RESOURCE && + decl.operand.indices.size() == 1 && decl.operand.indices[0] == op.operands[2].indices[0]) + { + switch(decl.dim) + { + case RESOURCE_DIMENSION_BUFFER: + case RESOURCE_DIMENSION_RAW_BUFFER: + case RESOURCE_DIMENSION_STRUCTURED_BUFFER: + case RESOURCE_DIMENSION_TEXTURE1D: + case RESOURCE_DIMENSION_TEXTURE1DARRAY: + dim = 1; + break; + case RESOURCE_DIMENSION_TEXTURE2D: + case RESOURCE_DIMENSION_TEXTURE2DMS: + case RESOURCE_DIMENSION_TEXTURE2DARRAY: + case RESOURCE_DIMENSION_TEXTURE2DMSARRAY: + case RESOURCE_DIMENSION_TEXTURECUBE: + case RESOURCE_DIMENSION_TEXTURECUBEARRAY: + dim = 2; + break; + case RESOURCE_DIMENSION_TEXTURE3D: + dim = 3; + break; + } + break; + } + } + } + + // apply swizzle + ShaderVariable swizzled("", 0.0f, 0.0f, 0.0f, 0.0f); + + for(int i=0; i < 4; i++) + { + if(op.operands[2].comps[i] == 0xff) + swizzled.value.uv[i] = result.value.uv[0]; + else + swizzled.value.uv[i] = result.value.uv[op.operands[2].comps[i]]; + } + + // apply ret type + if(op.resinfoRetType == RETTYPE_FLOAT) + { + result.value.f.x = (float)swizzled.value.u.x; + result.value.f.y = (float)swizzled.value.u.y; + result.value.f.z = (float)swizzled.value.u.z; + result.value.f.w = (float)swizzled.value.u.w; + } + else if(op.resinfoRetType == RETTYPE_RCPFLOAT) + { + // only width/height/depth values we set are reciprocated, other values + // are just left as is + if(dim <= 1) + result.value.f.x = 1.0f/(float)swizzled.value.u.x; + else + result.value.f.x = (float)swizzled.value.u.x; + + if(dim <= 2) + result.value.f.y = 1.0f/(float)swizzled.value.u.y; + else + result.value.f.y = (float)swizzled.value.u.y; + + if(dim <= 3) + result.value.f.z = 1.0f/(float)swizzled.value.u.z; + else + result.value.f.z = (float)swizzled.value.u.z; + + result.value.f.w = (float)swizzled.value.u.w; + } + else if(op.resinfoRetType == RETTYPE_UINT) + { + result = swizzled; + } + + // if we are assigning into a scalar, SetDst expects the result to be in .x (as normally we are assigning FROM a scalar also). + // to match this expectation, propogate the component across. + if(op.operands[0].comps[0] != 0xff && op.operands[0].comps[0] != 0xff && op.operands[0].comps[0] != 0xff && op.operands[0].comps[0] != 0xff) + result.value.uv[ 0 ] = result.value.uv[ op.operands[0].comps[0] ]; + + s.SetDst(op.operands[0], op, result); + } + else + { + RDCERR("Unexpected relative addressing"); + s.SetDst(op.operands[0], op, ShaderVariable("", 0.0f, 0.0f, 0.0f, 0.0f)); + } + + SAFE_RELEASE(context); + + break; + } + case OPCODE_SAMPLE: + case OPCODE_SAMPLE_L: + case OPCODE_SAMPLE_B: + case OPCODE_SAMPLE_D: + case OPCODE_SAMPLE_C: + case OPCODE_SAMPLE_C_LZ: + case OPCODE_LD: + case OPCODE_LD_MS: + { + string sampler = ""; + string texture = ""; + string funcRet = ""; + DXGI_FORMAT retFmt = DXGI_FORMAT_UNKNOWN; + + bool useOffsets = true; + int texdim = 2; + int offsdim = 2; // ddN and offset dimension + + for(size_t i=0; i < s.dxbc->m_Declarations.size(); i++) + { + ASMDecl &decl = s.dxbc->m_Declarations[i]; + + if(decl.declaration == OPCODE_DCL_SAMPLER && decl.operand == op.operands[3]) + { + if(decl.samplerMode == SAMPLER_MODE_DEFAULT) + sampler = "SamplerState s"; + else if(decl.samplerMode == SAMPLER_MODE_COMPARISON) + sampler = "SamplerComparisonState s"; + else + RDCERR("Unsupported sampler type %d in sample operation", decl.samplerMode); + } + if(decl.dim == RESOURCE_DIMENSION_BUFFER && op.operation == OPCODE_LD && + decl.declaration == OPCODE_DCL_RESOURCE && decl.operand.type == TYPE_RESOURCE && + decl.operand.indices.size() == 1 && decl.operand.indices[0] == op.operands[2].indices[0]) + { + uint32_t resIndex = (uint32_t)decl.operand.indices[0].index; + + byte *data = &global.srvs[resIndex].data[0]; + uint32_t offset = global.srvs[resIndex].firstElement; + uint32_t numElems = global.srvs[resIndex].numElements; + + GlobalState::ViewFmt fmt = global.srvs[resIndex].format; + + data += fmt.Stride()*offset; + + ShaderVariable result; + + if(op.resinfoRetType == RETTYPE_FLOAT) + { + result = ShaderVariable("", 0.0f, 0.0f, 0.0f, 0.0f); + + if(srcOpers[0].value.uv[0] < numElems) + { + byte *d = data + srcOpers[0].value.uv[0]*fmt.Stride(); + + if(fmt.byteWidth == 10) + { + uint32_t u = *((uint32_t *)d); + + if(fmt.fmt == eCompType_UInt) + { + result.value.u.x = (u>> 0) & 0x3ff; + result.value.u.y = (u>>10) & 0x3ff; + result.value.u.z = (u>>20) & 0x3ff; + result.value.u.w = (u>>30) & 0x003; + } + else if(fmt.fmt == eCompType_UNorm) + { + Vec4f res = ConvertFromR10G10B10A2(u); + result.value.f.x = res.x; + result.value.f.y = res.y; + result.value.f.z = res.z; + result.value.f.w = res.w; + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + else if(fmt.byteWidth == 11) + { + uint32_t *u = (uint32_t *)d; + + Vec3f res = ConvertFromR11G11B10(*u); + result.value.f.x = res.x; + result.value.f.y = res.y; + result.value.f.z = res.z; + result.value.f.w = 1.0f; + } + else if(fmt.byteWidth == 4) + { + if(fmt.fmt == eCompType_Float) + { + float *f = (float *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.fv[i] = f[i]; + } + else if(fmt.fmt == eCompType_UInt) + { + uint32_t *u = (uint32_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.uv[i] = u[i]; + } + else if(fmt.fmt == eCompType_SInt) + { + int32_t *in = (int32_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.iv[i] = in[i]; + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + else if(fmt.byteWidth == 2) + { + if(fmt.fmt == eCompType_Float) + { + uint16_t *u = (uint16_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.fv[i] = ConvertFromHalf(u[i]); + } + else if(fmt.fmt == eCompType_UInt) + { + uint16_t *u = (uint16_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.uv[i] = u[i]; + } + else if(fmt.fmt == eCompType_SInt) + { + int16_t *in = (int16_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.iv[i] = in[i]; + } + else if(fmt.fmt == eCompType_UNorm) + { + uint16_t *u = (uint16_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.fv[i] = float(u[i])/float(0xffff); + } + else if(fmt.fmt == eCompType_SNorm) + { + int16_t *in = (int16_t *)d; + + for(int i=0; i < fmt.numComps; i++) + { + // -32768 is mapped to -1, then -32767 to -32767 are mapped to -1 to 1 + if(in[i] == -32768) + result.value.fv[i] = -1.0f; + else + result.value.fv[i] = float(in[i])/32767.0f; + } + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + else if(fmt.byteWidth == 1) + { + if(fmt.fmt == eCompType_UInt) + { + uint8_t *u = (uint8_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.uv[i] = u[i]; + } + else if(fmt.fmt == eCompType_SInt) + { + int8_t *in = (int8_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.iv[i] = in[i]; + } + else if(fmt.fmt == eCompType_UNorm) + { + uint8_t *u = (uint8_t *)d; + + for(int i=0; i < fmt.numComps; i++) + result.value.fv[i] = float(u[i])/float(0xff); + } + else if(fmt.fmt == eCompType_SNorm) + { + int8_t *in = (int8_t *)d; + + for(int i=0; i < fmt.numComps; i++) + { + // -128 is mapped to -1, then -127 to -127 are mapped to -1 to 1 + if(in[i] == -128) + result.value.fv[i] = -1.0f; + else + result.value.fv[i] = float(in[i])/127.0f; + } + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + + if(fmt.reversed) + result = ShaderVariable("", result.value.uv[0], result.value.uv[1], result.value.uv[2], result.value.uv[3]); + } + } + else + { + RDCERR("Unsupported ret type %d in buffer load operation", op.resinfoRetType); + } + + ShaderVariable fetch("", 0U, 0U, 0U, 0U); + + for(int i=0; i < 4; i++) + { + uint8_t comp = op.operands[2].comps[i]; + if(op.operands[2].comps[i] == 0xff) + comp = 0; + + fetch.value.uv[i] = result.value.uv[comp]; + } + + s.SetDst(op.operands[0], op, fetch); + + return s; + } + if(decl.declaration == OPCODE_DCL_RESOURCE && + decl.operand.type == TYPE_RESOURCE && + decl.operand.indices.size() == 1 && decl.operand.indices[0] == op.operands[2].indices[0]) + { + if(decl.dim == RESOURCE_DIMENSION_TEXTURE1D) + { + texture = "Texture1D"; + texdim = 1; + offsdim = 1; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURE2D) + { + texture = "Texture2D"; + texdim = 2; + offsdim = 2; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURE2DMS) + { + texture = "Texture2DMS"; + texdim = 2; + offsdim = 2; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURE3D) + { + texture = "Texture3D"; + texdim = 3; + offsdim = 3; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURECUBE) + { + texture = "TextureCube"; + texdim = 3; + offsdim = 3; + useOffsets = false; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY) + { + texture = "Texture1DArray"; + texdim = 2; + offsdim = 1; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY) + { + texture = "Texture2DArray"; + texdim = 3; + offsdim = 2; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) + { + texture = "Texture2DMSArray"; + texdim = 3; + offsdim = 2; + } + else if(decl.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY) + { + texture = "TextureCubeArray"; + texdim = 4; + offsdim = 3; + useOffsets = false; + } + else + { + RDCERR("Unsupported resource type %d in sample operation", decl.dim); + } + + // doesn't seem like these are ever less than four components, even if the texture is declared for example. + // shouldn't matter though is it just comes out in the wash. + RDCASSERT(decl.resType[0] == decl.resType[1] && decl.resType[1] == decl.resType[2] && decl.resType[2] == decl.resType[3]); + RDCASSERT(decl.resType[0] != RETURN_TYPE_CONTINUED && decl.resType[0] != RETURN_TYPE_UNUSED && decl.resType[0] != RETURN_TYPE_MIXED && + decl.resType[0] >= 0 && decl.resType[0] < NUM_RETURN_TYPES); + + char *typeStr[NUM_RETURN_TYPES] = { + "", // enum starts at ==1 + "unorm float", + "snorm float", + "int", + "uint", + "float", + "__", // RETURN_TYPE_MIXED + "double", + "__", // RETURN_TYPE_CONTINUED + "__", // RETURN_TYPE_UNUSED + }; + + // obviously these may be overly optimistic in some cases + // but since we don't know at debug time what the source texture format is + // we just use the fattest one necessary. There's no harm in retrieving at + // higher precision + DXGI_FORMAT fmts[NUM_RETURN_TYPES] = { + DXGI_FORMAT_UNKNOWN, // enum starts at ==1 + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_MIXED + + // should maybe be double, but there is no double texture format anyway! + // spec is unclear but I presume reads are done at most at float + // precision anyway since that's the source, and converted to doubles. + DXGI_FORMAT_R32G32B32A32_FLOAT, + + DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_CONTINUED + DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_UNUSED + }; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%hs4", typeStr[decl.resType[0]]); + + funcRet = buf; + retFmt = fmts[decl.resType[0]]; + + if(decl.dim == RESOURCE_DIMENSION_TEXTURE2DMS || decl.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) + { + if(decl.sampleCount > 0) + StringFormat::snprintf(buf, 63, "%hs4, %d", typeStr[decl.resType[0]], decl.sampleCount); + } + + texture += "<"; + texture += buf; + texture += "> t"; + } + } + + string sampleProgram; + + char buf[64] = {0}; + char buf2[64] = {0}; + char buf3[64] = {0}; + + ShaderVariable ddxCalc; + ShaderVariable ddyCalc; + + // these ops need DDX/DDY + if(op.operation == OPCODE_SAMPLE || + op.operation == OPCODE_SAMPLE_B || + op.operation == OPCODE_SAMPLE_C) + { + if(quad == NULL) + { + RDCERR("Attempt to use derivative instruction not in pixel shader. Undefined results will occur!"); + } + else + { + ddxCalc = s.DDX(quad, op.operands[1], op); + ddyCalc = s.DDY(quad, op.operands[1], op); + } + } + else if(op.operation == OPCODE_SAMPLE_D) + { + ddxCalc = srcOpers[3]; + ddyCalc = srcOpers[4]; + } + + // serious printf abuse below! + + char *formats[4][2] = { + { "float(%f)", "int(%d)" }, + { "float2(%f, %f)", "int2(%d, %d)" }, + { "float3(%f, %f, %f)", "int3(%d, %d, %d)" }, + { "float4(%f, %f, %f, %f)", "int4(%d, %d, %d, %d)" }, + }; + + int texcoordType = 0; + int ddxType = 0; + int ddyType = 0; + + int texdimOffs = 0; + + if(op.operation == OPCODE_SAMPLE || + op.operation == OPCODE_SAMPLE_L || + op.operation == OPCODE_SAMPLE_B || + op.operation == OPCODE_SAMPLE_D || + op.operation == OPCODE_SAMPLE_C || + op.operation == OPCODE_SAMPLE_C_LZ) + { + // all floats + texcoordType = ddxType = ddyType = 0; + } + else if(op.operation == OPCODE_LD) + { + // int address, one larger than texdim (to account for mip/slice parameter) + texdimOffs = 1; + texcoordType = 1; + + if(texdim == 4) + { + RDCERR("Unexpectedly large texture in load operation"); + } + } + else if(op.operation == OPCODE_LD_MS) + { + texcoordType = 1; + + if(texdim == 4) + { + RDCERR("Unexpectedly large texture in load operation"); + } + } + + ShaderVariable uv = srcOpers[0]; + + for(uint32_t i=0; i < ddxCalc.columns; i++) + { + if(_isnan(ddxCalc.value.fv[i]) || !_finite(ddxCalc.value.fv[i])) + { + RDCWARN("NaN or Inf in texlookup"); + ddxCalc.value.fv[i] = 0.0f; + } + if(_isnan(ddyCalc.value.fv[i]) || !_finite(ddyCalc.value.fv[i])) + { + RDCWARN("NaN or Inf in texlookup"); + ddyCalc.value.fv[i] = 0.0f; + } + if(_isnan(uv.value.fv[i]) || !_finite(uv.value.fv[i])) + { + RDCWARN("NaN or Inf in texlookup"); + uv.value.fv[i] = 0.0f; + } + } + + // because of unions in .value we can pass the float versions and printf will interpret it as the right type according to formats + if(texcoordType == 0) + StringFormat::snprintf(buf, 63, formats[texdim+texdimOffs-1][texcoordType], uv.value.f.x, uv.value.f.y, uv.value.f.z, uv.value.f.w); + else + StringFormat::snprintf(buf, 63, formats[texdim+texdimOffs-1][texcoordType], uv.value.i.x, uv.value.i.y, uv.value.i.z, uv.value.i.w); + + if(ddxType == 0) + StringFormat::snprintf(buf2, 63, formats[offsdim+texdimOffs-1][ddxType], ddxCalc.value.f.x, ddxCalc.value.f.y, ddxCalc.value.f.z, ddxCalc.value.f.w); + else + StringFormat::snprintf(buf2, 63, formats[offsdim+texdimOffs-1][ddxType], ddxCalc.value.i.x, ddxCalc.value.i.y, ddxCalc.value.i.z, ddxCalc.value.i.w); + + if(ddyType == 0) + StringFormat::snprintf(buf3, 63, formats[offsdim+texdimOffs-1][ddyType], ddyCalc.value.f.x, ddyCalc.value.f.y, ddyCalc.value.f.z, ddyCalc.value.f.w); + else + StringFormat::snprintf(buf3, 63, formats[offsdim+texdimOffs-1][ddyType], ddyCalc.value.i.x, ddyCalc.value.i.y, ddyCalc.value.i.z, ddyCalc.value.i.w); + + string texcoords = buf; + string ddx = buf2; + string ddy = buf3; + + if(op.operation == OPCODE_LD_MS) + { + StringFormat::snprintf(buf, 63, formats[0][1], srcOpers[2].value.i.x); + } + + string sampleIdx = buf; + + string offsets = ""; + + if(useOffsets) + { + if(offsdim == 1) + StringFormat::snprintf(buf, 63, ", int(%d)", op.texelOffset[0]); + if(offsdim == 2) + StringFormat::snprintf(buf, 63, ", int2(%d, %d)", op.texelOffset[0], op.texelOffset[1]); + if(offsdim == 3) + StringFormat::snprintf(buf, 63, ", int3(%d, %d, %d)", op.texelOffset[0], op.texelOffset[1], op.texelOffset[2]); + // texdim == 4 is cube arrays, no offset supported + + offsets = buf; + } + + string swizzle = "."; + + char elems[] = "xyzw"; + + for(int i=0; i < 4; i++) + { + if(op.operands[2].comps[i] == 0xff) + swizzle += "x"; + else + swizzle += elems[op.operands[2].comps[i]]; + } + + string vsProgram = "float4 main(uint id : SV_VertexID) : SV_Position {\n"; + vsProgram += "return float4((id == 2) ? 3.0f : -1.0f, (id == 0) ? -3.0f : 1.0f, 0.5, 1.0);\n"; + vsProgram += "}"; + + if(op.operation == OPCODE_SAMPLE || + op.operation == OPCODE_SAMPLE_B || + op.operation == OPCODE_SAMPLE_D) + { + sampleProgram = texture + " : register(t" + op.operands[2].indices[0].str + ");\n" + sampler + " : register(s" + op.operands[3].indices[0].str + ");\n\n"; + sampleProgram += funcRet + " main() : SV_Target0\n{\nreturn "; + sampleProgram += "t.SampleGrad(s, " + texcoords + ", " + ddx + ", " + ddy + offsets + ")" + swizzle + ";"; + sampleProgram += "\n}\n"; + } + else if(op.operation == OPCODE_SAMPLE_L) + { + // lod selection + StringFormat::snprintf(buf, 63, "%f", srcOpers[1].value.f.x); + + sampleProgram = texture + " : register(t" + op.operands[2].indices[0].str + ");\n" + sampler + " : register(s" + op.operands[3].indices[0].str + ");\n\n"; + sampleProgram += funcRet + " main() : SV_Target0\n{\nreturn "; + sampleProgram += "t.SampleLevel(s, " + texcoords + ", " + buf + offsets + ")" + swizzle + ";"; + sampleProgram += "\n}\n"; + } + else if(op.operation == OPCODE_SAMPLE_C) + { + string uvDim = "1"; + uvDim[0] += char(texdim+texdimOffs-1); + + vsProgram = "void main(uint id : SV_VertexID, out float4 pos : SV_Position, out float" + uvDim + " uv : uvs) {\n"; + + StringFormat::snprintf(buf, 63, formats[texdim+texdimOffs-1][texcoordType], + uv.value.f.x + ddyCalc.value.f.x*2.0f, + uv.value.f.y + ddyCalc.value.f.y*2.0f, + uv.value.f.z + ddyCalc.value.f.z*2.0f, + uv.value.f.w + ddyCalc.value.f.w*2.0f); + + vsProgram += "if(id == 0) uv = " + string(buf) + ";\n"; + + StringFormat::snprintf(buf, 63, formats[texdim+texdimOffs-1][texcoordType], uv.value.f.x, uv.value.f.y, uv.value.f.z, uv.value.f.w); + + vsProgram += "if(id == 1) uv = " + string(buf) + ";\n"; + + StringFormat::snprintf(buf, 63, formats[texdim+texdimOffs-1][texcoordType], + uv.value.f.x + ddxCalc.value.f.x*2.0f, + uv.value.f.y + ddxCalc.value.f.y*2.0f, + uv.value.f.z + ddxCalc.value.f.z*2.0f, + uv.value.f.w + ddxCalc.value.f.w*2.0f); + + vsProgram += "if(id == 2) uv = " + string(buf) + ";\n"; + + vsProgram += "pos = float4((id == 2) ? 3.0f : -1.0f, (id == 0) ? -3.0f : 1.0f, 0.5, 1.0);\n"; + vsProgram += "}"; + + // comparison value + StringFormat::snprintf(buf, 63, "%f", srcOpers[3].value.f.x); + + sampleProgram = texture + " : register(t" + op.operands[2].indices[0].str + ");\n" + sampler + " : register(s" + op.operands[3].indices[0].str + ");\n\n"; + sampleProgram += funcRet + " main(float4 pos : SV_Position, float" + uvDim + " uv : uvs) : SV_Target0\n{\n"; + sampleProgram += "return t.SampleCmpLevelZero(s, uv, " + string(buf) + offsets + ").xxxx;"; + sampleProgram += "\n}\n"; + } + else if(op.operation == OPCODE_SAMPLE_C_LZ) + { + // comparison value + StringFormat::snprintf(buf, 63, "%f", srcOpers[3].value.f.x); + + sampleProgram = texture + " : register(t" + op.operands[2].indices[0].str + ");\n" + sampler + " : register(s" + op.operands[3].indices[0].str + ");\n\n"; + sampleProgram += funcRet + " main() : SV_Target0\n{\nreturn "; + sampleProgram += "t.SampleCmpLevelZero(s, " + texcoords + ", " + buf + offsets + ")" + swizzle + ";"; + sampleProgram += "\n}\n"; + } + else if(op.operation == OPCODE_LD) + { + sampleProgram = texture + " : register(t" + op.operands[2].indices[0].str + ");\n\n"; + sampleProgram += funcRet + " main() : SV_Target0\n{\nreturn "; + sampleProgram += "t.Load(" + texcoords + offsets + ")" + swizzle + ";"; + sampleProgram += "\n}\n"; + } + else if(op.operation == OPCODE_LD_MS) + { + sampleProgram = texture + " : register(t" + op.operands[2].indices[0].str + ");\n\n"; + sampleProgram += funcRet + " main() : SV_Target0\n{\nreturn "; + sampleProgram += "t.Load(" + texcoords + ", " + sampleIdx + offsets + ")" + swizzle + ";"; + sampleProgram += "\n}\n"; + } + + ID3D11VertexShader *vs = device->GetDebugManager()->MakeVShader(vsProgram.c_str(), "main", "vs_4_0"); + ID3D11PixelShader *ps = device->GetDebugManager()->MakePShader(sampleProgram.c_str(), "main", "ps_5_0"); + + ID3D11DeviceContext *context = NULL; + + device->GetReal()->GetImmediateContext(&context); + + context->IASetInputLayout(NULL); + context->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + context->VSSetShader(vs, NULL, 0); + context->PSSetShader(ps, NULL, 0); + + // for bias instruction we can't do a SampleGradBias, so add the bias into the sampler state. + if(op.operation == OPCODE_SAMPLE_B) + { + ID3D11SamplerState *samp = NULL; + + context->PSGetSamplers((UINT)srcOpers[2].value.u.x, 1, &samp); + + RDCASSERT(samp); + + D3D11_SAMPLER_DESC desc; + + samp->GetDesc(&desc); + + SAFE_RELEASE(samp); + + desc.MipLODBias = RDCCLAMP(desc.MipLODBias + srcOpers[3].value.f.x, -15.999f, 15.999f); + + ID3D11SamplerState *replacementSamp = NULL; + + HRESULT hr = device->GetReal()->CreateSamplerState(&desc, &replacementSamp); + + if(FAILED(hr)) + { + RDCERR("Failed to create new sampler state in debugging %08x", hr); + } + else + { + context->PSSetSamplers((UINT)srcOpers[2].value.u.x, 1, &replacementSamp); + + SAFE_RELEASE(replacementSamp); + } + } + + D3D11_VIEWPORT view = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }; + context->RSSetViewports(1, &view); + + context->GSSetShader(NULL, NULL, 0); + context->DSSetShader(NULL, NULL, 0); + context->HSSetShader(NULL, NULL, 0); + context->CSSetShader(NULL, NULL, 0); + + context->SOSetTargets(0, NULL, NULL); + + context->RSSetState(NULL); + context->OMSetBlendState(NULL, NULL, (UINT)~0); + context->OMSetDepthStencilState(NULL, 0); + + ID3D11RenderTargetView *rtv = NULL; + + ID3D11Texture2D *rtTex = NULL; + ID3D11Texture2D *copyTex = NULL; + + D3D11_TEXTURE2D_DESC tdesc; + + RDCASSERT(retFmt != DXGI_FORMAT_UNKNOWN); + + tdesc.ArraySize = 1; + tdesc.BindFlags = D3D11_BIND_RENDER_TARGET; + tdesc.CPUAccessFlags = 0; + tdesc.Format = retFmt; + tdesc.Width = 1; + tdesc.Height = 1; + tdesc.MipLevels = 0; + tdesc.MiscFlags = 0; + tdesc.SampleDesc.Count = 1; + tdesc.SampleDesc.Quality = 0; + tdesc.Usage = D3D11_USAGE_DEFAULT; + + HRESULT hr = S_OK; + + hr = device->GetReal()->CreateTexture2D(&tdesc, NULL, &rtTex); + + if(FAILED(hr)) + { + RDCERR("Failed to create RT tex %08x", hr); + return s; + } + + tdesc.BindFlags = 0; + tdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + tdesc.Usage = D3D11_USAGE_STAGING; + + hr = device->GetReal()->CreateTexture2D(&tdesc, NULL, ©Tex); + + if(FAILED(hr)) + { + RDCERR("Failed to create copy tex %08x", hr); + return s; + } + + D3D11_RENDER_TARGET_VIEW_DESC rtDesc; + + rtDesc.Format = retFmt; + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtDesc.Texture2D.MipSlice = 0; + + hr = device->GetReal()->CreateRenderTargetView(rtTex, &rtDesc, &rtv); + + if(FAILED(hr)) + { + RDCERR("Failed to create rt rtv %08x", hr); + return s; + } + + context->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtv, NULL, 0, 0, NULL, NULL); + context->Draw(3, 0); + + context->CopyResource(copyTex, rtTex); + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = context->Map(copyTex, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map results %08x", hr); + return s; + } + + ShaderVariable lookupResult("tex", 0.0f, 0.0f, 0.0f, 0.0f); + + memcpy(lookupResult.value.iv, mapped.pData, sizeof(uint32_t)*4); + + context->Unmap(copyTex, 0); + + SAFE_RELEASE(rtTex); + SAFE_RELEASE(copyTex); + SAFE_RELEASE(rtv); + SAFE_RELEASE(vs); + SAFE_RELEASE(ps); + SAFE_RELEASE(context); + + // should be a better way of doing this + if(op.operands[0].comps[1] == 0xff) + lookupResult.value.iv[0] = lookupResult.value.iv[ op.operands[0].comps[0] ]; + + s.SetDst(op.operands[0], op, lookupResult); + break; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // Flow control + + case OPCODE_SWITCH: + { + uint32_t switchValue = GetSrc(op.operands[0], op).value.u.x; + + int depth = 0; + + uint32_t jumpLocation = 0; + + uint32_t search = s.nextInstruction; + + for(; search < (int)dxbc->m_Instructions.size(); search++) + { + const ASMOperation &nextOp = s.dxbc->m_Instructions[search]; + + // track nested switch statements to ensure we don't accidentally pick the case from a different switch + if(nextOp.operation == OPCODE_SWITCH) + { + depth++; + } + else if(nextOp.operation == OPCODE_ENDSWITCH) + { + depth--; + } + else if(depth == 0) + { + // note the default: location as jumpLocation if we haven't found a matching + // case yet. If we find one later, this will be overridden + if(nextOp.operation == OPCODE_DEFAULT) + jumpLocation = search; + + // reached end of our switch statement + if(nextOp.operation == OPCODE_ENDSWITCH) + break; + + if(nextOp.operation == OPCODE_CASE) + { + uint32_t caseValue = GetSrc(nextOp.operands[0], nextOp).value.u.x; + + // comparison is defined to be bitwise + if(caseValue == switchValue) + { + // we've found our case, break out + jumpLocation = search; + break; + } + } + } + } + + // jumpLocation points to the case we're taking, either a matching case or default + + if(jumpLocation == 0) + { + RDCERR("Didn't find matching case or default: for switch(%u)!", switchValue); + } + else + { + // skip straight past any case or default labels as we don't want to step to them, we want next instruction to point + // at the next excutable instruction (which might be a break if we're doing nothing) + for(; jumpLocation < (int)dxbc->m_Instructions.size(); jumpLocation++) + { + const ASMOperation &nextOp = s.dxbc->m_Instructions[jumpLocation]; + + if(nextOp.operation != OPCODE_CASE && nextOp.operation != OPCODE_DEFAULT) + break; + } + + s.nextInstruction = jumpLocation; + } + + break; + } + case OPCODE_CASE: + case OPCODE_DEFAULT: + case OPCODE_LOOP: + case OPCODE_ENDSWITCH: + // do nothing. Basically just an anonymous label that is used elsewhere (SWITCH/ENDLOOP/BREAK) + break; + case OPCODE_CONTINUE: + case OPCODE_CONTINUEC: + case OPCODE_ENDLOOP: + { + int depth = 0; + + int32_t test = op.operation == OPCODE_CONTINUEC ? GetSrc(op.operands[0], op).value.i.x : 0; + + if(op.operation == OPCODE_CONTINUE || op.operation == OPCODE_CONTINUEC) + depth = 1; + + if( + (test == 0 && !op.nonzero) || + (test != 0 && op.nonzero) || + op.operation == OPCODE_CONTINUE || + op.operation == OPCODE_ENDLOOP + ) + { + // skip back one to the endloop that we're processing + s.nextInstruction--; + + for(; s.nextInstruction >= 0; s.nextInstruction--) + { + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDLOOP) + depth++; + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_LOOP) + depth--; + + if(depth == 0) + { + break; + } + } + + RDCASSERT(s.nextInstruction >= 0); + } + + break; + } + case OPCODE_BREAK: + case OPCODE_BREAKC: + { + int32_t test = op.operation == OPCODE_BREAKC ? GetSrc(op.operands[0], op).value.i.x : 0; + + if( + (test == 0 && !op.nonzero) || + (test != 0 && op.nonzero) || + op.operation == OPCODE_BREAK + ) + { + // break out (jump to next endloop/endswitch) + int depth = 1; + + for(; s.nextInstruction < (int)dxbc->m_Instructions.size(); s.nextInstruction++) + { + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_LOOP || + s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_SWITCH) + depth++; + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDLOOP || + s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDSWITCH) + depth--; + + if(depth == 0) + { + break; + } + } + + RDCASSERT(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDLOOP || + s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDSWITCH); + + // don't want to process the endloop and jump again! + s.nextInstruction++; + } + + break; + } + case OPCODE_IF: + { + int32_t test = GetSrc(op.operands[0], op).value.i.x; + + if( + (test == 0 && !op.nonzero) || + (test != 0 && op.nonzero) + ) + { + // nothing, we go into the if. + } + else + { + // jump to after the next matching else/endif + int depth = 0; + + // skip back one to the if that we're processing + s.nextInstruction--; + + for(; s.nextInstruction < (int)dxbc->m_Instructions.size(); s.nextInstruction++) + { + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_IF) + depth++; + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ELSE) + depth--; + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDIF) + depth--; + + if(depth == 0) + { + break; + } + } + + RDCASSERT(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ELSE || + s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDIF); + + // step to next instruction after the else/endif (processing an else would skip that block) + s.nextInstruction++; + } + + break; + } + case OPCODE_ELSE: + { + // if we hit an else then we've just processed the if() bracket and need to break out (jump to next endif) + int depth = 1; + + for(; s.nextInstruction < (int)dxbc->m_Instructions.size(); s.nextInstruction++) + { + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_IF) + depth++; + if(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDIF) + depth--; + + if(depth == 0) + { + break; + } + } + + RDCASSERT(s.dxbc->m_Instructions[s.nextInstruction].operation == OPCODE_ENDIF); + + break; + } + case OPCODE_ENDIF: + // do nothing. Basically just an anonymous label that is used in the IF/ELSE code. + break; + case OPCODE_DISCARD: + { + int32_t test = GetSrc(op.operands[0], op).value.i.x; + + if( + (test != 0 && !op.nonzero) || + (test == 0 && op.nonzero) + ) + { + // don't discard + break; + } + + // discarding. + s.done = true; + break; + } + case OPCODE_RET: + case OPCODE_RETC: + { + int32_t test = op.operation == OPCODE_RETC ? GetSrc(op.operands[0], op).value.i.x : 0; + + if( + (test == 0 && !op.nonzero) || + (test != 0 && op.nonzero) || + op.operation == OPCODE_RET + ) + { + // assumes not in a function call + s.done = true; + } + break; + } + default: + { + RDCERR("Unsupported operation %d in assembly debugging", op.operation); + break; + } + } + + return s; +} + +}; // namespace ShaderDebug \ No newline at end of file diff --git a/renderdoc/driver/d3d11/shaders/dxbc_debug.h b/renderdoc/driver/d3d11/shaders/dxbc_debug.h new file mode 100644 index 0000000000..c604c18c5d --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_debug.h @@ -0,0 +1,149 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + + +#pragma once + +#include "dxbc_disassemble.h" + +namespace DXBC { class DXBCFile; struct CBufferVariable; } + +class WrappedID3D11Device; + +namespace ShaderDebug +{ + +struct GlobalState +{ + public: + GlobalState() + { + for(int i=0; i < 8; i++) + uavs[i].firstElement = uavs[i].numElements = uavs[i].hiddenCounter = 0; + + for(int i=0; i < 128; i++) + srvs[i].firstElement = srvs[i].numElements = 0; + } + + struct ViewFmt + { + ViewFmt() { byteWidth = 0; numComps = 0; reversed = false; fmt = eCompType_None; } + + int byteWidth; + int numComps; + bool reversed; + FormatComponentType fmt; + + int Stride() + { + if(byteWidth == 10 || byteWidth == 11) return 32; // 10 10 10 2 or 11 11 10 + + return byteWidth*numComps; + } + }; + + struct + { + vector data; + uint32_t firstElement; + uint32_t numElements; + + ViewFmt format; + + uint32_t hiddenCounter; + } uavs[8]; + + struct + { + vector data; + uint32_t firstElement; + uint32_t numElements; + + ViewFmt format; + } srvs[128]; +}; + +class State : public ShaderDebugState +{ + public: + State() + { + quadIndex = 0; + nextInstruction = 0; + done = false; + dxbc = NULL; + } + State(int quadIdx, const ShaderDebugTrace *t, DXBC::DXBCFile *f, WrappedID3D11Device *d) + { + quadIndex = quadIdx; + nextInstruction = 0; + done = false; + trace = t; + dxbc = f; + device = d; + } + + void SetTrace(const ShaderDebugTrace *t) + { + trace = t; + } + + struct + { + uint32_t GroupID[3]; + uint32_t ThreadID[3]; + } semantics; + + void Init(); + bool Finished(); + + State GetNext(GlobalState &global, State quad[4]) const; + + private: + // index in the pixel quad + int quadIndex; + + bool done; + + // sets the destination operand by looking up in the register + // file and applying any masking or swizzling + void SetDst(const DXBC::ASMOperand &dstoper, const DXBC::ASMOperation &op, const ShaderVariable &val); + + // retrieves the value of the operand, by looking up + // in the register file and performing any swizzling and + // negation/abs functions + ShaderVariable GetSrc(const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const; + + ShaderVariable DDX(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const; + ShaderVariable DDY(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const; + + VarType OperationType(const DXBC::OpcodeType &op) const; + + DXBC::DXBCFile *dxbc; + const ShaderDebugTrace *trace; + WrappedID3D11Device *device; +}; + +}; // namespace ShaderDebug \ No newline at end of file diff --git a/renderdoc/driver/d3d11/shaders/dxbc_disassemble.cpp b/renderdoc/driver/d3d11/shaders/dxbc_disassemble.cpp new file mode 100644 index 0000000000..2d757a9fb0 --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_disassemble.cpp @@ -0,0 +1,2499 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" // only dependencies are RDCASSERT, so this code is easy to detach from RenderDoc +#include "dxbc_inspect.h" +#include "dxbc_disassemble.h" +#include "common/string_utils.h" + +#include + +#include + +namespace DXBC +{ + +// little utility function to both document and easily extract an arbitrary mask +// out of the tokens. Makes the assumption that we always take some masked off +// bits and shift them all the way to the LSB. Then casts it to whatever type +template +class MaskedElement +{ + public: + static T Get(uint32_t token) + { + unsigned long shift = 0; + unsigned long mask = M; + byte hasBit = _BitScanForward(&shift, mask); + RDCASSERT(hasBit != 0); + + T ret = (T)( (token & mask) >> shift); + + return ret; + } +}; + +// bools need a comparison to be safe, rather than casting. +template +class MaskedElement +{ + public: + static bool Get(uint32_t token) + { + unsigned long shift = 0; + unsigned long mask = M; + byte hasBit = _BitScanForward(&shift, mask); + RDCASSERT(hasBit != 0); + + bool ret = ( (token & mask) >> shift) != 0; + + return ret; + } +}; + +//////////////////////////////////////////////////////////////////////////// +// The token stream appears as a series of uint32 tokens. +// First is a version token, then a length token, then a series of Opcodes +// (which are N tokens). +// An Opcode consists of an Opcode token, then optionally some ExtendedOpcode +// tokens. Then depending on the type of Opcode some number of further tokens - +// typically Operands, although occasionally other DWORDS. +// An Operand is a single Operand token then possibly some more DWORDS again, +// indices and such like. + +namespace VersionToken +{ + static MaskedElement MajorVersion; + static MaskedElement MinorVersion; + + static MaskedElement ProgramType; +}; + +namespace LengthToken +{ + static MaskedElement Length; +}; + +namespace Opcode +{ + // generic + static MaskedElement Type; + static MaskedElement Length; + static MaskedElement Extended; + static MaskedElement CustomClass; + + // opcode specific + static MaskedElement PreciseValues; + + // several + static MaskedElement Saturate; + static MaskedElement TestNonZero; + + // OPCODE_RESINFO + static MaskedElement ResinfoReturn; + + // OPCODE_SYNC + static MaskedElement SyncFlags; + // relative to above uint32! ie. post shift. + static MaskedElement Sync_Threads; + static MaskedElement Sync_TGSM; + static MaskedElement Sync_UAV_Group; + static MaskedElement Sync_UAV_Global; + + // OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED + // OPCODE_DCL_RESOURCE_STRUCTURED + static MaskedElement HasOrderPreservingCounter; +}; // Opcode + +// Declarations are Opcode tokens, but with their own particular definitions +// of most of the bits (aside from the generice type/length/extended bits above) +namespace Declaration +{ + // OPCODE_DCL_GLOBAL_FLAGS + static MaskedElement RefactoringAllowed; + static MaskedElement DoubleFloatOps; + static MaskedElement ForceEarlyDepthStencil; + static MaskedElement EnableRawStructuredBufs; + + // OPCODE_DCL_CONSTANT_BUFFER + static MaskedElement AccessPattern; + + // OPCODE_DCL_SAMPLER + static MaskedElement SamplerMode; + + // OPCODE_DCL_RESOURCE + static MaskedElement ResourceDim; + static MaskedElement SampleCount; + // below come in a second token (ResourceReturnTypeToken). See extract functions below + static MaskedElement ReturnTypeX; + static MaskedElement ReturnTypeY; + static MaskedElement ReturnTypeZ; + static MaskedElement ReturnTypeW; + + // OPCODE_DCL_INPUT_PS + static MaskedElement InterpolationMode; + + // OPCODE_DCL_INPUT_CONTROL_POINT_COUNT + // OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT + static MaskedElement ControlPointCount; + + // OPCODE_DCL_TESS_DOMAIN + static MaskedElement TessDomain; + + // OPCODE_DCL_TESS_PARTITIONING + static MaskedElement TessPartitioning; + + // OPCODE_DCL_GS_INPUT_PRIMITIVE + static MaskedElement InputPrimitive; + + // OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY + static MaskedElement OutputPrimitiveTopology; + + // OPCODE_DCL_TESS_OUTPUT_PRIMITIVE + static MaskedElement OutputPrimitive; + + // OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED + static MaskedElement GloballyCoherant; + + // OPCODE_DCL_INTERFACE + static MaskedElement TableLength; + static MaskedElement NumInterfaces; +}; // Declaration + +namespace ExtendedOpcode +{ + static MaskedElement Extended; + static MaskedElement Type; + + // OPCODE_EX_SAMPLE_CONTROLS + static MaskedElement TexelOffsetU; + static MaskedElement TexelOffsetV; + static MaskedElement TexelOffsetW; + + // OPCODE_EX_RESOURCE_DIM + static MaskedElement ResourceDim; + + // OPCODE_EX_RESOURCE_RETURN_TYPE + static MaskedElement ReturnTypeX; + static MaskedElement ReturnTypeY; + static MaskedElement ReturnTypeZ; + static MaskedElement ReturnTypeW; +}; // ExtendedOpcode + +namespace Operand +{ + static MaskedElement NumComponents; + static MaskedElement SelectionMode; + + // SELECTION_MASK + static MaskedElement ComponentMaskX; + static MaskedElement ComponentMaskY; + static MaskedElement ComponentMaskZ; + static MaskedElement ComponentMaskW; + + // SELECTION_SWIZZLE + static MaskedElement ComponentSwizzleX; + static MaskedElement ComponentSwizzleY; + static MaskedElement ComponentSwizzleZ; + static MaskedElement ComponentSwizzleW; + + // SELECTION_SELECT_1 + static MaskedElement ComponentSel1; + + static MaskedElement Type; + static MaskedElement IndexDimension; + + static MaskedElement Index0; + static MaskedElement Index1; + static MaskedElement Index2; + + static MaskedElement Extended; +}; // Operand + +namespace ExtendedOperand +{ + static MaskedElement Type; + static MaskedElement Extended; + + // EXTENDED_OPERAND_MODIFIER + static MaskedElement Modifier; +}; + +string toString(vector values); +char *toString(OpcodeType op); +char *toString(ResourceDimension dim); +char *toString(ResourceRetType type); +char *toString(ResinfoRetType type); +char *toString(InterpolationMode type); +char *SystemValueToString(uint32_t type); + +bool ASMOperand::operator ==(const ASMOperand &o) const +{ + if(type != o.type) return false; + if(numComponents != o.numComponents) return false; + if(memcmp(comps, o.comps, 4)) return false; + if(modifier != o.modifier) return false; + + if(indices.size() != o.indices.size()) return false; + if(values.size() != o.values.size()) return false; + + for(size_t i=0; i < indices.size(); i++) + if(indices[i] != o.indices[i]) return false; + + for(size_t i=0; i < values.size(); i++) + if(values[i] != o.values[i]) return false; + + return true; +} + +void DXBCFile::DisassembleHexDump() +{ + uint32_t *begin = &m_HexDump.front(); + uint32_t *cur = begin; + uint32_t *end = &m_HexDump.back(); + + if(m_HexDump.empty()) + return; + + m_Type = VersionToken::ProgramType.Get(cur[0]); + m_Version.Major = VersionToken::MajorVersion.Get(cur[0]); + m_Version.Minor = VersionToken::MinorVersion.Get(cur[0]); + + // check supported types + if( !(m_Version.Major == 0x5 && m_Version.Minor == 0x0) && + !(m_Version.Major == 0x4 && m_Version.Minor == 0x1) && + !(m_Version.Major == 0x4 && m_Version.Minor == 0x0) + ) + { + RDCERR("Unsupported shader bytecode version: %u.%u", m_Version.Major, m_Version.Minor); + return; + } + + RDCASSERT(LengthToken::Length.Get(cur[1]) == m_HexDump.size()); // length token + + cur += 2; + + while(cur < end) + { + ASMOperation op; + ASMDecl decl; + + uintptr_t offset = cur-begin; + + decl.instruction = m_Instructions.size(); + decl.offset = offset*sizeof(uint32_t); + op.offset = offset*sizeof(uint32_t); + + if(!ExtractOperation(cur, op)) + { + if(!ExtractDecl(cur, decl)) + { + RDCERR("Unexpected non-operation and non-decl in token stream at 0x%x", cur-begin); + } + else + { + m_Declarations.push_back(decl); + } + } + else + { + m_Instructions.push_back(op); + } + } + + ASMOperation implicitRet; + implicitRet.length = 1; + implicitRet.offset = (end-begin)*sizeof(uint32_t); + implicitRet.operation = OPCODE_RET; + implicitRet.str = "ret"; + + m_Instructions.push_back(implicitRet); +} + +void DXBCFile::MakeDisassembly() +{ + if(m_HexDump.empty()) + { + m_Disassembly = "No bytecode in this blob"; + return; + } + + m_Disassembly = ""; + + switch(m_Type) + { + case D3D11_SHVER_PIXEL_SHADER: m_Disassembly = "ps_"; break; + case D3D11_SHVER_VERTEX_SHADER: m_Disassembly = "vs_"; break; + case D3D11_SHVER_GEOMETRY_SHADER: m_Disassembly = "gs_"; break; + case D3D11_SHVER_HULL_SHADER: m_Disassembly = "hs_"; break; + case D3D11_SHVER_DOMAIN_SHADER: m_Disassembly = "ds_"; break; + case D3D11_SHVER_COMPUTE_SHADER: m_Disassembly = "cs_"; break; + default: RDCERR("Unknown shader type: %u", m_Type); break; + } + + char buf[] = {0, 0}; + buf[0] = (char)('0'+m_Version.Major); + m_Disassembly += buf; + m_Disassembly += "_"; + buf[0] = (char)('0'+m_Version.Minor); + m_Disassembly += buf; + m_Disassembly += "\n"; + + int indent = 0; + + size_t d=0; + + vector< vector > fileLines; + + if(m_DebugInfo) + { + vector fileNames; + + fileLines.resize(m_DebugInfo->Files.size()); + fileNames.resize(m_DebugInfo->Files.size()); + + for(size_t i=0; i < m_DebugInfo->Files.size(); i++) + fileNames[i] = m_DebugInfo->Files[i].first; + + // we essentially do a copy-paste out of m_DebugInfo->Files into fileLines, + // by doing a mini-preprocess to handle #line directives. This means that + // any lines that our source file declares to be in another filename via a #line + // get put in the right place for what the debug information hopefully matches. + // We also concatenate duplicate lines and display them all, to handle edge + // cases where #lines declare duplicates. + + for(size_t i=0; i < m_DebugInfo->Files.size(); i++) + { + vector srclines; + vector *dstFile = &fileLines[i]; // start off writing to the corresponding output file. + + size_t dstLine = 0; + + split(m_DebugInfo->Files[i].second, srclines, '\n'); + srclines.push_back(""); + + // handle #line directives by inserting empty lines or erasing as necessary + + for(size_t srcLine=0; srcLine < srclines.size(); srcLine++) + { + char *c = &srclines[srcLine][0]; + while(*c == '\t' || *c == ' ' || *c == '\r') c++; + + if(strncmp(c, "#line", 5)) + { + // resize up to account for the current line, if necessary + dstFile->resize(RDCMAX(dstLine+1, dstFile->size())); + + // if non-empty, append this line (to allow multiple lines on the same line + // number to be concatenated) + if((*dstFile)[dstLine].empty()) + (*dstFile)[dstLine] = srclines[srcLine]; + else + (*dstFile)[dstLine] += "\n" + srclines[srcLine]; + + // advance line counter + dstLine++; + + continue; + } + + // we have a #line directive + c += 5; + + while(*c == '\t' || *c == ' ') c++; + + // invalid #line, no line number. Skip/ignore + if(*c < '0' || *c > '9') + continue; + + size_t newLineNum = 0; + while(*c >= '0' && *c <= '9') + { + newLineNum *= 10; + newLineNum += int((*c) - '0'); + c++; + } + + // convert to 0-indexed line number + if(newLineNum > 0) + newLineNum--; + + while(*c == '\t' || *c == ' ') c++; + + // no filename + if(*c == 0) + { + // set the next line number, and continue processing + dstLine = newLineNum; + continue; + } + else if(*c == '"') + { + c++; + + char *filename = c; + + // parse out filename + while(*c != '"' && *c != 0) + { + if(*c == '\\') + { + // skip escaped characters + c += 2; + } + else + { + c++; + } + } + + // parsed filename successfully + if(*c == '"') + { + *c = 0; + + // find the new destination file + bool found = false; + size_t dstFileIdx = 0; + + for(size_t f=0; f < fileNames.size(); f++) + { + if(fileNames[f] == filename) + { + found = true; + dstFileIdx = f; + break; + } + } + + if(found) + { + dstFile = &fileLines[dstFileIdx]; + } + else + { + RDCWARN("Couldn't find filename '%hs' in #line directive in debug info", filename); + + // make a dummy file to write into that won't be used. + fileNames.push_back(filename); + fileLines.push_back(vector()); + + dstFile = &fileLines.back(); + } + + // set the next line number, and continue processing + dstLine = newLineNum; + + continue; + } + else + { + // invalid #line, ignore + continue; + } + } + else + { + // invalid #line, ignore + continue; + } + } + } + + for(size_t i=0; i < m_DebugInfo->Files.size(); i++) + { + if(m_DebugInfo->Files[i].second.empty()) + { + merge(fileLines[i], m_DebugInfo->Files[i].second, '\n'); + } + } + } + + int32_t prevFile = -1; + int32_t prevLine = -1; + + size_t debugInst = 0; + + for(size_t i=0; i < m_Instructions.size(); i++) + { + for(; d < m_Declarations.size(); d++) + { + if(m_Declarations[d].instruction > i) + { + if(i == 0) + m_Disassembly += "\n"; + break; + } + + m_Disassembly += " "; + m_Disassembly += m_Declarations[d].str; + m_Disassembly += "\n"; + } + + if(m_Instructions[i].operation == OPCODE_ENDIF || + m_Instructions[i].operation == OPCODE_ENDLOOP) + { + indent--; + } + + if(m_DebugInfo) + { + int32_t fileID = prevFile; + int32_t lineNum = prevLine; + + m_DebugInfo->GetFileLine(debugInst, m_Instructions[i].offset, fileID, lineNum); + + if(fileID >= 0 && lineNum >= 0 && (fileID != prevFile || lineNum != prevLine)) + { + string line = ""; + if(fileID >= (int32_t)fileLines.size()) + { + line = "Unknown file"; + } + else + { + int32_t lineIdx = RDCMIN(lineNum, (int32_t)fileLines[fileID].size()-1); + line = fileLines[fileID][lineIdx]; + } + + size_t startLine = line.find_first_not_of(" \t"); + + if(startLine != string::npos) + line = line.substr(startLine); + + m_Disassembly += "\n"; + + if( + (fileID != prevFile && fileID < (int32_t)fileLines.size()) || + line == "" + ) + { + m_Disassembly += " "; // "0000: " + for(int in=0; in < indent; in++) + m_Disassembly += " "; + m_Disassembly += StringFormat::Fmt("%hs:%d\n", m_DebugInfo->Files[fileID].first.c_str(), lineNum+1); + } + + if(line != "") + { + m_Disassembly += " "; // "0000: " + for(int in=0; in < indent; in++) + m_Disassembly += " "; + m_Disassembly += line + "\n"; + } + } + + prevFile = fileID; + prevLine = lineNum; + } + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "% 4u", i); + m_Disassembly += buf; + m_Disassembly += ": "; + for(int in=0; in < indent - (m_Instructions[i].operation == OPCODE_ELSE ? 1 : 0); in++) + m_Disassembly += " "; + m_Disassembly += m_Instructions[i].str + "\n"; + + if(m_Instructions[i].operation == OPCODE_IF || + m_Instructions[i].operation == OPCODE_LOOP) + { + indent++; + } + + if(m_Instructions[i].operation != OPCODE_HS_CONTROL_POINT_PHASE && + m_Instructions[i].operation != OPCODE_HS_FORK_PHASE && + m_Instructions[i].operation != OPCODE_HS_JOIN_PHASE) + debugInst++; + } +} + +bool DXBCFile::IsDeclaration(OpcodeType op) +{ + // isDecl means not a real instruction, just a declaration type token + bool isDecl = false; + isDecl = isDecl || (op >= OPCODE_DCL_RESOURCE && op <= OPCODE_DCL_GLOBAL_FLAGS); + isDecl = isDecl || (op >= OPCODE_DCL_STREAM && op <= OPCODE_DCL_RESOURCE_STRUCTURED); + isDecl = isDecl || (op == OPCODE_DCL_GS_INSTANCE_COUNT); + isDecl = isDecl || (op == OPCODE_HS_DECLS); + isDecl = isDecl || (op == OPCODE_CUSTOMDATA); + + return isDecl; +} + +bool DXBCFile::ExtractOperand(uint32_t *&tokenStream, ASMOperand &retOper) +{ + uint32_t OperandToken0 = tokenStream[0]; + + retOper.type = Operand::Type.Get(OperandToken0); + retOper.numComponents = Operand::NumComponents.Get(OperandToken0); + + SelectionMode selMode = Operand::SelectionMode.Get(OperandToken0); + + if(selMode == SELECTION_MASK) + { + int i=0; + + if(Operand::ComponentMaskX.Get(OperandToken0)) retOper.comps[i++] = 0; + if(Operand::ComponentMaskY.Get(OperandToken0)) retOper.comps[i++] = 1; + if(Operand::ComponentMaskZ.Get(OperandToken0)) retOper.comps[i++] = 2; + if(Operand::ComponentMaskW.Get(OperandToken0)) retOper.comps[i++] = 3; + } + else if(selMode == SELECTION_SWIZZLE) + { + retOper.comps[0] = Operand::ComponentSwizzleX.Get(OperandToken0); + retOper.comps[1] = Operand::ComponentSwizzleY.Get(OperandToken0); + retOper.comps[2] = Operand::ComponentSwizzleZ.Get(OperandToken0); + retOper.comps[3] = Operand::ComponentSwizzleW.Get(OperandToken0); + } + else if(selMode == SELECTION_SELECT_1) + { + retOper.comps[0] = Operand::ComponentSel1.Get(OperandToken0); + } + + uint32_t indexDim = Operand::IndexDimension.Get(OperandToken0); + + OperandIndexType rep[] = { + Operand::Index0.Get(OperandToken0), + Operand::Index1.Get(OperandToken0), + Operand::Index2.Get(OperandToken0), + }; + + bool extended = Operand::Extended.Get(OperandToken0); + + tokenStream++; + + while(extended) + { + uint32_t OperandTokenN = tokenStream[0]; + + ExtendedOperandType type = ExtendedOperand::Type.Get(OperandTokenN); + + if(type == EXTENDED_OPERAND_MODIFIER) + { + retOper.modifier = ExtendedOperand::Modifier.Get(OperandTokenN); + } + else + { + RDCERR("Unexpected extended operand modifier"); + } + + extended = ExtendedOperand::Extended.Get(OperandTokenN) == 1; + + tokenStream++; + } + + retOper.indices.resize(indexDim); + + if(retOper.type == TYPE_IMMEDIATE32 || + retOper.type == TYPE_IMMEDIATE64) + { + RDCASSERT(retOper.indices.empty()); + + if(retOper.numComponents == NUMCOMPS_1) + retOper.values.resize(1); + else if(retOper.numComponents == NUMCOMPS_4) + retOper.values.resize(4); + else + RDCERR("N-wide vectors not supported."); + + for(size_t i=0; i < retOper.values.size(); i++) + { + uint64_t val = tokenStream[0]; + tokenStream++; + + if(retOper.type == INDEX_IMMEDIATE64) + { + val <<= 32; + val |= tokenStream[0]; + tokenStream++; + } + + retOper.values[i] = val; + } + } + + for(int idx=0; idx < (int)indexDim; idx++) + { + if(rep[idx] == INDEX_IMMEDIATE32_PLUS_RELATIVE || rep[idx] == INDEX_IMMEDIATE32) + { + retOper.indices[idx].absolute = true; + retOper.indices[idx].index = tokenStream[0]; + + tokenStream++; + } + else if(rep[idx] == INDEX_IMMEDIATE64_PLUS_RELATIVE || rep[idx] == INDEX_IMMEDIATE64) + { + retOper.indices[idx].absolute = true; + + // hi/lo words + retOper.indices[idx].index = tokenStream[0]; + retOper.indices[idx].index <<= 32; + tokenStream++; + + retOper.indices[idx].index |= tokenStream[0]; + tokenStream++; + + RDCASSERT(sizeof(retOper.indices[idx].index) == 8); + } + + if(rep[idx] == INDEX_IMMEDIATE64_PLUS_RELATIVE || + rep[idx] == INDEX_IMMEDIATE32_PLUS_RELATIVE || + rep[idx] == INDEX_RELATIVE) + { + // relative addressing + retOper.indices[idx].relative = true; + + bool ret = ExtractOperand(tokenStream, retOper.indices[idx].operand); + RDCASSERT(ret); + } + + if(retOper.indices[idx].relative) + retOper.indices[idx].str = "[" + retOper.indices[idx].operand.toString() + " + "; + + if(retOper.indices[idx].absolute) + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%llu", retOper.indices[idx].index); + retOper.indices[idx].str += buf; + } + else if(retOper.indices[idx].relative) + retOper.indices[idx].str += "0"; + + if(retOper.indices[idx].relative) + retOper.indices[idx].str += "]"; + + RDCASSERT(retOper.indices[idx].relative || retOper.indices[idx].absolute); + } + + return true; +} + +string ASMOperand::toString(bool swizzle) const +{ + string str = ""; + + char swiz[6] = {0, 0, 0, 0, 0, 0}; + + char compchars[] = {'x', 'y', 'z', 'w'}; + + for(int i=0; i < 4; i++) + { + if(comps[i] < 4) + { + swiz[0] = '.'; + swiz[i+1] = compchars[comps[i]]; + } + } + + if(type == TYPE_NULL) + { + str = "null"; + } + else if(type == TYPE_INTERFACE) + { + str = "fp"; + + RDCASSERT(indices.size() == 2); + + str += indices[0].str; + str += "[" + indices[1].str + "]"; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "[%u]", funcNum); + str += buf; + } + else if(type == TYPE_TEMP || + type == TYPE_RESOURCE || + type == TYPE_SAMPLER || + type == TYPE_OUTPUT || + type == TYPE_STREAM || + type == TYPE_THREAD_GROUP_SHARED_MEMORY || + type == TYPE_UNORDERED_ACCESS_VIEW || + type == TYPE_FUNCTION_BODY) + { + if(type == TYPE_TEMP) str = "r"; + if(type == TYPE_RESOURCE) str = "t"; + if(type == TYPE_SAMPLER) str = "s"; + if(type == TYPE_OUTPUT) str = "o"; + if(type == TYPE_STREAM) str = "m"; + if(type == TYPE_THREAD_GROUP_SHARED_MEMORY) str = "g"; + if(type == TYPE_UNORDERED_ACCESS_VIEW) str = "u"; + if(type == TYPE_FUNCTION_BODY) str = "fb"; + + RDCASSERT(indices.size() == 1); + + str += indices[0].str; + } + else if(type == TYPE_CONSTANT_BUFFER || + type == TYPE_IMMEDIATE_CONSTANT_BUFFER || + type == TYPE_INDEXABLE_TEMP || + type == TYPE_INPUT || + type == TYPE_INPUT_CONTROL_POINT || + type == TYPE_INPUT_PATCH_CONSTANT || + type == TYPE_THIS_POINTER || + type == TYPE_OUTPUT_CONTROL_POINT) + { + if(type == TYPE_IMMEDIATE_CONSTANT_BUFFER) str = "icb"; + if(type == TYPE_CONSTANT_BUFFER) str = "cb"; + if(type == TYPE_INDEXABLE_TEMP) str = "x"; + if(type == TYPE_INPUT) str = "v"; + if(type == TYPE_INPUT_CONTROL_POINT) str = "vicp"; + if(type == TYPE_INPUT_PATCH_CONSTANT) str = "vpc"; + if(type == TYPE_OUTPUT_CONTROL_POINT) str = "vocp"; + if(type == TYPE_THIS_POINTER) str = "this"; + + if(indices.size() == 1 && type != TYPE_IMMEDIATE_CONSTANT_BUFFER) + { + str += indices[0].str; + } + else + { + for(size_t i=0; i < indices.size(); i++) + { + if(i == 0 && (type == TYPE_CONSTANT_BUFFER || type == TYPE_INDEXABLE_TEMP)) + { + str += indices[i].str; + continue; + } + + if(indices[i].relative) + str += indices[i].str; + else + str += "[" + indices[i].str + "]"; + } + } + } + else if(type == TYPE_IMMEDIATE32) + { + RDCASSERT(indices.size() == 0 && values.size() > 0); + + str = "l(" + DXBC::toString(values) + ")"; + } + else if(type == TYPE_IMMEDIATE64) + { + RDCASSERT(values.size() > 0); + + if(values.empty()) + { + str += "l(err)"; + } + else + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "l(%llx)", values[0]); + str += buf; + } + } + else if(type == TYPE_RASTERIZER) str = "rasterizer"; + else if(type == TYPE_OUTPUT_CONTROL_POINT_ID) str = "vOutputControlPointID"; + else if(type == TYPE_INPUT_DOMAIN_POINT) str = "vDomain"; + else if(type == TYPE_INPUT_PRIMITIVEID) str = "vPrim"; + else if(type == TYPE_INPUT_COVERAGE_MASK) str = "vCoverageMask"; + else if(type == TYPE_INPUT_GS_INSTANCE_ID) str = "vGSInstanceID"; + else if(type == TYPE_INPUT_THREAD_ID) str = "vThreadID"; + else if(type == TYPE_INPUT_THREAD_GROUP_ID) str = "vThreadGroupID"; + else if(type == TYPE_INPUT_THREAD_ID_IN_GROUP) str = "vThreadIDInGroup"; + else if(type == TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED) str = "vThreadIDInGroupFlattened"; + else if(type == TYPE_INPUT_FORK_INSTANCE_ID) str = "vForkInstanceID"; + else if(type == TYPE_INPUT_JOIN_INSTANCE_ID) str = "vJoinInstanceID"; + else if(type == TYPE_OUTPUT_DEPTH) str = "oDepth"; + else if(type == TYPE_OUTPUT_DEPTH_LESS_EQUAL) str = "oDepthLessEqual"; + else if(type == TYPE_OUTPUT_DEPTH_GREATER_EQUAL) str = "oDepthGreaterEqual"; + else if(type == TYPE_OUTPUT_COVERAGE_MASK) str = "oMask"; + else + { + RDCERR("Unsupported system value semantic %d", type); + str = "oUnsupported"; + } + + if(swizzle) + str += swiz; + + if(modifier == OPERAND_MODIFIER_NEG) + str = "-" + str; + if(modifier == OPERAND_MODIFIER_ABS) + str = "abs(" + str + ")"; + if(modifier == OPERAND_MODIFIER_ABSNEG) + str = "-abs(" + str + ")"; + + return str; +} + +bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) +{ + uint32_t *begin = tokenStream; + uint32_t OpcodeToken0 = tokenStream[0]; + + OpcodeType op = Opcode::Type.Get(OpcodeToken0); + + bool extended = Opcode::Extended.Get(OpcodeToken0) == 1; + + RDCASSERT(op < NUM_OPCODES); + + if(!IsDeclaration(op)) + return false; + + if(op == OPCODE_CUSTOMDATA) + { + CustomDataClass customClass = Opcode::CustomClass.Get(OpcodeToken0); + + tokenStream++; + // DWORD length including OpcodeToken0 and this length token + uint32_t customDataLength = tokenStream[0]; + tokenStream++; + + RDCASSERT(customDataLength >= 2); + + switch(customClass) + { + case CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER: + { + retDecl.str = "dcl_immediateConstantBuffer {"; + + uint32_t dataLength = customDataLength-2; + + RDCASSERT(dataLength%4 == 0); + + for(uint32_t i=0; i < dataLength; i++) + { + if(i%4 == 0) + retDecl.str += "\n\t\t\t{ "; + + m_Immediate.push_back(tokenStream[0]); + + vector values; values.push_back(tokenStream[0]); + + retDecl.str += toString(values); + + tokenStream++; + + if((i+1)%4 == 0) + retDecl.str += "}"; + + if(i+1 < dataLength) + retDecl.str += ", "; + } + + retDecl.str += " }"; + + break; + } + + default: + { + RDCERR("Unsupported custom data class %d!", customClass); + + uint32_t dataLength = customDataLength-2; + RDCLOG("Data length seems to be %d uint32s", dataLength); + + for(uint32_t i=0; i < dataLength; i++) + { + char *str = (char *)tokenStream; + RDCDEBUG("uint32 %d: 0x%08x %c %c %c %c", i, tokenStream[0], str[0], str[1], str[2], str[3]); + tokenStream++; + } + + break; + } + } + + return true; + } + + retDecl.declaration = op; + retDecl.length = Opcode::Length.Get(OpcodeToken0); + + tokenStream++; + + retDecl.str = toString(op); + + if(op == OPCODE_DCL_GLOBAL_FLAGS) + { + retDecl.refactoringAllowed = Declaration::RefactoringAllowed.Get(OpcodeToken0); + retDecl.doublePrecisionFloats = Declaration::DoubleFloatOps.Get(OpcodeToken0); + retDecl.forceEarlyDepthStencil = Declaration::ForceEarlyDepthStencil.Get(OpcodeToken0); + retDecl.enableRawAndStructuredBuffers = Declaration::EnableRawStructuredBufs.Get(OpcodeToken0); + + retDecl.str += " "; + + bool added = false; + + if(retDecl.refactoringAllowed) + { + if(added) + retDecl.str += ", "; + retDecl.str += "refactoringAllowed"; + added = true; + } + if(retDecl.doublePrecisionFloats) + { + if(added) + retDecl.str += ", "; + retDecl.str += "doublePrecisionFloats"; + added = true; + } + if(retDecl.forceEarlyDepthStencil) + { + if(added) + retDecl.str += ", "; + retDecl.str += "forceEarlyDepthStencil"; + added = true; + } + if(retDecl.enableRawAndStructuredBuffers) + { + if(added) + retDecl.str += ", "; + retDecl.str += "enableRawAndStructuredBuffers"; + added = true; + } + } + else if(op == OPCODE_DCL_CONSTANT_BUFFER) + { + CBufferAccessPattern accessPattern = Declaration::AccessPattern.Get(OpcodeToken0); + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += " "; + retDecl.str += retDecl.operand.toString(false); + retDecl.str += ", "; + + if(accessPattern == ACCESS_IMMEDIATE_INDEXED) + retDecl.str += "immediateIndexed"; + else if(accessPattern == ACCESS_DYNAMIC_INDEXED) + retDecl.str += "dynamicIndexed"; + else + RDCERR("Unexpected cbuffer access pattern"); + } + else if(op == OPCODE_DCL_INPUT) + { + retDecl.str += " "; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += retDecl.operand.toString(); + } + else if(op == OPCODE_DCL_TEMPS) + { + retDecl.str += " "; + + retDecl.numTemps = tokenStream[0]; + + tokenStream++; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.numTemps); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_INDEXABLE_TEMP) + { + retDecl.str += " "; + + retDecl.tempReg = tokenStream[0]; + tokenStream++; + + retDecl.numTemps = tokenStream[0]; + tokenStream++; + + retDecl.tempComponentCount = tokenStream[0]; + tokenStream++; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "x%u[%u], %u", retDecl.tempReg, retDecl.numTemps, retDecl.tempComponentCount); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_OUTPUT) + { + retDecl.str += " "; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += retDecl.operand.toString(); + } + else if(op == OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT) + { + retDecl.str += " "; + + retDecl.maxOut = tokenStream[0]; + + tokenStream++; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.maxOut); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_INPUT_SIV || op == OPCODE_DCL_INPUT_SGV || + op == OPCODE_DCL_INPUT_PS_SIV || op == OPCODE_DCL_INPUT_PS_SGV || + op == OPCODE_DCL_OUTPUT_SIV) + { + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.systemValue = tokenStream[0]; + tokenStream++; + + retDecl.str += " "; + retDecl.str += retDecl.operand.toString(); + + retDecl.str += ", "; + retDecl.str += SystemValueToString(retDecl.systemValue); + } + else if(op == OPCODE_DCL_STREAM) + { + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += " "; + retDecl.str += retDecl.operand.toString(false); + } + else if(op == OPCODE_DCL_SAMPLER) + { + retDecl.samplerMode = Declaration::SamplerMode.Get(OpcodeToken0); + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += " "; + retDecl.str += retDecl.operand.toString(false); + + retDecl.str += ", "; + if(retDecl.samplerMode == SAMPLER_MODE_DEFAULT) + retDecl.str += "mode_default"; + if(retDecl.samplerMode == SAMPLER_MODE_COMPARISON) + retDecl.str += "mode_comparison"; + if(retDecl.samplerMode == SAMPLER_MODE_MONO) + retDecl.str += "mode_mono"; + } + else if(op == OPCODE_DCL_RESOURCE) + { + retDecl.dim = Declaration::ResourceDim.Get(OpcodeToken0); + + retDecl.sampleCount = 0; + if(retDecl.dim == RESOURCE_DIMENSION_TEXTURE2DMS || + retDecl.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) + { + retDecl.sampleCount = Declaration::SampleCount.Get(OpcodeToken0); + } + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + uint32_t ResourceReturnTypeToken = tokenStream[0]; + tokenStream++; + + retDecl.resType[0] = Declaration::ReturnTypeX.Get(ResourceReturnTypeToken); + retDecl.resType[1] = Declaration::ReturnTypeY.Get(ResourceReturnTypeToken); + retDecl.resType[2] = Declaration::ReturnTypeZ.Get(ResourceReturnTypeToken); + retDecl.resType[3] = Declaration::ReturnTypeW.Get(ResourceReturnTypeToken); + + retDecl.str += "_"; + retDecl.str += toString(retDecl.dim); + retDecl.str += " "; + + retDecl.str += "("; + retDecl.str += toString(retDecl.resType[0]); + retDecl.str += ","; + retDecl.str += toString(retDecl.resType[1]); + retDecl.str += ","; + retDecl.str += toString(retDecl.resType[2]); + retDecl.str += ","; + retDecl.str += toString(retDecl.resType[3]); + retDecl.str += ")"; + + retDecl.str += " " + retDecl.operand.toString(false); + } + else if(op == OPCODE_DCL_INPUT_PS) + { + retDecl.interpolation = Declaration::InterpolationMode.Get(OpcodeToken0); + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += " "; + retDecl.str += toString(retDecl.interpolation); + + retDecl.str += " "; + retDecl.str += retDecl.operand.toString(); + } + else if(op == OPCODE_DCL_INDEX_RANGE) + { + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.str += " "; + retDecl.str += retDecl.operand.toString(); + + retDecl.indexRange = tokenStream[0]; + tokenStream++; + + retDecl.str += " "; + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.indexRange); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_THREAD_GROUP) + { + retDecl.str += " "; + + retDecl.groupSize[0] = tokenStream[0]; + tokenStream++; + + retDecl.groupSize[1] = tokenStream[0]; + tokenStream++; + + retDecl.groupSize[2] = tokenStream[0]; + tokenStream++; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.groupSize[0]); + retDecl.str += buf; + retDecl.str += ", "; + + StringFormat::snprintf(buf, 63, "%u", retDecl.groupSize[1]); + retDecl.str += buf; + retDecl.str += ", "; + + StringFormat::snprintf(buf, 63, "%u", retDecl.groupSize[2]); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW) + { + retDecl.str += " "; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.count = tokenStream[0]; + tokenStream++; + + retDecl.str += retDecl.operand.toString(false); + retDecl.str += ", "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.count); + retDecl.str += buf; + retDecl.str += ", "; + } + else if(op == OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED) + { + retDecl.str += " "; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.stride = tokenStream[0]; + tokenStream++; + + retDecl.count = tokenStream[0]; + tokenStream++; + + retDecl.str += retDecl.operand.toString(false); + retDecl.str += ", "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.stride); + retDecl.str += buf; + retDecl.str += ", "; + + StringFormat::snprintf(buf, 63, "%u", retDecl.count); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_INPUT_CONTROL_POINT_COUNT || + op == OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT) + { + retDecl.str += " "; + + retDecl.controlPointCount = Declaration::ControlPointCount.Get(OpcodeToken0); + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.controlPointCount); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_TESS_DOMAIN) + { + retDecl.domain = Declaration::TessDomain.Get(OpcodeToken0); + + retDecl.str += " "; + if(retDecl.domain == DOMAIN_ISOLINE) + retDecl.str += "domain_isoline"; + else if(retDecl.domain == DOMAIN_TRI) + retDecl.str += "domain_tri"; + else if(retDecl.domain == DOMAIN_QUAD) + retDecl.str += "domain_quad"; + else + RDCERR("Unexpected Tessellation domain"); + } + else if(op == OPCODE_DCL_TESS_PARTITIONING) + { + retDecl.partition = Declaration::TessPartitioning.Get(OpcodeToken0); + + retDecl.str += " "; + if(retDecl.partition == PARTITIONING_INTEGER) + retDecl.str += "partitioning_integer"; + else if(retDecl.partition == PARTITIONING_POW2) + retDecl.str += "partitioning_pow2"; + else if(retDecl.partition == PARTITIONING_FRACTIONAL_ODD) + retDecl.str += "partitioning_fractional_odd"; + else if(retDecl.partition == PARTITIONING_FRACTIONAL_EVEN) + retDecl.str += "partitioning_fractional_even"; + else + RDCERR("Unexpected Partitioning"); + } + else if(op == OPCODE_DCL_GS_INPUT_PRIMITIVE) + { + retDecl.inPrim = Declaration::InputPrimitive.Get(OpcodeToken0); + + retDecl.str += " "; + if(retDecl.inPrim == PRIMITIVE_POINT) + retDecl.str += "point"; + else if(retDecl.inPrim == PRIMITIVE_LINE) + retDecl.str += "line"; + else if(retDecl.inPrim == PRIMITIVE_TRIANGLE) + retDecl.str += "triangle"; + else if(retDecl.inPrim == PRIMITIVE_LINE_ADJ) + retDecl.str += "line_adj"; + else if(retDecl.inPrim == PRIMITIVE_TRIANGLE_ADJ) + retDecl.str += "triangle_adj"; + else if(retDecl.inPrim >= PRIMITIVE_1_CONTROL_POINT_PATCH && + retDecl.inPrim <= PRIMITIVE_32_CONTROL_POINT_PATCH) + { + retDecl.str += "control_point_patch_"; + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", 1+int(retDecl.inPrim-PRIMITIVE_1_CONTROL_POINT_PATCH)); + retDecl.str += buf; + } + else + RDCERR("Unexpected primitive type"); + } + else if(op == OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY) + { + retDecl.outTopology = Declaration::OutputPrimitiveTopology.Get(OpcodeToken0); + + retDecl.str += " "; + if(retDecl.outTopology == TOPOLOGY_POINTLIST) + retDecl.str += "point"; + else if(retDecl.outTopology == TOPOLOGY_LINELIST) + retDecl.str += "linelist"; + else if(retDecl.outTopology == TOPOLOGY_LINESTRIP) + retDecl.str += "linestrip"; + else if(retDecl.outTopology == TOPOLOGY_TRIANGLELIST) + retDecl.str += "trianglelist"; + else if(retDecl.outTopology == TOPOLOGY_TRIANGLESTRIP) + retDecl.str += "trianglestrip"; + else if(retDecl.outTopology == TOPOLOGY_LINELIST_ADJ) + retDecl.str += "linelist_adj"; + else if(retDecl.outTopology == TOPOLOGY_LINESTRIP_ADJ) + retDecl.str += "linestrip_adj"; + else if(retDecl.outTopology == TOPOLOGY_TRIANGLELIST_ADJ) + retDecl.str += "trianglelist_adj"; + else if(retDecl.outTopology == TOPOLOGY_TRIANGLESTRIP_ADJ) + retDecl.str += "trianglestrip_adj"; + else + RDCERR("Unexpected primitive topology"); + } + else if(op == OPCODE_DCL_TESS_OUTPUT_PRIMITIVE) + { + retDecl.outPrim = Declaration::OutputPrimitive.Get(OpcodeToken0); + + retDecl.str += " "; + if(retDecl.outPrim == OUTPUT_PRIMITIVE_POINT) + retDecl.str += "output_point"; + else if(retDecl.outPrim == OUTPUT_PRIMITIVE_LINE) + retDecl.str += "output_line"; + else if(retDecl.outPrim == OUTPUT_PRIMITIVE_TRIANGLE_CW) + retDecl.str += "output_triangle_cw"; + else if(retDecl.outPrim == OUTPUT_PRIMITIVE_TRIANGLE_CCW) + retDecl.str += "output_triangle_ccw"; + else + RDCERR("Unexpected output primitive"); + } + else if(op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW || + op == OPCODE_DCL_RESOURCE_RAW) + { + retDecl.str += " "; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + } + else if(op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED || + op == OPCODE_DCL_RESOURCE_STRUCTURED) + { + retDecl.hasCounter = (op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED) && + Opcode::HasOrderPreservingCounter.Get(OpcodeToken0); + + retDecl.str += " "; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + retDecl.stride = tokenStream[0]; + tokenStream++; + + retDecl.str += retDecl.operand.toString(false); + retDecl.str += ", "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.stride); + retDecl.str += buf; + + if(retDecl.hasCounter) + retDecl.str += ", hasOrderPreservingCounter"; + } + else if(op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED) + { + retDecl.dim = Declaration::ResourceDim.Get(OpcodeToken0); + + retDecl.globallyCoherant = Declaration::GloballyCoherant.Get(OpcodeToken0); + + retDecl.str += "_"; + retDecl.str += toString(retDecl.dim); + + if(retDecl.globallyCoherant) + retDecl.str += "_glc"; + + bool ret = ExtractOperand(tokenStream, retDecl.operand); + RDCASSERT(ret); + + uint32_t ResourceReturnTypeToken = tokenStream[0]; + tokenStream++; + + retDecl.resType[0] = Declaration::ReturnTypeX.Get(ResourceReturnTypeToken); + retDecl.resType[1] = Declaration::ReturnTypeY.Get(ResourceReturnTypeToken); + retDecl.resType[2] = Declaration::ReturnTypeZ.Get(ResourceReturnTypeToken); + retDecl.resType[3] = Declaration::ReturnTypeW.Get(ResourceReturnTypeToken); + + retDecl.str += " "; + + retDecl.str += "("; + retDecl.str += toString(retDecl.resType[0]); + retDecl.str += ","; + retDecl.str += toString(retDecl.resType[1]); + retDecl.str += ","; + retDecl.str += toString(retDecl.resType[2]); + retDecl.str += ","; + retDecl.str += toString(retDecl.resType[3]); + retDecl.str += ")"; + + retDecl.str += " "; + + retDecl.str += retDecl.operand.toString(false); + } + else if(op == OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT) + { + retDecl.forkInstanceCount = tokenStream[0]; + tokenStream++; + + retDecl.str += " "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", retDecl.forkInstanceCount); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_HS_MAX_TESSFACTOR) + { + float *f = (float *)tokenStream; + retDecl.maxTessFactor = *f; + tokenStream++; + + retDecl.str += " "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "l(%f)", retDecl.maxTessFactor); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_FUNCTION_BODY) + { + retDecl.functionBody = tokenStream[0]; + tokenStream++; + + retDecl.str += " "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "fb%u", retDecl.functionBody); + retDecl.str += buf; + } + else if(op == OPCODE_DCL_FUNCTION_TABLE) + { + retDecl.functionTable = tokenStream[0]; + tokenStream++; + + retDecl.str += " "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "ft%u", retDecl.functionTable); + retDecl.str += buf; + + uint32_t TableLength = tokenStream[0]; + tokenStream++; + + retDecl.str += " = {"; + + for(uint32_t i=0; i < TableLength; i++) + { + StringFormat::snprintf(buf, 63, "fb%u", tokenStream[0]); + retDecl.str += buf; + + if(i+1 < TableLength) + retDecl.str += ", "; + + retDecl.immediateData.push_back(tokenStream[0]); + tokenStream++; + } + + retDecl.str += "}"; + } + else if(op == OPCODE_DCL_INTERFACE) + { + retDecl.interfaceID = tokenStream[0]; + tokenStream++; + + retDecl.numTypes = tokenStream[0]; + tokenStream++; + + uint32_t CountToken = tokenStream[0]; + tokenStream++; + + retDecl.numInterfaces = Declaration::NumInterfaces.Get(CountToken); + uint32_t TableLength = Declaration::TableLength.Get(CountToken); + + retDecl.str += " "; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "fp%u[%u][%u]", retDecl.interfaceID, retDecl.numInterfaces, retDecl.numTypes); + retDecl.str += buf; + + retDecl.str += " = {"; + + for(uint32_t i=0; i < TableLength; i++) + { + StringFormat::snprintf(buf, 63, "ft%u", tokenStream[0]); + retDecl.str += buf; + + if(i+1 < TableLength) + retDecl.str += ", "; + + retDecl.immediateData.push_back(tokenStream[0]); + tokenStream++; + } + + retDecl.str += "}"; + } + else if(op == OPCODE_HS_DECLS); + else + { + RDCERR("Unexpected opcode decl %d", op); + } + + // make sure we consumed all uint32s + RDCASSERT((uint32_t)(tokenStream - begin) == retDecl.length); + + return true; +} + +bool DXBCFile::ExtractOperation(uint32_t *&tokenStream, ASMOperation &retOp) +{ + uint32_t *begin = tokenStream; + uint32_t OpcodeToken0 = tokenStream[0]; + + OpcodeType op = Opcode::Type.Get(OpcodeToken0); + + RDCASSERT(op < NUM_OPCODES); + + if(IsDeclaration(op)) + return false; + + // possibly only set these when applicable + retOp.operation = op; + retOp.length = Opcode::Length.Get(OpcodeToken0); + retOp.nonzero = Opcode::TestNonZero.Get(OpcodeToken0) == 1; + retOp.saturate = Opcode::Saturate.Get(OpcodeToken0) == 1; + retOp.preciseValues = Opcode::PreciseValues.Get(OpcodeToken0); + retOp.resinfoRetType = Opcode::ResinfoReturn.Get(OpcodeToken0); + retOp.syncFlags = Opcode::SyncFlags.Get(OpcodeToken0); + + bool extended = Opcode::Extended.Get(OpcodeToken0) == 1; + + tokenStream++; + + retOp.str = toString(op); + + while(extended) + { + uint32_t OpcodeTokenN = tokenStream[0]; + + ExtendedOpcodeType type = ExtendedOpcode::Type.Get(OpcodeTokenN); + + if(type == EXTENDED_OPCODE_SAMPLE_CONTROLS) + { + retOp.texelOffset[0] = ExtendedOpcode::TexelOffsetU.Get(OpcodeTokenN); + retOp.texelOffset[1] = ExtendedOpcode::TexelOffsetV.Get(OpcodeTokenN); + retOp.texelOffset[2] = ExtendedOpcode::TexelOffsetW.Get(OpcodeTokenN); + + // apply 4-bit two's complement as per spec + if(retOp.texelOffset[0] > 7) + retOp.texelOffset[0] -= 16; + if(retOp.texelOffset[1] > 7) + retOp.texelOffset[1] -= 16; + if(retOp.texelOffset[2] > 7) + retOp.texelOffset[2] -= 16; + + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "(%d,%d,%d)", retOp.texelOffset[0], retOp.texelOffset[1], retOp.texelOffset[2]); + retOp.str += buf; + } + else if(type == EXTENDED_OPCODE_RESOURCE_DIM) + { + retOp.resDim = ExtendedOpcode::ResourceDim.Get(OpcodeTokenN); + + if(op == OPCODE_LD_STRUCTURED) + { + retOp.str += "_indexable("; + retOp.str += toString(retOp.resDim); + retOp.str += ""; + retOp.str += ")"; + } + else + { + retOp.str += "("; + retOp.str += toString(retOp.resDim); + retOp.str += ")"; + } + } + else if(type == EXTENDED_OPCODE_RESOURCE_RETURN_TYPE) + { + retOp.resType[0] = ExtendedOpcode::ReturnTypeX.Get(OpcodeTokenN); + retOp.resType[1] = ExtendedOpcode::ReturnTypeY.Get(OpcodeTokenN); + retOp.resType[2] = ExtendedOpcode::ReturnTypeZ.Get(OpcodeTokenN); + retOp.resType[3] = ExtendedOpcode::ReturnTypeW.Get(OpcodeTokenN); + + retOp.str += "("; + retOp.str += toString(retOp.resType[0]); + retOp.str += ","; + retOp.str += toString(retOp.resType[1]); + retOp.str += ","; + retOp.str += toString(retOp.resType[2]); + retOp.str += ","; + retOp.str += toString(retOp.resType[3]); + retOp.str += ")"; + } + + extended = ExtendedOpcode::Extended.Get(OpcodeTokenN) == 1; + + tokenStream++; + } + + if(op == OPCODE_RESINFO) + { + retOp.str += "_"; + retOp.str += toString(retOp.resinfoRetType); + } + + if(op == OPCODE_SYNC) + { + if(Opcode::Sync_UAV_Global.Get(retOp.syncFlags)) + { + retOp.str += "_uglobal"; + } + if(Opcode::Sync_UAV_Group.Get(retOp.syncFlags)) + { + retOp.str += "_ugroup"; + } + if(Opcode::Sync_TGSM.Get(retOp.syncFlags)) + { + retOp.str += "_g"; + } + if(Opcode::Sync_Threads.Get(retOp.syncFlags)) + { + retOp.str += "_t"; + } + } + + uint32_t func = 0; + if(op == OPCODE_INTERFACE_CALL) + { + func = tokenStream[0]; + tokenStream++; + } + + retOp.operands.resize(NumOperands(op)); + + for(size_t i=0; i < retOp.operands.size(); i++) + { + bool ret = ExtractOperand(tokenStream, retOp.operands[i]); + RDCASSERT(ret); + } + + if(op == OPCODE_SAMPLE_POS) + { + // no idea what this is. I've always seen it be '8'. + uint32_t unknown = tokenStream[0]; + tokenStream++; + } + + if(op == OPCODE_INTERFACE_CALL) + { + retOp.operands[0].funcNum = func; + } + + if(op == OPCODE_IF || + op == OPCODE_BREAKC || + op == OPCODE_CALLC || + op == OPCODE_RETC || + op == OPCODE_SWAPC || + op == OPCODE_DMOVC || + op == OPCODE_DISCARD || + op == OPCODE_DMOVC) + retOp.str += retOp.nonzero ? "_nz" : "_z"; + + if(op != OPCODE_SYNC) + { + retOp.str += retOp.saturate ? "_sat" : ""; + } + + for(size_t i=0; i < retOp.operands.size(); i++) + { + if(i == 0) + retOp.str += " "; + else + retOp.str += ", "; + retOp.str += retOp.operands[i].toString(); + } + + // fixup + size_t strideLoc = retOp.str.find(""); + if(strideLoc != string::npos && op == OPCODE_LD_STRUCTURED) + { + string a = retOp.str.substr(0, strideLoc); + string b = retOp.str.substr(strideLoc+8); + + uint32_t stride = 0; + + RDCASSERT(retOp.operands[3].type == TYPE_UNORDERED_ACCESS_VIEW || + retOp.operands[3].type == TYPE_RESOURCE); + + RDCASSERT(retOp.operands[3].indices.size() > 0); + + for(size_t i=0; i < m_Declarations.size(); i++) + { + if( + (m_Declarations[i].declaration == OPCODE_DCL_RESOURCE_STRUCTURED && retOp.operands[3].type == TYPE_RESOURCE) || + (m_Declarations[i].declaration == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED && retOp.operands[3].type == TYPE_UNORDERED_ACCESS_VIEW) + ) + { + if(m_Declarations[i].operand.indices[0] == retOp.operands[3].indices[0]) + { + stride = m_Declarations[i].stride; + break; + } + } + } + // get index out of retOp.operands[3].indices + // look up in declarations + + if(stride > 0) + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "%u", stride); + retOp.str = a + ", stride=" + buf + b; + } + else + { + retOp.str = a + b; + } + } + + if((uint32_t)(tokenStream - begin) > retOp.length) + { + RDCERR("Consumed too many tokens for %d!", retOp.operation); + + // try to recover by rewinding the stream, this instruction will be garbage but at least the next ones will be correct + uint32_t overread = (uint32_t)(tokenStream - begin) - retOp.length; + tokenStream -= overread; + } + else if((uint32_t)(tokenStream - begin) < retOp.length) + { + RDCERR("Consumed too few tokens for %d!", retOp.operation); + uint32_t missing = retOp.length - (uint32_t)(tokenStream - begin); + for(uint32_t i=0; i < missing; i++) + { + RDCLOG("missing token %d: 0x%08x", tokenStream[0]); + tokenStream++; + } + } + + // make sure we consumed all uint32s + RDCASSERT((uint32_t)(tokenStream - begin) == retOp.length); + + return true; +} + +//////////////////////////////////////////////////////////// +// boring tedious long switch statement style functions + +// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb219840(v=vs.85).aspx +// for details of these opcodes +size_t DXBCFile::NumOperands(OpcodeType op) +{ + switch(op) + { + case OPCODE_BREAK: + case OPCODE_CONTINUE: + case OPCODE_CUT: + case OPCODE_DEFAULT: + case OPCODE_ELSE: + case OPCODE_EMIT: + case OPCODE_EMITTHENCUT: + case OPCODE_ENDIF: + case OPCODE_ENDLOOP: + case OPCODE_ENDSWITCH: + case OPCODE_LOOP: + case OPCODE_NOP: + case OPCODE_RET: + case OPCODE_SYNC: + + case OPCODE_HS_CONTROL_POINT_PHASE: + case OPCODE_HS_FORK_PHASE: + case OPCODE_HS_JOIN_PHASE: + case OPCODE_HS_DECLS: + return 0; + case OPCODE_BREAKC: + case OPCODE_CONTINUEC: + case OPCODE_CALL: + case OPCODE_CASE: + case OPCODE_CUT_STREAM: + case OPCODE_DISCARD: + case OPCODE_EMIT_STREAM: + case OPCODE_EMITTHENCUT_STREAM: + case OPCODE_IF: + case OPCODE_INTERFACE_CALL: + case OPCODE_LABEL: + case OPCODE_RETC: + case OPCODE_SWITCH: + return 1; + case OPCODE_BFREV: + case OPCODE_BUFINFO: + case OPCODE_CALLC: + case OPCODE_COUNTBITS: + case OPCODE_DERIV_RTX: + case OPCODE_DERIV_RTY: + case OPCODE_DERIV_RTX_COARSE: + case OPCODE_DERIV_RTX_FINE: + case OPCODE_DERIV_RTY_COARSE: + case OPCODE_DERIV_RTY_FINE: + case OPCODE_DMOV: + case OPCODE_DTOF: + case OPCODE_EXP: + case OPCODE_F32TOF16: + case OPCODE_F16TOF32: + case OPCODE_FIRSTBIT_HI: + case OPCODE_FIRSTBIT_LO: + case OPCODE_FIRSTBIT_SHI: + case OPCODE_FRC: + case OPCODE_FTOD: + case OPCODE_FTOI: + case OPCODE_FTOU: + case OPCODE_IMM_ATOMIC_ALLOC: + case OPCODE_IMM_ATOMIC_CONSUME: + case OPCODE_INEG: + case OPCODE_ITOF: + case OPCODE_LOG: + case OPCODE_MOV: + case OPCODE_NOT: + case OPCODE_RCP: + case OPCODE_ROUND_NE: + case OPCODE_ROUND_NI: + case OPCODE_ROUND_PI: + case OPCODE_ROUND_Z: + case OPCODE_RSQ: + case OPCODE_SAMPLE_INFO: + case OPCODE_SQRT: + case OPCODE_UTOF: + case OPCODE_EVAL_CENTROID: + return 2; + case OPCODE_AND: + case OPCODE_ADD: + case OPCODE_ATOMIC_AND: + case OPCODE_ATOMIC_OR: + case OPCODE_ATOMIC_XOR: + case OPCODE_ATOMIC_IADD: + case OPCODE_ATOMIC_IMAX: + case OPCODE_ATOMIC_IMIN: + case OPCODE_ATOMIC_UMAX: + case OPCODE_ATOMIC_UMIN: + case OPCODE_DADD: + case OPCODE_DIV: + case OPCODE_DP2: + case OPCODE_DP3: + case OPCODE_DP4: + case OPCODE_DEQ: + case OPCODE_DGE: + case OPCODE_DLT: + case OPCODE_DMAX: + case OPCODE_DMIN: + case OPCODE_DMUL: + case OPCODE_DNE: + case OPCODE_EQ: + case OPCODE_GE: + case OPCODE_IADD: + case OPCODE_IEQ: + case OPCODE_IGE: + case OPCODE_ILT: + case OPCODE_IMAX: + case OPCODE_IMIN: + case OPCODE_INE: + case OPCODE_ISHL: + case OPCODE_ISHR: + case OPCODE_LD: + case OPCODE_LD_RAW: + case OPCODE_LD_UAV_TYPED: + case OPCODE_LT: + case OPCODE_MAX: + case OPCODE_MIN: + case OPCODE_MUL: + case OPCODE_NE: + case OPCODE_OR: + case OPCODE_RESINFO: + case OPCODE_SAMPLE_POS: + case OPCODE_SINCOS: + case OPCODE_STORE_RAW: + case OPCODE_STORE_UAV_TYPED: + case OPCODE_UGE: + case OPCODE_ULT: + case OPCODE_UMAX: + case OPCODE_UMIN: + case OPCODE_USHR: + case OPCODE_XOR: + case OPCODE_EVAL_SNAPPED: + case OPCODE_EVAL_SAMPLE_INDEX: + return 3; + case OPCODE_ATOMIC_CMP_STORE: + case OPCODE_DMOVC: + case OPCODE_GATHER4: + case OPCODE_IBFE: + case OPCODE_IMAD: + case OPCODE_IMM_ATOMIC_IADD: + case OPCODE_IMM_ATOMIC_AND: + case OPCODE_IMM_ATOMIC_OR: + case OPCODE_IMM_ATOMIC_XOR: + case OPCODE_IMM_ATOMIC_EXCH: + case OPCODE_IMM_ATOMIC_IMAX: + case OPCODE_IMM_ATOMIC_IMIN: + case OPCODE_IMM_ATOMIC_UMAX: + case OPCODE_IMM_ATOMIC_UMIN: + case OPCODE_IMUL: + case OPCODE_LD_MS: + case OPCODE_LD_STRUCTURED: + case OPCODE_LOD: + case OPCODE_MAD: + case OPCODE_MOVC: + case OPCODE_SAMPLE: + case OPCODE_STORE_STRUCTURED: + case OPCODE_UADDC: + case OPCODE_UBFE: + case OPCODE_UDIV: + case OPCODE_UMAD: + case OPCODE_UMUL: + case OPCODE_USUBB: + return 4; + case OPCODE_BFI: + case OPCODE_GATHER4_C: + case OPCODE_GATHER4_PO: + case OPCODE_IMM_ATOMIC_CMP_EXCH: + case OPCODE_SAMPLE_C: + case OPCODE_SAMPLE_C_LZ: + case OPCODE_SAMPLE_L: + case OPCODE_SAMPLE_B: + case OPCODE_SWAPC: + return 5; + case OPCODE_GATHER4_PO_C: + case OPCODE_SAMPLE_D: + return 6; + + // custom data doesn't have particular operands + case OPCODE_CUSTOMDATA: + default: + break; + } + + RDCERR("Unknown opcode: %u", op); + return 0xffffffff; +} + +string toString(vector values) +{ + string str = ""; + + // fxc actually guesses these types it seems. + // try setting an int value to 1085276160, it will be displayed in disasm as 5.500000. + // I don't know the exact heuristic but I'm guessing something along the lines of + // checking if it's float-looking. + // My heuristic is: + // * is exponent 0 or 0x7f8? It's either inf, NaN, other special value. OR it's 0, which is + // identical in int or float anyway - so interpret it as an int. Small ints display as numbers, + // larger ints in raw hex + // * otherwise, assume it's a float. + // * If any component is a float, they are all floats. + // + // this means this will break if an inf/nan is set as a param, and is kind of a kludge, but the + // behaviour seems to match d3dcompiler.dll's behaviour in most cases. There are a couple of + // exceptions that I don't follow: 0 is always displayed as a float in vectors, however + // sometimes it can be an int. + + bool floatOutput = false; + + for(size_t i=0; i < values.size(); i++) + { + float *vf = (float*)&values[i]; + int32_t *vi = (int32_t*)&values[i]; + + uint32_t exponent = vi[0] & 0x7f800000; + + if(exponent != 0 && exponent != 0x7f800000) + floatOutput = true; + } + + for(size_t i=0; i < values.size(); i++) + { + float *vf = (float*)&values[i]; + int32_t *vi = (int32_t*)&values[i]; + + char buf[64] = {0}; + + if(!floatOutput) + { + // print small ints straight up, otherwise as hex + if(vi[0] <= 10000 && vi[0] >= -10000) + StringFormat::snprintf(buf, 63, "%d", vi[0]); + else + StringFormat::snprintf(buf, 63, "0x%08x", vi[0]); + } + else + StringFormat::snprintf(buf, 63, "%f", vf[0]); + + str += buf; + + if(i+1 < values.size()) + str += ", "; + } + + return str; +} + +char *toString(OpcodeType op) +{ + switch(op) + { + case OPCODE_ADD: return "add"; + case OPCODE_AND: return "and"; + case OPCODE_BREAK: return "break"; + case OPCODE_BREAKC: return "breakc"; + case OPCODE_CALL: return "call"; + case OPCODE_CALLC: return "callc"; + case OPCODE_CASE: return "case"; + case OPCODE_CONTINUE: return "continue"; + case OPCODE_CONTINUEC: return "continuec"; + case OPCODE_CUT: return "cut"; + case OPCODE_DEFAULT: return "default"; + case OPCODE_DERIV_RTX: return "deriv_rtx"; + case OPCODE_DERIV_RTY: return "deriv_rty"; + case OPCODE_DISCARD: return "discard"; + case OPCODE_DIV: return "div"; + case OPCODE_DP2: return "dp2"; + case OPCODE_DP3: return "dp3"; + case OPCODE_DP4: return "dp4"; + case OPCODE_ELSE: return "else"; + case OPCODE_EMIT: return "emit"; + case OPCODE_EMITTHENCUT: return "emitthencut"; + case OPCODE_ENDIF: return "endif"; + case OPCODE_ENDLOOP: return "endloop"; + case OPCODE_ENDSWITCH: return "endswitch"; + case OPCODE_EQ: return "eq"; + case OPCODE_EXP: return "exp"; + case OPCODE_FRC: return "frc"; + case OPCODE_FTOI: return "ftoi"; + case OPCODE_FTOU: return "ftou"; + case OPCODE_GE: return "ge"; + case OPCODE_IADD: return "iadd"; + case OPCODE_IF: return "if"; + case OPCODE_IEQ: return "ieq"; + case OPCODE_IGE: return "ige"; + case OPCODE_ILT: return "ilt"; + case OPCODE_IMAD: return "imad"; + case OPCODE_IMAX: return "imax"; + case OPCODE_IMIN: return "imin"; + case OPCODE_IMUL: return "imul"; + case OPCODE_INE: return "ine"; + case OPCODE_INEG: return "ineg"; + case OPCODE_ISHL: return "ishl"; + case OPCODE_ISHR: return "ishr"; + case OPCODE_ITOF: return "itof"; + case OPCODE_LABEL: return "label"; + case OPCODE_LD: return "ld_indexable"; + case OPCODE_LD_MS: return "ld_ms"; + case OPCODE_LOG: return "log"; + case OPCODE_LOOP: return "loop"; + case OPCODE_LT: return "lt"; + case OPCODE_MAD: return "mad"; + case OPCODE_MIN: return "min"; + case OPCODE_MAX: return "max"; + case OPCODE_CUSTOMDATA: return "customdata"; + case OPCODE_MOV: return "mov"; + case OPCODE_MOVC: return "movc"; + case OPCODE_MUL: return "mul"; + case OPCODE_NE: return "ne"; + case OPCODE_NOP: return "nop"; + case OPCODE_NOT: return "not"; + case OPCODE_OR: return "or"; + case OPCODE_RESINFO: return "resinfo_indexable"; + case OPCODE_RET: return "ret"; + case OPCODE_RETC: return "retc"; + case OPCODE_ROUND_NE: return "round_ne"; + case OPCODE_ROUND_NI: return "round_ni"; + case OPCODE_ROUND_PI: return "round_pi"; + case OPCODE_ROUND_Z: return "round_z"; + case OPCODE_RSQ: return "rsq"; + case OPCODE_SAMPLE: return "sample_indexable"; + case OPCODE_SAMPLE_C: return "sample_c"; + case OPCODE_SAMPLE_C_LZ: return "sample_c_lz"; + case OPCODE_SAMPLE_L: return "sample_l"; + case OPCODE_SAMPLE_D: return "sample_d"; + case OPCODE_SAMPLE_B: return "sample_b"; + case OPCODE_SQRT: return "sqrt"; + case OPCODE_SWITCH: return "switch"; + case OPCODE_SINCOS: return "sincos"; + case OPCODE_UDIV: return "udiv"; + case OPCODE_ULT: return "ult"; + case OPCODE_UGE: return "uge"; + case OPCODE_UMUL: return "umul"; + case OPCODE_UMAD: return "umad"; + case OPCODE_UMAX: return "umax"; + case OPCODE_UMIN: return "umin"; + case OPCODE_USHR: return "ushr"; + case OPCODE_UTOF: return "utof"; + case OPCODE_XOR: return "xor"; + case OPCODE_DCL_RESOURCE: return "dcl_resource"; + case OPCODE_DCL_CONSTANT_BUFFER: return "dcl_constantbuffer"; + case OPCODE_DCL_SAMPLER: return "dcl_sampler"; + case OPCODE_DCL_INDEX_RANGE: return "dcl_indexRange"; + case OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY: return "dcl_outputtopology"; + case OPCODE_DCL_GS_INPUT_PRIMITIVE: return "dcl_inputprimitive"; + case OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT: return "dcl_maxout"; + case OPCODE_DCL_INPUT: return "dcl_input"; + case OPCODE_DCL_INPUT_SGV: return "dcl_input_sgv"; + case OPCODE_DCL_INPUT_SIV: return "dcl_input_siv"; + case OPCODE_DCL_INPUT_PS: return "dcl_input_ps"; + case OPCODE_DCL_INPUT_PS_SGV: return "dcl_input_ps_sgv"; + case OPCODE_DCL_INPUT_PS_SIV: return "dcl_input_ps_siv"; + case OPCODE_DCL_OUTPUT: return "dcl_output"; + case OPCODE_DCL_OUTPUT_SGV: return "dcl_output_sgv"; + case OPCODE_DCL_OUTPUT_SIV: return "dcl_output_siv"; + case OPCODE_DCL_TEMPS: return "dcl_temps"; + case OPCODE_DCL_INDEXABLE_TEMP: return "dcl_indexableTemp"; + case OPCODE_DCL_GLOBAL_FLAGS: return "dcl_globalFlags"; + case OPCODE_LOD: return "lod"; + case OPCODE_GATHER4: return "gather4"; + case OPCODE_SAMPLE_POS: return "samplepos"; + case OPCODE_SAMPLE_INFO: return "sample_info"; + case OPCODE_HS_DECLS: return "hs_decls"; + case OPCODE_HS_CONTROL_POINT_PHASE: return "hs_control_point_phase"; + case OPCODE_HS_FORK_PHASE: return "hs_fork_phase"; + case OPCODE_HS_JOIN_PHASE: return "hs_join_phase"; + case OPCODE_EMIT_STREAM: return "emit_stream"; + case OPCODE_CUT_STREAM: return "cut_stream"; + case OPCODE_EMITTHENCUT_STREAM: return "emitThenCut_stream"; + case OPCODE_INTERFACE_CALL: return "fcall"; + case OPCODE_BUFINFO: return "bufinfo"; + case OPCODE_DERIV_RTX_COARSE: return "deriv_rtx_coarse"; + case OPCODE_DERIV_RTX_FINE: return "deriv_rtx_fine"; + case OPCODE_DERIV_RTY_COARSE: return "deriv_rty_coarse"; + case OPCODE_DERIV_RTY_FINE: return "deriv_rty_fine"; + case OPCODE_GATHER4_C: return "gather4_c"; + case OPCODE_GATHER4_PO: return "gather4_po"; + case OPCODE_GATHER4_PO_C: return "gather4_po_c"; + case OPCODE_RCP: return "rcp"; + case OPCODE_F32TOF16: return "f32tof16"; + case OPCODE_F16TOF32: return "f16tof32"; + case OPCODE_UADDC: return "uaddc"; + case OPCODE_USUBB: return "usubb"; + case OPCODE_COUNTBITS: return "countbits"; + case OPCODE_FIRSTBIT_HI: return "firstbit_hi"; + case OPCODE_FIRSTBIT_LO: return "firstbit_lo"; + case OPCODE_FIRSTBIT_SHI: return "firstbit_shi"; + case OPCODE_UBFE: return "ubfe"; + case OPCODE_IBFE: return "ibfe"; + case OPCODE_BFI: return "bfi"; + case OPCODE_BFREV: return "bfrev"; + case OPCODE_SWAPC: return "swapc"; + case OPCODE_DCL_STREAM: return "dcl_stream"; + case OPCODE_DCL_FUNCTION_BODY: return "dcl_function_body"; + case OPCODE_DCL_FUNCTION_TABLE: return "dcl_function_table"; + case OPCODE_DCL_INTERFACE: return "dcl_interface"; + case OPCODE_DCL_INPUT_CONTROL_POINT_COUNT: return "dcl_input_control_point_count"; + case OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT: return "dcl_output_control_point_count"; + case OPCODE_DCL_TESS_DOMAIN: return "dcl_tessellator_domain"; + case OPCODE_DCL_TESS_PARTITIONING: return "dcl_tessellator_partitioning"; + case OPCODE_DCL_TESS_OUTPUT_PRIMITIVE: return "dcl_tessellator_output_primitive"; + case OPCODE_DCL_HS_MAX_TESSFACTOR: return "dcl_hs_max_tessfactor"; + case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT: return "dcl_hs_fork_phase_instance_count"; + case OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT: return "dcl_hs_join_phase_instance_count"; + case OPCODE_DCL_THREAD_GROUP: return "dcl_thread_group"; + case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED: return "dcl_uav_typed"; + case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW: return "dcl_uav_raw"; + case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED: return "dcl_uav_structured"; + case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW: return "dcl_tgsm_raw"; + case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED: return "dcl_tgsm_structured"; + case OPCODE_DCL_RESOURCE_RAW: return "dcl_resource_raw"; + case OPCODE_DCL_RESOURCE_STRUCTURED: return "dcl_resource_structured"; + case OPCODE_LD_UAV_TYPED: return "ld_uav_typed"; + case OPCODE_STORE_UAV_TYPED: return "store_uav_typed"; + case OPCODE_LD_RAW: return "ld_raw"; + case OPCODE_STORE_RAW: return "store_raw"; + case OPCODE_LD_STRUCTURED: return "ld_structured"; + case OPCODE_STORE_STRUCTURED: return "store_structured"; + case OPCODE_ATOMIC_AND: return "atomic_and"; + case OPCODE_ATOMIC_OR: return "atomic_or"; + case OPCODE_ATOMIC_XOR: return "atomic_xor"; + case OPCODE_ATOMIC_CMP_STORE: return "atomic_cmp_store"; + case OPCODE_ATOMIC_IADD: return "atomic_iadd"; + case OPCODE_ATOMIC_IMAX: return "atomic_imax"; + case OPCODE_ATOMIC_IMIN: return "atomic_imin"; + case OPCODE_ATOMIC_UMAX: return "atomic_umax"; + case OPCODE_ATOMIC_UMIN: return "atomic_umin"; + case OPCODE_IMM_ATOMIC_ALLOC: return "imm_atomic_alloc"; + case OPCODE_IMM_ATOMIC_CONSUME: return "imm_atomic_consume"; + case OPCODE_IMM_ATOMIC_IADD: return "imm_atomic_iadd"; + case OPCODE_IMM_ATOMIC_AND: return "imm_atomic_and"; + case OPCODE_IMM_ATOMIC_OR: return "imm_atomic_or"; + case OPCODE_IMM_ATOMIC_XOR: return "imm_atomic_xor"; + case OPCODE_IMM_ATOMIC_EXCH: return "imm_atomic_exch"; + case OPCODE_IMM_ATOMIC_CMP_EXCH: return "imm_atomic_cmp_exch"; + case OPCODE_IMM_ATOMIC_IMAX: return "imm_atomic_imax"; + case OPCODE_IMM_ATOMIC_IMIN: return "imm_atomic_imin"; + case OPCODE_IMM_ATOMIC_UMAX: return "imm_atomic_umax"; + case OPCODE_IMM_ATOMIC_UMIN: return "imm_atomic_umin"; + case OPCODE_SYNC: return "sync"; + case OPCODE_DADD: return "dadd"; + case OPCODE_DMAX: return "dmax"; + case OPCODE_DMIN: return "dmin"; + case OPCODE_DMUL: return "dmul"; + case OPCODE_DEQ: return "deq"; + case OPCODE_DGE: return "dge"; + case OPCODE_DLT: return "dlt"; + case OPCODE_DNE: return "dne"; + case OPCODE_DMOV: return "dmov"; + case OPCODE_DMOVC: return "dmovc"; + case OPCODE_DTOF: return "dtof"; + case OPCODE_FTOD: return "ftod"; + case OPCODE_EVAL_SNAPPED: return "eval_snapped"; + case OPCODE_EVAL_SAMPLE_INDEX: return "eval_sample_index"; + case OPCODE_EVAL_CENTROID: return "eval_centroid"; + case OPCODE_DCL_GS_INSTANCE_COUNT: return "dcl_gs_instance_count"; + default: + break; + } + + RDCERR("Unknown opcode: %u", op); + return ""; +} + +char *toString(ResourceDimension dim) +{ + switch(dim) + { + case RESOURCE_DIMENSION_UNKNOWN: return "unknown"; + case RESOURCE_DIMENSION_BUFFER: return "buffer"; + case RESOURCE_DIMENSION_TEXTURE1D: return "texture1d"; + case RESOURCE_DIMENSION_TEXTURE2D: return "texture2d"; + case RESOURCE_DIMENSION_TEXTURE2DMS: return "texture2dms"; + case RESOURCE_DIMENSION_TEXTURE3D: return "texture3d"; + case RESOURCE_DIMENSION_TEXTURECUBE: return "texturecube"; + case RESOURCE_DIMENSION_TEXTURE1DARRAY: return "texture1darray"; + case RESOURCE_DIMENSION_TEXTURE2DARRAY: return "texture2darray"; + case RESOURCE_DIMENSION_TEXTURE2DMSARRAY: return "texture2dmsarray"; + case RESOURCE_DIMENSION_TEXTURECUBEARRAY: return "texturecubearray"; + case RESOURCE_DIMENSION_RAW_BUFFER: return "rawbuffer"; + case RESOURCE_DIMENSION_STRUCTURED_BUFFER: return "structured_buffer"; + default: + break; + } + + RDCERR("Unknown dim: %u", dim); + return ""; +} + +char *toString(ResourceRetType type) +{ + switch(type) + { + case RETURN_TYPE_UNORM: return "unorm"; + case RETURN_TYPE_SNORM: return "snorm"; + case RETURN_TYPE_SINT: return "sint"; + case RETURN_TYPE_UINT: return "uint"; + case RETURN_TYPE_FLOAT: return "float"; + case RETURN_TYPE_MIXED: return "mixed"; + case RETURN_TYPE_DOUBLE: return "double"; + case RETURN_TYPE_CONTINUED: return "continued"; + case RETURN_TYPE_UNUSED: return "unused"; + default: + break; + } + + RDCERR("Unknown type: %u", type); + return ""; +} + +char *toString(ResinfoRetType type) +{ + switch(type) + { + case RETTYPE_FLOAT: return "float"; + case RETTYPE_RCPFLOAT: return "rcpfloat"; + case RETTYPE_UINT: return "uint"; + default: + break; + } + + RDCERR("Unknown type: %u", type); + return ""; +} + +char *toString(InterpolationMode interp) +{ + switch(interp) + { + case INTERPOLATION_UNDEFINED: return "undefined"; + case INTERPOLATION_CONSTANT: return "constant"; + case INTERPOLATION_LINEAR: return "linear"; + case INTERPOLATION_LINEAR_CENTROID: return "linearCentroid"; + case INTERPOLATION_LINEAR_NOPERSPECTIVE: return "linearNopersp"; + case INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID: return "linearNoperspCentroid"; + case INTERPOLATION_LINEAR_SAMPLE: return "linearSample"; + case INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE: return "linaerNoperspSample"; + default: + break; + } + + RDCERR("Unknown interp: %u", interp); + return ""; +} + +char *SystemValueToString(uint32_t name) +{ + enum DXBC_SVSemantic + { + SVNAME_UNDEFINED = 0, + SVNAME_POSITION, + SVNAME_CLIP_DISTANCE, + SVNAME_CULL_DISTANCE, + SVNAME_RENDER_TARGET_ARRAY_INDEX, + SVNAME_VIEWPORT_ARRAY_INDEX, + SVNAME_VERTEX_ID, + SVNAME_PRIMITIVE_ID, + SVNAME_INSTANCE_ID, + SVNAME_IS_FRONT_FACE, + SVNAME_SAMPLE_INDEX, + + SVNAME_FINAL_QUAD_EDGE_TESSFACTOR0, + SVNAME_FINAL_QUAD_EDGE_TESSFACTOR1, + SVNAME_FINAL_QUAD_EDGE_TESSFACTOR2, + SVNAME_FINAL_QUAD_EDGE_TESSFACTOR3, + + SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR0, + SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR1, + + SVNAME_FINAL_TRI_EDGE_TESSFACTOR0, + SVNAME_FINAL_TRI_EDGE_TESSFACTOR1, + SVNAME_FINAL_TRI_EDGE_TESSFACTOR2, + + SVNAME_FINAL_TRI_INSIDE_TESSFACTOR, + + SVNAME_FINAL_LINE_DETAIL_TESSFACTOR, + + SVNAME_FINAL_LINE_DENSITY_TESSFACTOR, + + SVNAME_TARGET = 64, + SVNAME_DEPTH, + SVNAME_COVERAGE, + SVNAME_DEPTH_GREATER_EQUAL, + SVNAME_DEPTH_LESS_EQUAL, + }; + + // cast to uint32 for the fixup around tessellation factors where we don't use direct enum values + switch((DXBC_SVSemantic)name) + { + case SVNAME_POSITION: return "position"; + case SVNAME_CLIP_DISTANCE: return "clipdistance"; + case SVNAME_CULL_DISTANCE: return "culldistance"; + case SVNAME_RENDER_TARGET_ARRAY_INDEX: return "rendertarget_array_index"; + case SVNAME_VIEWPORT_ARRAY_INDEX: return "viewport_array_index"; + case SVNAME_VERTEX_ID: return "vertexid"; + case SVNAME_PRIMITIVE_ID: return "primitiveid"; + case SVNAME_INSTANCE_ID: return "instanceid"; + case SVNAME_IS_FRONT_FACE: return "isfrontface"; + case SVNAME_SAMPLE_INDEX: return "sampleidx"; + + // tessellation factors don't correspond directly to their enum values + + // SVNAME_FINAL_QUAD_EDGE_TESSFACTOR + case SVNAME_FINAL_QUAD_EDGE_TESSFACTOR0: return "finalQuadUeq0EdgeTessFactor"; + case SVNAME_FINAL_QUAD_EDGE_TESSFACTOR1: return "finalQuadVeq0EdgeTessFactor"; + case SVNAME_FINAL_QUAD_EDGE_TESSFACTOR2: return "finalQuadUeq1EdgeTessFactor"; + case SVNAME_FINAL_QUAD_EDGE_TESSFACTOR3: return "finalQuadVeq1EdgeTessFactor"; + + // SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR + case SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR0: return "finalQuadUInsideTessFactor"; + case SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR1: return "finalQuadVInsideTessFactor"; + + // SVNAME_FINAL_TRI_EDGE_TESSFACTOR + case SVNAME_FINAL_TRI_EDGE_TESSFACTOR0: return "finalTriUeq0EdgeTessFactor"; + case SVNAME_FINAL_TRI_EDGE_TESSFACTOR1: return "finalTriVeq0EdgeTessFactor"; + case SVNAME_FINAL_TRI_EDGE_TESSFACTOR2: return "finalTriWeq0EdgeTessFactor"; + + // SVNAME_FINAL_TRI_INSIDE_TESSFACTOR + case SVNAME_FINAL_TRI_INSIDE_TESSFACTOR: return "finalTriInsideTessFactor"; + + // SVNAME_FINAL_LINE_DETAIL_TESSFACTOR + case SVNAME_FINAL_LINE_DETAIL_TESSFACTOR: return "finalLineEdgeTessFactor"; + + // SVNAME_FINAL_LINE_DENSITY_TESSFACTOR + case SVNAME_FINAL_LINE_DENSITY_TESSFACTOR: return "finalLineInsideTessFactor"; + + case SVNAME_TARGET: return "target"; + case SVNAME_DEPTH: return "depth"; + case SVNAME_COVERAGE: return "coverage"; + case SVNAME_DEPTH_GREATER_EQUAL: return "depthgreaterequal"; + case SVNAME_DEPTH_LESS_EQUAL: return "depthlessequal"; + default: + break; + } + + RDCERR("Unknown name: %u", name); + return ""; +} + +}; // namespace DXBC \ No newline at end of file diff --git a/renderdoc/driver/d3d11/shaders/dxbc_disassemble.h b/renderdoc/driver/d3d11/shaders/dxbc_disassemble.h new file mode 100644 index 0000000000..63b0f2e6b9 --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_disassemble.h @@ -0,0 +1,855 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include +using std::vector; +using std::string; + +#include + +namespace DXBC +{ + +///////////////////////////////////////////////////////////////////////// +// Enums for use below. If you're reading this you might want to skip to +// the main structures after this section. +///////////////////////////////////////////////////////////////////////// + +enum ProgramType +{ + TYPE_PIXEL = 0, + TYPE_VERTEX, + TYPE_GEOMETRY, + TYPE_HULL, + TYPE_DOMAIN, + TYPE_COMPUTE, + + NUM_TYPES, +}; + +enum OpcodeType +{ + OPCODE_ADD = 0, + OPCODE_AND, + OPCODE_BREAK, + OPCODE_BREAKC, + OPCODE_CALL, + OPCODE_CALLC, + OPCODE_CASE, + OPCODE_CONTINUE, + OPCODE_CONTINUEC, + OPCODE_CUT, + OPCODE_DEFAULT, + OPCODE_DERIV_RTX, + OPCODE_DERIV_RTY, + OPCODE_DISCARD, + OPCODE_DIV, + OPCODE_DP2, + OPCODE_DP3, + OPCODE_DP4, + OPCODE_ELSE, + OPCODE_EMIT, + OPCODE_EMITTHENCUT, + OPCODE_ENDIF, + OPCODE_ENDLOOP, + OPCODE_ENDSWITCH, + OPCODE_EQ, + OPCODE_EXP, + OPCODE_FRC, + OPCODE_FTOI, + OPCODE_FTOU, + OPCODE_GE, + OPCODE_IADD, + OPCODE_IF, + OPCODE_IEQ, + OPCODE_IGE, + OPCODE_ILT, + OPCODE_IMAD, + OPCODE_IMAX, + OPCODE_IMIN, + OPCODE_IMUL, + OPCODE_INE, + OPCODE_INEG, + OPCODE_ISHL, + OPCODE_ISHR, + OPCODE_ITOF, + OPCODE_LABEL, + OPCODE_LD, + OPCODE_LD_MS, + OPCODE_LOG, + OPCODE_LOOP, + OPCODE_LT, + OPCODE_MAD, + OPCODE_MIN, + OPCODE_MAX, + OPCODE_CUSTOMDATA, + OPCODE_MOV, + OPCODE_MOVC, + OPCODE_MUL, + OPCODE_NE, + OPCODE_NOP, + OPCODE_NOT, + OPCODE_OR, + OPCODE_RESINFO, + OPCODE_RET, + OPCODE_RETC, + OPCODE_ROUND_NE, + OPCODE_ROUND_NI, + OPCODE_ROUND_PI, + OPCODE_ROUND_Z, + OPCODE_RSQ, + OPCODE_SAMPLE, + OPCODE_SAMPLE_C, + OPCODE_SAMPLE_C_LZ, + OPCODE_SAMPLE_L, + OPCODE_SAMPLE_D, + OPCODE_SAMPLE_B, + OPCODE_SQRT, + OPCODE_SWITCH, + OPCODE_SINCOS, + OPCODE_UDIV, + OPCODE_ULT, + OPCODE_UGE, + OPCODE_UMUL, + OPCODE_UMAD, + OPCODE_UMAX, + OPCODE_UMIN, + OPCODE_USHR, + OPCODE_UTOF, + OPCODE_XOR, + OPCODE_DCL_RESOURCE, + OPCODE_DCL_CONSTANT_BUFFER, + OPCODE_DCL_SAMPLER, + OPCODE_DCL_INDEX_RANGE, + OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY, + OPCODE_DCL_GS_INPUT_PRIMITIVE, + OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT, + OPCODE_DCL_INPUT, + OPCODE_DCL_INPUT_SGV, + OPCODE_DCL_INPUT_SIV, + OPCODE_DCL_INPUT_PS, + OPCODE_DCL_INPUT_PS_SGV, + OPCODE_DCL_INPUT_PS_SIV, + OPCODE_DCL_OUTPUT, + OPCODE_DCL_OUTPUT_SGV, + OPCODE_DCL_OUTPUT_SIV, + OPCODE_DCL_TEMPS, + OPCODE_DCL_INDEXABLE_TEMP, + OPCODE_DCL_GLOBAL_FLAGS, + + OPCODE_RESERVED0, + + OPCODE_LOD, + OPCODE_GATHER4, + OPCODE_SAMPLE_POS, + OPCODE_SAMPLE_INFO, + + OPCODE_RESERVED1, + + OPCODE_HS_DECLS, + OPCODE_HS_CONTROL_POINT_PHASE, + OPCODE_HS_FORK_PHASE, + OPCODE_HS_JOIN_PHASE, + + OPCODE_EMIT_STREAM, + OPCODE_CUT_STREAM, + OPCODE_EMITTHENCUT_STREAM, + OPCODE_INTERFACE_CALL, + + OPCODE_BUFINFO, + OPCODE_DERIV_RTX_COARSE, + OPCODE_DERIV_RTX_FINE, + OPCODE_DERIV_RTY_COARSE, + OPCODE_DERIV_RTY_FINE, + OPCODE_GATHER4_C, + OPCODE_GATHER4_PO, + OPCODE_GATHER4_PO_C, + OPCODE_RCP, + OPCODE_F32TOF16, + OPCODE_F16TOF32, + OPCODE_UADDC, + OPCODE_USUBB, + OPCODE_COUNTBITS, + OPCODE_FIRSTBIT_HI, + OPCODE_FIRSTBIT_LO, + OPCODE_FIRSTBIT_SHI, + OPCODE_UBFE, + OPCODE_IBFE, + OPCODE_BFI, + OPCODE_BFREV, + OPCODE_SWAPC, + + OPCODE_DCL_STREAM, + OPCODE_DCL_FUNCTION_BODY, + OPCODE_DCL_FUNCTION_TABLE, + OPCODE_DCL_INTERFACE, + + OPCODE_DCL_INPUT_CONTROL_POINT_COUNT, + OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT, + OPCODE_DCL_TESS_DOMAIN, + OPCODE_DCL_TESS_PARTITIONING, + OPCODE_DCL_TESS_OUTPUT_PRIMITIVE, + OPCODE_DCL_HS_MAX_TESSFACTOR, + OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT, + OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT, + + OPCODE_DCL_THREAD_GROUP, + OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED, + OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW, + OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED, + OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW, + OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED, + OPCODE_DCL_RESOURCE_RAW, + OPCODE_DCL_RESOURCE_STRUCTURED, + OPCODE_LD_UAV_TYPED, + OPCODE_STORE_UAV_TYPED, + OPCODE_LD_RAW, + OPCODE_STORE_RAW, + OPCODE_LD_STRUCTURED, + OPCODE_STORE_STRUCTURED, + OPCODE_ATOMIC_AND, + OPCODE_ATOMIC_OR, + OPCODE_ATOMIC_XOR, + OPCODE_ATOMIC_CMP_STORE, + OPCODE_ATOMIC_IADD, + OPCODE_ATOMIC_IMAX, + OPCODE_ATOMIC_IMIN, + OPCODE_ATOMIC_UMAX, + OPCODE_ATOMIC_UMIN, + OPCODE_IMM_ATOMIC_ALLOC, + OPCODE_IMM_ATOMIC_CONSUME, + OPCODE_IMM_ATOMIC_IADD, + OPCODE_IMM_ATOMIC_AND, + OPCODE_IMM_ATOMIC_OR, + OPCODE_IMM_ATOMIC_XOR, + OPCODE_IMM_ATOMIC_EXCH, + OPCODE_IMM_ATOMIC_CMP_EXCH, + OPCODE_IMM_ATOMIC_IMAX, + OPCODE_IMM_ATOMIC_IMIN, + OPCODE_IMM_ATOMIC_UMAX, + OPCODE_IMM_ATOMIC_UMIN, + OPCODE_SYNC, + + OPCODE_DADD, + OPCODE_DMAX, + OPCODE_DMIN, + OPCODE_DMUL, + OPCODE_DEQ, + OPCODE_DGE, + OPCODE_DLT, + OPCODE_DNE, + OPCODE_DMOV, + OPCODE_DMOVC, + OPCODE_DTOF, + OPCODE_FTOD, + + OPCODE_EVAL_SNAPPED, + OPCODE_EVAL_SAMPLE_INDEX, + OPCODE_EVAL_CENTROID, + + OPCODE_DCL_GS_INSTANCE_COUNT, + + NUM_OPCODES, +}; + +enum CustomDataClass +{ + CUSTOMDATA_COMMENT = 0, + CUSTOMDATA_DEBUGINFO, + CUSTOMDATA_OPAQUE, + CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER, + + NUM_CUSTOMDATA_CLASSES, +}; + +enum ResinfoRetType +{ + RETTYPE_FLOAT = 0, + RETTYPE_RCPFLOAT, + RETTYPE_UINT, + + NUM_RETTYPES, +}; + +enum ExtendedOpcodeType +{ + EXTENDED_OPCODE_EMPTY = 0, + EXTENDED_OPCODE_SAMPLE_CONTROLS, + EXTENDED_OPCODE_RESOURCE_DIM, + EXTENDED_OPCODE_RESOURCE_RETURN_TYPE, + + NUM_EXTENDED_TYPES, +}; + +enum NumOperandComponents +{ + NUMCOMPS_0 = 0, + NUMCOMPS_1, + NUMCOMPS_4, + NUMCOMPS_N, + + MAX_COMPONENTS, +}; + +enum SelectionMode +{ + SELECTION_MASK = 0, + SELECTION_SWIZZLE, + SELECTION_SELECT_1, +}; + +enum OperandType +{ + TYPE_TEMP = 0, + TYPE_INPUT, + TYPE_OUTPUT, + TYPE_INDEXABLE_TEMP, + TYPE_IMMEDIATE32, + TYPE_IMMEDIATE64, + TYPE_SAMPLER, + TYPE_RESOURCE, + TYPE_CONSTANT_BUFFER, + TYPE_IMMEDIATE_CONSTANT_BUFFER, + TYPE_LABEL, + TYPE_INPUT_PRIMITIVEID, + TYPE_OUTPUT_DEPTH, + TYPE_NULL, + + TYPE_RASTERIZER, + TYPE_OUTPUT_COVERAGE_MASK, + + TYPE_STREAM, + TYPE_FUNCTION_BODY, + TYPE_FUNCTION_TABLE, + TYPE_INTERFACE, + TYPE_FUNCTION_INPUT, + TYPE_FUNCTION_OUTPUT, + TYPE_OUTPUT_CONTROL_POINT_ID, + TYPE_INPUT_FORK_INSTANCE_ID, + TYPE_INPUT_JOIN_INSTANCE_ID, + TYPE_INPUT_CONTROL_POINT, + TYPE_OUTPUT_CONTROL_POINT, + TYPE_INPUT_PATCH_CONSTANT, + TYPE_INPUT_DOMAIN_POINT, + TYPE_THIS_POINTER, + TYPE_UNORDERED_ACCESS_VIEW, + TYPE_THREAD_GROUP_SHARED_MEMORY, + TYPE_INPUT_THREAD_ID, + TYPE_INPUT_THREAD_GROUP_ID, + TYPE_INPUT_THREAD_ID_IN_GROUP, + TYPE_INPUT_COVERAGE_MASK, + TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED, + TYPE_INPUT_GS_INSTANCE_ID, + TYPE_OUTPUT_DEPTH_GREATER_EQUAL, + TYPE_OUTPUT_DEPTH_LESS_EQUAL, + TYPE_CYCLE_COUNTER, + + NUM_OPERAND_TYPES, +}; + +enum OperandIndexType +{ + INDEX_IMMEDIATE32 = 0, // 0 + INDEX_IMMEDIATE64, // 0 + INDEX_RELATIVE, // [r1] + INDEX_IMMEDIATE32_PLUS_RELATIVE, // [r1+0] + INDEX_IMMEDIATE64_PLUS_RELATIVE, // [r1+0] + + NUM_INDEX_TYPES +}; + +enum ExtendedOperandType +{ + EXTENDED_OPERAND_EMPTY = 0, + EXTENDED_OPERAND_MODIFIER, + + NUM_EXTENDED_OPERAND_TYPES, +}; + +enum OperandModifier +{ + OPERAND_MODIFIER_NONE = 0, + OPERAND_MODIFIER_NEG, + OPERAND_MODIFIER_ABS, + OPERAND_MODIFIER_ABSNEG, + + NUM_MODIFIERS, +}; + +enum SamplerMode +{ + SAMPLER_MODE_DEFAULT = 0, + SAMPLER_MODE_COMPARISON, + SAMPLER_MODE_MONO, + + NUM_SAMPLERS, +}; + +enum CBufferAccessPattern +{ + ACCESS_IMMEDIATE_INDEXED = 0, + ACCESS_DYNAMIC_INDEXED, + + NUM_PATTERNS, +}; + +enum TessellatorDomain +{ + DOMAIN_UNDEFINED = 0, + DOMAIN_ISOLINE, + DOMAIN_TRI, + DOMAIN_QUAD, + + NUM_DOMAINS, +}; + +enum TessellatorPartitioning +{ + PARTITIONING_UNDEFINED = 0, + PARTITIONING_INTEGER, + PARTITIONING_POW2, + PARTITIONING_FRACTIONAL_ODD, + PARTITIONING_FRACTIONAL_EVEN, + + NUM_PARTITIONINGS, +}; + +enum TessellatorOutputPrimitive +{ + OUTPUT_PRIMITIVE_UNDEFINED = 0, + OUTPUT_PRIMITIVE_POINT, + OUTPUT_PRIMITIVE_LINE, + OUTPUT_PRIMITIVE_TRIANGLE_CW, + OUTPUT_PRIMITIVE_TRIANGLE_CCW, + + NUM_OUTPUT_PRIMITIVES, +}; + +enum InterpolationMode +{ + INTERPOLATION_UNDEFINED = 0, + INTERPOLATION_CONSTANT, + INTERPOLATION_LINEAR, + INTERPOLATION_LINEAR_CENTROID, + INTERPOLATION_LINEAR_NOPERSPECTIVE, + INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID, + INTERPOLATION_LINEAR_SAMPLE, + INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE, + + NUM_INTERPOLATIONS, +}; + +enum PrimitiveTopology +{ + TOPOLOGY_UNDEFINED = 0, + TOPOLOGY_POINTLIST, + TOPOLOGY_LINELIST, + TOPOLOGY_LINESTRIP, + TOPOLOGY_TRIANGLELIST, + TOPOLOGY_TRIANGLESTRIP, + TOPOLOGY_LINELIST_ADJ, + TOPOLOGY_LINESTRIP_ADJ, + TOPOLOGY_TRIANGLELIST_ADJ, + TOPOLOGY_TRIANGLESTRIP_ADJ, + + NUM_TOPOLOGYS, +}; + +enum PrimitiveType +{ + PRIMITIVE_UNDEFINED = 0, + PRIMITIVE_POINT, + PRIMITIVE_LINE, + PRIMITIVE_TRIANGLE, + PRIMITIVE_LINE_ADJ, + PRIMITIVE_TRIANGLE_ADJ, + PRIMITIVE_1_CONTROL_POINT_PATCH, + PRIMITIVE_2_CONTROL_POINT_PATCH, + PRIMITIVE_3_CONTROL_POINT_PATCH, + PRIMITIVE_4_CONTROL_POINT_PATCH, + PRIMITIVE_5_CONTROL_POINT_PATCH, + PRIMITIVE_6_CONTROL_POINT_PATCH, + PRIMITIVE_7_CONTROL_POINT_PATCH, + PRIMITIVE_8_CONTROL_POINT_PATCH, + PRIMITIVE_9_CONTROL_POINT_PATCH, + PRIMITIVE_10_CONTROL_POINT_PATCH, + PRIMITIVE_11_CONTROL_POINT_PATCH, + PRIMITIVE_12_CONTROL_POINT_PATCH, + PRIMITIVE_13_CONTROL_POINT_PATCH, + PRIMITIVE_14_CONTROL_POINT_PATCH, + PRIMITIVE_15_CONTROL_POINT_PATCH, + PRIMITIVE_16_CONTROL_POINT_PATCH, + PRIMITIVE_17_CONTROL_POINT_PATCH, + PRIMITIVE_18_CONTROL_POINT_PATCH, + PRIMITIVE_19_CONTROL_POINT_PATCH, + PRIMITIVE_20_CONTROL_POINT_PATCH, + PRIMITIVE_21_CONTROL_POINT_PATCH, + PRIMITIVE_22_CONTROL_POINT_PATCH, + PRIMITIVE_23_CONTROL_POINT_PATCH, + PRIMITIVE_24_CONTROL_POINT_PATCH, + PRIMITIVE_25_CONTROL_POINT_PATCH, + PRIMITIVE_26_CONTROL_POINT_PATCH, + PRIMITIVE_27_CONTROL_POINT_PATCH, + PRIMITIVE_28_CONTROL_POINT_PATCH, + PRIMITIVE_29_CONTROL_POINT_PATCH, + PRIMITIVE_30_CONTROL_POINT_PATCH, + PRIMITIVE_31_CONTROL_POINT_PATCH, + PRIMITIVE_32_CONTROL_POINT_PATCH, + + NUM_PRIMITIVES, +}; + +enum SemanticName +{ + SEMANTIC_UNDEFINED = 0, + SEMANTIC_POSITION, + SEMANTIC_CLIP_DISTANCE, + SEMANTIC_CULL_DISTANCE, + SEMANTIC_RENDER_TARGET_ARRAY_INDEX, + SEMANTIC_VIEWPORT_ARRAY_INDEX, + SEMANTIC_VERTEX_ID, + SEMANTIC_PRIMITIVE_ID, + SEMANTIC_INSTANCE_ID, + SEMANTIC_IS_FRONT_FACE, + SEMANTIC_SAMPLE_INDEX, + SEMANTIC_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR, + SEMANTIC_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR, + SEMANTIC_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR, + SEMANTIC_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR, + SEMANTIC_FINAL_QUAD_U_INSIDE_TESSFACTOR, + SEMANTIC_FINAL_QUAD_V_INSIDE_TESSFACTOR, + SEMANTIC_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR, + SEMANTIC_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR, + SEMANTIC_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR, + SEMANTIC_FINAL_TRI_INSIDE_TESSFACTOR, + SEMANTIC_FINAL_LINE_DETAIL_TESSFACTOR, + SEMANTIC_FINAL_LINE_DENSITY_TESSFACTOR, + + NUM_SEMANTICS, +}; + +enum ResourceDimension +{ + RESOURCE_DIMENSION_UNKNOWN = 0, + RESOURCE_DIMENSION_BUFFER, + RESOURCE_DIMENSION_TEXTURE1D, + RESOURCE_DIMENSION_TEXTURE2D, + RESOURCE_DIMENSION_TEXTURE2DMS, + RESOURCE_DIMENSION_TEXTURE3D, + RESOURCE_DIMENSION_TEXTURECUBE, + RESOURCE_DIMENSION_TEXTURE1DARRAY, + RESOURCE_DIMENSION_TEXTURE2DARRAY, + RESOURCE_DIMENSION_TEXTURE2DMSARRAY, + RESOURCE_DIMENSION_TEXTURECUBEARRAY, + RESOURCE_DIMENSION_RAW_BUFFER, + RESOURCE_DIMENSION_STRUCTURED_BUFFER, + + NUM_DIMENSIONS, +}; + +enum ResourceRetType +{ + RETURN_TYPE_UNORM = 1, + RETURN_TYPE_SNORM, + RETURN_TYPE_SINT, + RETURN_TYPE_UINT, + RETURN_TYPE_FLOAT, + RETURN_TYPE_MIXED, + RETURN_TYPE_DOUBLE, + RETURN_TYPE_CONTINUED, + RETURN_TYPE_UNUSED, + + NUM_RETURN_TYPES, +}; + +enum ComponentType +{ + COMPONENT_TYPE_UNKNOWN = 0, + COMPONENT_TYPE_UINT32, + COMPONENT_TYPE_SINT32, + COMPONENT_TYPE_FLOAT32, + + NUM_COMP_TYPES, +}; + +///////////////////////////////////////////////////////////////////////// +// Main structures +///////////////////////////////////////////////////////////////////////// + +struct ASMIndex; + +struct ASMOperand +{ + ASMOperand() + { + type = NUM_OPERAND_TYPES; + numComponents = MAX_COMPONENTS; + comps[0] = comps[1] = comps[2] = comps[3] = 0xff; + modifier = OPERAND_MODIFIER_NONE; + } + + bool operator ==(const ASMOperand &o) const; + + string toString(bool swizzle = true) const; + + /////////////////////////////////////// + + OperandType type; // temp register, constant buffer, input, output, other more specialised types + NumOperandComponents numComponents; // scalar, 4-vector or N-vector (currently unused) + + uint8_t comps[4]; // the components. each is 0,1,2,3 for x,y,z,w or 0xff if unused. + // e.g. .x = { 0, -1, -1, -1 } + // .zzw = { 2, 2, 3, -1 } + // .zyx = { 2, 1, 0, -1 } + // .zxxw = { 2, 0, 0, 3 } + // .xyzw = { 0, 1, 2, 3 } + // .wzyx = { 3, 2, 1, 0 } + + vector indices; // indices for this register. + // 0 means this is a special register, specified by type alone. + // 1 is probably most common. Indicates ASMIndex specifies the register + // 2 is for constant buffers, array inputs etc. [0] indicates the cbuffer, [1] indicates the cbuffer member + // 3 is rare but follows the above pattern + + vector values; // if this operand is immediate, the values are here + + OperandModifier modifier; // modifier, neg, abs(), -abs() etc. Could potentially be multiple modifiers in future + + uint32_t funcNum; // interface this operand refers to +}; + +struct ASMIndex +{ + ASMIndex() + { + absolute = false; + relative = false; + index = 0; + } + + bool operator !=(const ASMIndex &o) const + { + return !(*this == o); + } + + bool operator ==(const ASMIndex &o) const + { + if(absolute == o.absolute && relative == o.relative) + { + if(absolute && !relative) + return index == o.index; + else if(relative && !absolute) + return operand == o.operand; + + return index == o.index && operand == o.operand; + } + + return false; + } + + string str; + + /////////////////////////////////////// + + bool absolute; // if true, use uint64 index below as an absolute value + bool relative; // if true, use the operand below. + + // note, absolute == relative == true IS VALID. It means you must add the two. + // both cannot be false, at least one must be true. + + uint64_t index; + ASMOperand operand; +}; + +struct ASMDecl +{ + ASMDecl() + { + offset = 0; + length = 0; + instruction = 0; + declaration = NUM_OPCODES; + refactoringAllowed = doublePrecisionFloats = forceEarlyDepthStencil = enableRawAndStructuredBuffers = false; + stride = 0; + hasCounter = false; + numTemps = 0; + count = 0; + groupSize[0] = groupSize[1] = groupSize[2] = 0; + resType[0] = resType[1] = resType[2] = resType[3] = NUM_RETURN_TYPES; + dim = RESOURCE_DIMENSION_UNKNOWN; + sampleCount = 0; + interpolation = INTERPOLATION_UNDEFINED; + systemValue = eAttr_None; + maxOut = 0; + samplerMode = NUM_SAMPLERS; + domain = DOMAIN_UNDEFINED; + controlPointCount = 0; + partition = PARTITIONING_UNDEFINED; + outPrim = OUTPUT_PRIMITIVE_UNDEFINED; + inPrim = PRIMITIVE_UNDEFINED; + outTopology = TOPOLOGY_UNDEFINED; + } + + string str; + + /////////////////////////////////////// + + uintptr_t offset; + uint32_t length; + + size_t instruction; // happens before this instruction. Usually 0 as all decls are up front, + // but can be non-zero for e.g. HS control point and join phase + OpcodeType declaration; + + ASMOperand operand; // many decls use an operand to declare things + + vector immediateData; // raw data (like default value of operand) for immediate constant buffer decl + + // opcode specific data + + // OPCODE_DCL_GLOBAL_FLAGS + bool refactoringAllowed; + bool doublePrecisionFloats; + bool forceEarlyDepthStencil; + bool enableRawAndStructuredBuffers; + + // OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED + uint32_t stride; + bool hasCounter; + + // OPCODE_DCL_TEMPS, OPCODE_DCL_INDEXABLE_TEMP + uint32_t numTemps; + + // OPCODE_DCL_INDEXABLE_TEMP + uint32_t tempReg; + uint32_t tempComponentCount; + + // OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED + uint32_t count; + + // OPCODE_DCL_THREAD_GROUP + uint32_t groupSize[3]; + + // OPCODE_DCL_RESOURCE + ResourceRetType resType[4]; + ResourceDimension dim; + uint32_t sampleCount; + + // OPCODE_DCL_INPUT_PS + InterpolationMode interpolation; + + // OPCODE_DCL_INPUT_SIV + uint32_t systemValue; + + // OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT + uint32_t maxOut; + + // OPCODE_DCL_SAMPLER + SamplerMode samplerMode; + + // OPCODE_DCL_TESS_DOMAIN + TessellatorDomain domain; + + // OPCODE_DCL_INPUT_CONTROL_POINT_COUNT + uint32_t controlPointCount; + + // OPCODE_DCL_TESS_PARTITIONING + TessellatorPartitioning partition; + + // OPCODE_DCL_TESS_OUTPUT_PRIMITIVE + TessellatorOutputPrimitive outPrim; + + // OPCODE_DCL_GS_INPUT_PRIMITIVE + PrimitiveType inPrim; + + // OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY + PrimitiveTopology outTopology; + + // OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT + uint32_t forkInstanceCount; + + // OPCODE_DCL_INDEX_RANGE + uint32_t indexRange; + + // OPCODE_DCL_HS_MAX_TESSFACTOR + float maxTessFactor; + + // OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED + bool globallyCoherant; + + // OPCODE_DCL_FUNCTION_BODY + uint32_t functionBody; + + // OPCODE_DCL_FUNCTION_TABLE + uint32_t functionTable; + + // OPCODE_DCL_INTERFACE + uint32_t interfaceID; + uint32_t numInterfaces; + uint32_t numTypes; +}; + +struct ASMOperation +{ + ASMOperation() + { + offset = 0; + length = 0; + operation = NUM_OPCODES; + nonzero = false; + saturate = false; + preciseValues = 0; + resinfoRetType = NUM_RETTYPES; + syncFlags = 0; + texelOffset[0] = texelOffset[1] = texelOffset[2] = 0; + resDim = RESOURCE_DIMENSION_UNKNOWN; + resType[0] = resType[1] = resType[2] = resType[3] = RETURN_TYPE_UNUSED; + } + + string str; + + /////////////////////////////////////// + + uintptr_t offset; + uint32_t length; + + OpcodeType operation; + bool nonzero; // for if, etc. If it checks for zero or nonzero + bool saturate; // should the result be saturated. + uint32_t preciseValues; // for multiple output operand operations + ResinfoRetType resinfoRetType; // return type of resinfo + uint32_t syncFlags; // sync flags (for compute shader sync operations) + + int texelOffset[3]; // U,V,W texel offset + ResourceDimension resDim; // resource dimension (tex2d etc) + ResourceRetType resType[4]; // return type (e.g. for a sample operation) + + vector operands; +}; + +}; // DXBC \ No newline at end of file diff --git a/renderdoc/driver/d3d11/shaders/dxbc_inspect.cpp b/renderdoc/driver/d3d11/shaders/dxbc_inspect.cpp new file mode 100644 index 0000000000..c6012cb073 --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_inspect.cpp @@ -0,0 +1,2069 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" +#include "serialise/serialiser.h" +#include "common/string_utils.h" +#include "dxbc_inspect.h" +#include "dxbc_sdbg.h" +#include "dxbc_spdb.h" + +#include + +using std::make_pair; + +namespace DXBC +{ + +struct RDEFCBufferVariable +{ + uint32_t nameOffset; + + uint32_t startOffset; // start offset in bytes of this variable in the cbuffer + uint32_t size; // size in bytes of this type + uint32_t flags; + + uint32_t typeOffset; // offset to a RDEFCBufferType + uint32_t defaultValueOffset; // offset to [size] bytes where the default value can be found, or 0 for no default value + + uint32_t unknown[4]; // this is only present for RDEFHeader.targetVersion >= 0x500. In earlier versions, this is not in the file. +}; + +struct RDEFCBuffer +{ + uint32_t nameOffset; // relative to the same offset base position as others in this chunk - after FourCC and chunk length. + + DXBC::CountOffset variables; + uint32_t size; // size in bytes of this cbuffer + uint32_t flags; + uint32_t type; + + // followed immediately by [variables.count] RDEFCBufferVariables +}; + +// mostly for nested structures +struct RDEFCBufferChildType +{ + uint32_t nameOffset; + uint32_t typeOffset; // offset to a RDEFCBufferType + uint32_t memberOffset; // byte offset in the parent structure - not a file offset +}; + +struct RDEFCBufferType +{ + uint16_t varClass; // D3D_SHADER_VARIABLE_CLASS + uint16_t varType; // D3D_SHADER_VARIABLE_TYPE + + uint16_t rows; + uint16_t cols; + + uint16_t numElems; + uint16_t numMembers; + + uint32_t memberOffset; // offset to [numMembers] RDEFCBufferChildTypes that point to the member types + + // my own guessing - not in wine structures + // looks like these are only present for RD11 shaders + uint32_t unknown[4]; + + uint32_t nameOffset; // offset to type name +}; + +// this isn't a proper chunk, it's the file header before all the chunks. +struct FileHeader +{ + uint32_t fourcc; // "DXBC" + uint32_t hashValue[4]; // unknown hash function and data + uint32_t unknown; + uint32_t fileLength; + uint32_t numChunks; + // uint32 chunkOffsets[numChunks]; follows +}; + +struct RDEFHeader +{ + uint32_t fourcc; // "RDEF" + uint32_t chunkLength; // length of this chunk + + ////////////////////////////////////////////////////// + // offsets are relative to this position in the file. + // NOT the end of this structure. Note this differs + // from the SDBG chunk, but matches the SIGN chunks + + // note that these two actually come in the opposite order after + // this header. So cbuffers offset will be higher than resources + // offset + CountOffset cbuffers; + CountOffset resources; + + uint16_t targetVersion; // 0x0500 is the latest. + uint16_t targetShaderStage; // 0xffff for pixel shaders, 0xfffe for vertex shaders + + uint32_t flags; + uint32_t creatorOffset; // null terminated ascii string + + uint32_t unknown[8]; // this is only present for targetVersion >= 0x500. In earlier versions, this is not in the file. +}; + +struct RDEFResource +{ + uint32_t nameOffset; // relative to the same offset base position as others in this chunk - after FourCC and chunk length. + + uint32_t type; + uint32_t retType; + uint32_t dimension; + int32_t sampleCount; + uint32_t bindPoint; + uint32_t bindCount; + uint32_t flags; +}; + +struct SIGNHeader +{ + uint32_t fourcc; // "ISGN", "OSGN, "OSG5", "PCSG" + uint32_t chunkLength; // length of this chunk + + ////////////////////////////////////////////////////// + // offsets are relative to this position in the file. + // NOT the end of this structure. Note this differs + // from the SDBG chunk, but matches the RDEF chunk + + uint32_t numElems; + uint32_t unknown; + + // followed by SIGNElement elements[numElems]; - note that SIGNElement's size depends on the type. + // for OSG5 you should use SIGNElement7 +}; + +struct SIGNElement +{ + uint32_t nameOffset; // relative to the same offset base position as others in similar chunks - after FourCC and chunk length. + + uint32_t semanticIdx; + uint32_t systemType; + uint32_t componentType; + uint32_t registerNum; + + byte mask; + byte rwMask; + uint16_t unused; +}; + +struct SIGNElement7 +{ + uint32_t stream; + SIGNElement elem; +}; + +static const uint32_t STATSizeDX10 = 29*4; // either 29 uint32s +static const uint32_t STATSizeDX11 = 37*4; // or 37 uint32s + +static const uint32_t FOURCC_DXBC = MAKE_FOURCC('D', 'X', 'B', 'C'); +static const uint32_t FOURCC_RDEF = MAKE_FOURCC('R', 'D', 'E', 'F'); +static const uint32_t FOURCC_RD11 = MAKE_FOURCC('R', 'D', '1', '1'); +static const uint32_t FOURCC_STAT = MAKE_FOURCC('S', 'T', 'A', 'T'); +static const uint32_t FOURCC_SHEX = MAKE_FOURCC('S', 'H', 'E', 'X'); +static const uint32_t FOURCC_SHDR = MAKE_FOURCC('S', 'H', 'D', 'R'); +static const uint32_t FOURCC_SDBG = MAKE_FOURCC('S', 'D', 'B', 'G'); +static const uint32_t FOURCC_SPDB = MAKE_FOURCC('S', 'P', 'D', 'B'); +static const uint32_t FOURCC_ISGN = MAKE_FOURCC('I', 'S', 'G', 'N'); +static const uint32_t FOURCC_OSGN = MAKE_FOURCC('O', 'S', 'G', 'N'); +static const uint32_t FOURCC_OSG5 = MAKE_FOURCC('O', 'S', 'G', '5'); +static const uint32_t FOURCC_PCSG = MAKE_FOURCC('P', 'C', 'S', 'G'); +static const uint32_t FOURCC_Aon9 = MAKE_FOURCC('A', 'o', 'n', '9'); + +int TypeByteSize(VariableType t) +{ + switch(t) + { + case VARTYPE_UINT8: + return 1; + case VARTYPE_BOOL: + case VARTYPE_INT: + case VARTYPE_FLOAT: + case VARTYPE_UINT: + return 4; + case VARTYPE_DOUBLE: + return 8; + // 'virtual' type. Just return 1 + case VARTYPE_INTERFACE_POINTER: + return 1; + default: + RDCFATAL("Trying to take size of undefined type %d", t); + } +} + +SystemAttribute GetSystemValue(uint32_t systemValue) +{ + enum DXBC_SVSemantic + { + SVNAME_UNDEFINED = 0, + SVNAME_POSITION, + SVNAME_CLIP_DISTANCE, + SVNAME_CULL_DISTANCE, + SVNAME_RENDER_TARGET_ARRAY_INDEX, + SVNAME_VIEWPORT_ARRAY_INDEX, + SVNAME_VERTEX_ID, + SVNAME_PRIMITIVE_ID, + SVNAME_INSTANCE_ID, + SVNAME_IS_FRONT_FACE, + SVNAME_SAMPLE_INDEX, + + // following are non-contiguous + SVNAME_FINAL_QUAD_EDGE_TESSFACTOR, + SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR = SVNAME_FINAL_QUAD_EDGE_TESSFACTOR+4, + SVNAME_FINAL_TRI_EDGE_TESSFACTOR = SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR+2, + SVNAME_FINAL_TRI_INSIDE_TESSFACTOR = SVNAME_FINAL_TRI_EDGE_TESSFACTOR+3, + SVNAME_FINAL_LINE_DETAIL_TESSFACTOR, + SVNAME_FINAL_LINE_DENSITY_TESSFACTOR, + + SVNAME_TARGET = 64, + SVNAME_DEPTH, + SVNAME_COVERAGE, + SVNAME_DEPTH_GREATER_EQUAL, + SVNAME_DEPTH_LESS_EQUAL, + }; + + switch(systemValue) + { + case SVNAME_UNDEFINED: + return eAttr_None; + case SVNAME_POSITION: + return eAttr_Position; + case SVNAME_CLIP_DISTANCE: + return eAttr_ClipDistance; + case SVNAME_CULL_DISTANCE: + return eAttr_CullDistance; + case SVNAME_RENDER_TARGET_ARRAY_INDEX: + return eAttr_RTIndex; + case SVNAME_VIEWPORT_ARRAY_INDEX: + return eAttr_ViewportIndex; + case SVNAME_VERTEX_ID: + return eAttr_VertexIndex; + case SVNAME_PRIMITIVE_ID: + return eAttr_PrimitiveIndex; + case SVNAME_INSTANCE_ID: + return eAttr_InstanceIndex; + case SVNAME_IS_FRONT_FACE: + return eAttr_IsFrontFace; + case SVNAME_SAMPLE_INDEX: + return eAttr_MSAASampleIndex; + case SVNAME_FINAL_QUAD_EDGE_TESSFACTOR: + return eAttr_OuterTessFactor; + case SVNAME_FINAL_QUAD_INSIDE_TESSFACTOR: + return eAttr_InsideTessFactor; + case SVNAME_FINAL_TRI_EDGE_TESSFACTOR: + return eAttr_OuterTessFactor; + case SVNAME_FINAL_TRI_INSIDE_TESSFACTOR: + return eAttr_InsideTessFactor; + case SVNAME_FINAL_LINE_DETAIL_TESSFACTOR: + return eAttr_OuterTessFactor; + case SVNAME_FINAL_LINE_DENSITY_TESSFACTOR: + return eAttr_InsideTessFactor; + case SVNAME_TARGET: + return eAttr_ColourOutput; + case SVNAME_DEPTH: + return eAttr_DepthOutput; + case SVNAME_COVERAGE: + return eAttr_MSAACoverage; + case SVNAME_DEPTH_GREATER_EQUAL: + return eAttr_DepthOutputGreaterEqual; + case SVNAME_DEPTH_LESS_EQUAL: + return eAttr_DepthOutputLessEqual; + } + + return eAttr_None; +} + +string TypeName(CBufferVariableType::Descriptor desc) +{ + string ret; + + char *type = ""; + switch(desc.type) + { + case VARTYPE_BOOL: + type = "bool"; break; + case VARTYPE_INT: + type = "int"; break; + case VARTYPE_FLOAT: + type = "float"; break; + case VARTYPE_DOUBLE: + type = "double"; break; + case VARTYPE_UINT: + type = "uint"; break; + case VARTYPE_UINT8: + type = "ubyte"; break; + case VARTYPE_VOID: + type = "void"; break; + case VARTYPE_INTERFACE_POINTER: + type = "interface"; break; + default: + RDCERR("Unexpected type in RDEF variable type %d", type); + } + + if(desc.varClass == CLASS_OBJECT) + RDCERR("Unexpected object in RDEF variable type"); + else if(desc.varClass == CLASS_INTERFACE_CLASS) + RDCERR("Unexpected iface class in RDEF variable type"); + else if(desc.varClass == CLASS_INTERFACE_POINTER) + ret = type; + else if(desc.varClass == CLASS_STRUCT) + ret = ""; + else + { + char buf[64] = {0}; + + if(desc.rows > 1) + { + StringFormat::snprintf(buf, 63, "%hs%dx%d", type, desc.rows, desc.cols); + + if(desc.varClass == CLASS_MATRIX_ROWS) + { + ret = "row_major "; + ret += buf; + } + else + { + ret = buf; + } + } + else if(desc.cols > 1) + { + StringFormat::snprintf(buf, 63, "%hs%d", type, desc.cols); + + ret = buf; + } + else + { + ret = type; + } + } + + return ret; +} + +CBufferVariableType DXBCFile::ParseRDEFType(RDEFHeader *h, char *chunkContents, uint32_t typeOffset) +{ + if(m_Variables.find(typeOffset) != m_Variables.end()) + return m_Variables[typeOffset]; + + RDEFCBufferType *type = (RDEFCBufferType *)(chunkContents + typeOffset); + + CBufferVariableType ret; + + ret.descriptor.varClass = (VariableClass)type->varClass; + ret.descriptor.cols = type->cols; + ret.descriptor.elements = type->numElems; + ret.descriptor.members = type->numMembers; + ret.descriptor.rows = type->rows; + ret.descriptor.type = (VariableType)type->varType; + + ret.descriptor.name = TypeName(ret.descriptor); + + if(ret.descriptor.name == "interface") + { + if(h->targetVersion >= 0x500 && type->nameOffset > 0) + { + ret.descriptor.name += " " + string(chunkContents + type->nameOffset); + } + else + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "unnamed_iface_0x%08x", typeOffset); + ret.descriptor.name += " " + string(buf); + } + } + + // rename unnamed structs to have valid identifiers as type name + if(ret.descriptor.name.find("") != string::npos) + { + if(h->targetVersion >= 0x500 && type->nameOffset > 0) + { + ret.descriptor.name = chunkContents + type->nameOffset; + } + else + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "unnamed_struct_0x%08x", typeOffset); + ret.descriptor.name = buf; + } + } + + if(type->memberOffset) + { + RDEFCBufferChildType *members = (RDEFCBufferChildType *)(chunkContents + type->memberOffset); + + ret.members.reserve(type->numMembers); + + ret.descriptor.bytesize = 0; + + for(int32_t j=0; j < type->numMembers; j++) + { + CBufferVariable v; + + v.name = chunkContents + members[j].nameOffset; + v.type = ParseRDEFType(h, chunkContents, members[j].typeOffset); + v.descriptor.offset = members[j].memberOffset; + + ret.descriptor.bytesize += v.type.descriptor.bytesize; + + // N/A + v.descriptor.flags = 0; + v.descriptor.startTexture = 0; + v.descriptor.numTextures = 0; + v.descriptor.startSampler = 0; + v.descriptor.numSamplers = 0; + v.descriptor.defaultValue.clear(); + + ret.members.push_back(v); + } + } + else + { + // matrices take up a full vector for each column or row depending which is major, regardless of the other dimension + if(ret.descriptor.varClass == CLASS_MATRIX_COLUMNS) + ret.descriptor.bytesize = TypeByteSize(ret.descriptor.type)*ret.descriptor.cols*4*RDCMAX(1U,ret.descriptor.elements); + else if(ret.descriptor.varClass == CLASS_MATRIX_ROWS) + ret.descriptor.bytesize = TypeByteSize(ret.descriptor.type)*ret.descriptor.rows*4*RDCMAX(1U,ret.descriptor.elements); + else + ret.descriptor.bytesize = TypeByteSize(ret.descriptor.type)*ret.descriptor.rows*ret.descriptor.cols*RDCMAX(1U,ret.descriptor.elements); + } + + m_Variables[typeOffset] = ret; + return ret; +} + +DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) +{ + m_DebugInfo = NULL; + + RDCASSERT(ByteCodeLength < UINT32_MAX); + + m_ShaderBlob.resize(ByteCodeLength); + memcpy(&m_ShaderBlob[0], ByteCode, m_ShaderBlob.size()); + + char *data = (char *)&m_ShaderBlob[0]; // just for convenience + + FileHeader *header = (FileHeader *)&m_ShaderBlob[0]; + + if(header->fourcc != FOURCC_DXBC) + return; + + if(header->fileLength != (uint32_t)ByteCodeLength) + return; + + // default to vertex shader to support blobs without RDEF chunks (e.g. used with + // input layouts if they're super stripped down) + m_Type = D3D11_SHVER_VERTEX_SHADER; + + bool rdefFound = false; + + uint32_t *chunkOffsets = (uint32_t *)(header+1); // right after the header + + for(uint32_t chunkIdx = 0; chunkIdx < header->numChunks; chunkIdx++) + { + uint32_t *fourcc = (uint32_t *)(data + chunkOffsets[chunkIdx]); + uint32_t *chunkSize = (uint32_t *)(data + chunkOffsets[chunkIdx] + sizeof(uint32_t)); + + char *chunkContents = (char *)(data + chunkOffsets[chunkIdx] + sizeof(uint32_t)*2); + + if(*fourcc == FOURCC_RDEF) + { + RDEFHeader *h = (RDEFHeader *)fourcc; + + rdefFound = true; + + char *basePtr = (char *)(h+1); + + if(h->targetVersion >= 0x500) + { + RDCASSERT(h->unknown[0] == FOURCC_RD11); + } + + if(h->targetShaderStage == 0xffff) + m_Type = D3D11_SHVER_PIXEL_SHADER; + else if(h->targetShaderStage == 0xfffe) + m_Type = D3D11_SHVER_VERTEX_SHADER; + + else if(h->targetShaderStage == 0x4753) // 'GS' + m_Type = D3D11_SHVER_GEOMETRY_SHADER; + + else if(h->targetShaderStage == 0x4853) // 'HS' + m_Type = D3D11_SHVER_HULL_SHADER; + else if(h->targetShaderStage == 0x4453) // 'DS' + m_Type = D3D11_SHVER_DOMAIN_SHADER; + else if(h->targetShaderStage == 0x4353) // 'CS' + m_Type = D3D11_SHVER_COMPUTE_SHADER; + + m_Resources.reserve(h->resources.count); + + map cbufferSlots; + uint32_t maxCBufferSlot = 0; + + for(int32_t i = 0; i < h->resources.count; i++) + { + RDEFResource *res = (RDEFResource *)(chunkContents + h->resources.offset + i*sizeof(RDEFResource)); + + ShaderInputBind desc; + + desc.name = chunkContents + res->nameOffset; + desc.type = (ShaderInputBind::InputType)res->type; + desc.bindPoint = res->bindPoint; + desc.bindCount = res->bindCount; + desc.flags = res->flags; + desc.retType = (ShaderInputBind::RetType)res->retType; + desc.dimension = (ShaderInputBind::Dimension)res->dimension; + desc.numSamples = res->sampleCount; + + if(desc.numSamples == ~0 && + desc.retType != ShaderInputBind::RETTYPE_MIXED && + desc.retType != ShaderInputBind::RETTYPE_UNKNOWN && + desc.retType != ShaderInputBind::RETTYPE_CONTINUED) + { + // uint, uint2, uint3, uint4 seem to be in these bits of flags. + desc.numSamples = 1 + ((desc.flags&0xC) >> 2); + } + + if(desc.type == ShaderInputBind::TYPE_CBUFFER) + { + cbufferSlots[desc.name] = desc.bindPoint; + maxCBufferSlot = RDCMAX(maxCBufferSlot, desc.bindPoint); + } + + m_Resources.push_back(desc); + } + + if(h->cbuffers.count > 0) + m_CBuffers.resize(maxCBufferSlot+1); + + for(int32_t i = 0; i < h->cbuffers.count; i++) + { + RDEFCBuffer *cbuf = (RDEFCBuffer *)(chunkContents + h->cbuffers.offset + i*sizeof(RDEFCBuffer)); + + CBuffer cb; + + cb.name = chunkContents + cbuf->nameOffset; + + cb.descriptor.name = chunkContents + cbuf->nameOffset; + cb.descriptor.byteSize = cbuf->size; + cb.descriptor.type = (CBuffer::Descriptor::Type)cbuf->type; + cb.descriptor.flags = cbuf->flags; + cb.descriptor.numVars = cbuf->variables.count; + + cb.variables.reserve(cbuf->variables.count); + + size_t varStride = sizeof(RDEFCBufferVariable); + + if(h->targetVersion < 0x500) + varStride -= sizeof(((RDEFCBufferVariable *)0)->unknown); + + for(int32_t vi = 0; vi < cbuf->variables.count; vi++) + { + RDEFCBufferVariable *var = (RDEFCBufferVariable *)(chunkContents + cbuf->variables.offset + vi*varStride); + + RDCASSERT(var->nameOffset < ByteCodeLength); + + CBufferVariable v; + + v.name = chunkContents + var->nameOffset; + + v.descriptor.defaultValue.resize(var->size); + + if(var->defaultValueOffset) + { + memcpy(&v.descriptor.defaultValue[0], chunkContents + var->defaultValueOffset, var->size); + } + + v.descriptor.name = chunkContents + var->nameOffset; + //v.descriptor.bytesize = var->size; // size with cbuffer padding + v.descriptor.offset = var->startOffset; + v.descriptor.flags = var->flags; + + v.descriptor.startTexture = (uint32_t)-1; + v.descriptor.startSampler = (uint32_t)-1; + v.descriptor.numSamplers = 0; + v.descriptor.numTextures = 0; + + v.type = ParseRDEFType(h, chunkContents, var->typeOffset); + + cb.variables.push_back(v); + } + + if(cb.descriptor.type == CBuffer::Descriptor::TYPE_CBUFFER) + { + RDCASSERT(cbufferSlots.find(cb.name) != cbufferSlots.end()); + m_CBuffers[cbufferSlots[cb.name]] = cb; + } + else if(cb.descriptor.type == CBuffer::Descriptor::TYPE_RESOURCE_BIND_INFO) + { + RDCASSERT(cb.variables.size() == 1 && cb.variables[0].name == "$Element"); + m_ResourceBinds[cb.name] = cb.variables[0].type; + } + else if(cb.descriptor.type == CBuffer::Descriptor::TYPE_INTERFACE_POINTERS) + { + m_Interfaces = cb; + } + else + { + RDCDEBUG("Unused information, buffer %d: %hs", cb.descriptor.type, cb.descriptor.name.c_str()); + } + } + } + else if(*fourcc == FOURCC_STAT) + { + if( *chunkSize == STATSizeDX10 ) + { + memcpy(&m_ShaderStats, chunkContents, STATSizeDX10); + m_ShaderStats.version = ShaderStatistics::STATS_DX10; + } + else if( *chunkSize == STATSizeDX11 ) + { + memcpy(&m_ShaderStats, chunkContents, STATSizeDX11); + m_ShaderStats.version = ShaderStatistics::STATS_DX11; + } + else + { + RDCERR("Unexpected Unexpected STAT chunk version"); + } + } + else if(*fourcc == FOURCC_SHEX || *fourcc == FOURCC_SHDR) + { + m_HexDump.resize(*chunkSize / sizeof(uint32_t)); + memcpy((uint32_t *)&m_HexDump[0], chunkContents, *chunkSize); + } + } + + DisassembleHexDump(); + + // didn't find an rdef means reflection information was stripped. + // Attempt to reverse engineer basic info from declarations + if(!rdefFound) + GuessResources(); + + for(uint32_t chunkIdx = 0; chunkIdx < header->numChunks; chunkIdx++) + { + uint32_t *fourcc = (uint32_t *)(data + chunkOffsets[chunkIdx]); + uint32_t *chunkSize = (uint32_t *)(data + chunkOffsets[chunkIdx] + sizeof(uint32_t)); + + char *chunkContents = (char *)(data + chunkOffsets[chunkIdx] + sizeof(uint32_t)*2); + + if(*fourcc == FOURCC_ISGN || *fourcc == FOURCC_OSGN || *fourcc == FOURCC_OSG5 || *fourcc == FOURCC_PCSG) + { + SIGNHeader *sign = (SIGNHeader *)fourcc; + + vector *sig = NULL; + + bool input = false; + bool output = false; + bool patch = false; + + if(*fourcc == FOURCC_ISGN) + { + sig = &m_InputSig; + input = true; + } + if(*fourcc == FOURCC_OSGN || *fourcc == FOURCC_OSG5) + { + sig = &m_OutputSig; + output = true; + } + if(*fourcc == FOURCC_PCSG) + { + sig = &m_PatchConstantSig; + patch = true; + } + + RDCASSERT(sig && sig->empty()); + + SIGNElement *el = (SIGNElement *)(sign+1); + SIGNElement7 *el7 = (SIGNElement7 *)el; + + for(uint32_t signIdx = 0; signIdx < sign->numElems; signIdx++) + { + SigParameter desc; + + if(*fourcc == FOURCC_OSG5) + { + desc.stream = el7->stream; + + el = &el7->elem; + } + + ComponentType compType = (ComponentType)el->componentType; + desc.compType = eCompType_Float; + if(compType == COMPONENT_TYPE_UINT32) + desc.compType = eCompType_UInt; + else if(compType == COMPONENT_TYPE_SINT32) + desc.compType = eCompType_SInt; + else if(compType != COMPONENT_TYPE_FLOAT32) + RDCERR("Unexpected component type in signature"); + + desc.regChannelMask = (uint8_t)(el->mask&0xff); + desc.channelUsedMask = (uint8_t)(el->rwMask&0xff); + desc.regIndex = el->registerNum; + desc.semanticIndex = el->semanticIdx; + desc.semanticName = chunkContents + el->nameOffset; + desc.systemValue = GetSystemValue(el->systemType); + desc.compCount = + (desc.regChannelMask & 0x1 ? 1 : 0) + + (desc.regChannelMask & 0x2 ? 1 : 0) + + (desc.regChannelMask & 0x4 ? 1 : 0) + + (desc.regChannelMask & 0x8 ? 1 : 0); + + RDCASSERT(m_Type != (D3D11_SHADER_VERSION_TYPE)-1); + + // pixel shader outputs with registers are always targets + if(m_Type == D3D11_SHVER_PIXEL_SHADER && output && desc.systemValue == eAttr_None && + desc.regIndex >= 0 && desc.regIndex <= 16) + desc.systemValue = eAttr_ColourOutput; + + // check system value semantics + if(desc.systemValue == eAttr_None) + { + if(!_stricmp(desc.semanticName.elems, "SV_Position")) + desc.systemValue = eAttr_Position; + if(!_stricmp(desc.semanticName.elems, "SV_ClipDistance")) + desc.systemValue = eAttr_ClipDistance; + if(!_stricmp(desc.semanticName.elems, "SV_CullDistance")) + desc.systemValue = eAttr_CullDistance; + if(!_stricmp(desc.semanticName.elems, "SV_RenderTargetArrayIndex")) + desc.systemValue = eAttr_RTIndex; + if(!_stricmp(desc.semanticName.elems, "SV_ViewportArrayIndex")) + desc.systemValue = eAttr_ViewportIndex; + if(!_stricmp(desc.semanticName.elems, "SV_VertexID")) + desc.systemValue = eAttr_VertexIndex; + if(!_stricmp(desc.semanticName.elems, "SV_PrimitiveID")) + desc.systemValue = eAttr_PrimitiveIndex; + if(!_stricmp(desc.semanticName.elems, "SV_InstanceID")) + desc.systemValue = eAttr_InstanceIndex; + if(!_stricmp(desc.semanticName.elems, "SV_DispatchThreadID")) + desc.systemValue = eAttr_DispatchThreadIndex; + if(!_stricmp(desc.semanticName.elems, "SV_GroupID")) + desc.systemValue = eAttr_GroupIndex; + if(!_stricmp(desc.semanticName.elems, "SV_GroupIndex")) + desc.systemValue = eAttr_GroupFlatIndex; + if(!_stricmp(desc.semanticName.elems, "SV_GroupThreadID")) + desc.systemValue = eAttr_GroupThreadIndex; + if(!_stricmp(desc.semanticName.elems, "SV_GSInstanceID")) + desc.systemValue = eAttr_GSInstanceIndex; + if(!_stricmp(desc.semanticName.elems, "SV_OutputControlPointID")) + desc.systemValue = eAttr_OutputControlPointIndex; + if(!_stricmp(desc.semanticName.elems, "SV_DomainLocation")) + desc.systemValue = eAttr_DomainLocation; + if(!_stricmp(desc.semanticName.elems, "SV_IsFrontFace")) + desc.systemValue = eAttr_IsFrontFace; + if(!_stricmp(desc.semanticName.elems, "SV_SampleIndex")) + desc.systemValue = eAttr_MSAASampleIndex; + if(!_stricmp(desc.semanticName.elems, "SV_TessFactor")) + desc.systemValue = eAttr_OuterTessFactor; + if(!_stricmp(desc.semanticName.elems, "SV_InsideTessFactor")) + desc.systemValue = eAttr_InsideTessFactor; + if(!_stricmp(desc.semanticName.elems, "SV_Target")) + desc.systemValue = eAttr_ColourOutput; + if(!_stricmp(desc.semanticName.elems, "SV_Depth")) + desc.systemValue = eAttr_DepthOutput; + if(!_stricmp(desc.semanticName.elems, "SV_Coverage")) + desc.systemValue = eAttr_MSAACoverage; + if(!_stricmp(desc.semanticName.elems, "SV_DepthGreaterEqual")) + desc.systemValue = eAttr_DepthOutputGreaterEqual; + if(!_stricmp(desc.semanticName.elems, "SV_DepthLessEqual")) + desc.systemValue = eAttr_DepthOutputLessEqual; + } + + RDCASSERT(desc.systemValue != eAttr_None || desc.regIndex >= 0); + + sig->push_back(desc); + + el++; + el7++; + } + + for(uint32_t i = 0; i < sign->numElems; i++) + { + SigParameter &a = (*sig)[i]; + + for(uint32_t j = 0; j < sign->numElems; j++) + { + SigParameter &b = (*sig)[j]; + if(i != j && !strcmp(a.semanticName.elems, b.semanticName.elems)) + { + a.needSemanticIndex = true; + break; + } + } + + string semanticIdxName = a.semanticName.elems; + if(a.needSemanticIndex) + semanticIdxName += ToStr::Get(a.semanticIndex); + + a.semanticIdxName = semanticIdxName; + } + } + else if(*fourcc == FOURCC_Aon9) // 10Level9 most likely + { + char *c = (char *)fourcc; + RDCWARN("Unknown chunk: %c%c%c%c", c[0], c[1], c[2], c[3]); + } + else if(*fourcc == FOURCC_SDBG) + { + m_DebugInfo = new SDBGChunk(fourcc); + } + else if(*fourcc == FOURCC_SPDB) + { + m_DebugInfo = new SPDBChunk(fourcc, (uint32_t)m_Instructions[0].offset); + } + } + + MakeDisassembly(); +} + +void DXBCFile::GuessResources() +{ + char buf[64] = {0}; + + for(size_t i=0; i < m_Declarations.size(); i++) + { + ASMDecl &dcl = m_Declarations[i]; + + switch(dcl.declaration) + { + case OPCODE_DCL_SAMPLER: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_SAMPLER); + RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices[0].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + + StringFormat::snprintf(buf, 63, "sampler%u", idx); + + desc.name = buf; + desc.type = ShaderInputBind::TYPE_SAMPLER; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = dcl.samplerMode == SAMPLER_MODE_COMPARISON ? 2 : 0; + desc.retType = ShaderInputBind::RETTYPE_UNKNOWN; + desc.dimension = ShaderInputBind::DIM_UNKNOWN; + desc.numSamples = 0; + + m_Resources.push_back(desc); + + break; + } + case OPCODE_DCL_RESOURCE: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_RESOURCE); + RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices[0].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + + StringFormat::snprintf(buf, 63, "texture%u", idx); + + desc.name = buf; + desc.type = ShaderInputBind::TYPE_TEXTURE; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = 0; + desc.retType = (ShaderInputBind::RetType)dcl.resType[0]; + desc.dimension = dcl.dim == RESOURCE_DIMENSION_BUFFER ? ShaderInputBind::DIM_BUFFER : + dcl.dim == RESOURCE_DIMENSION_TEXTURE1D ? ShaderInputBind::DIM_TEXTURE1D : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2D ? ShaderInputBind::DIM_TEXTURE2D : + dcl.dim == RESOURCE_DIMENSION_TEXTURE3D ? ShaderInputBind::DIM_TEXTURE3D : + dcl.dim == RESOURCE_DIMENSION_TEXTURECUBE ? ShaderInputBind::DIM_TEXTURECUBE : + dcl.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY ? ShaderInputBind::DIM_TEXTURE1DARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY ? ShaderInputBind::DIM_TEXTURE2DARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY ? ShaderInputBind::DIM_TEXTURECUBEARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DMS ? ShaderInputBind::DIM_TEXTURE2DMS : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY ? ShaderInputBind::DIM_TEXTURE2DARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY ? ShaderInputBind::DIM_TEXTURE2DMSARRAY : + ShaderInputBind::DIM_UNKNOWN; + desc.numSamples = dcl.sampleCount; + + RDCASSERT(desc.dimension != ShaderInputBind::DIM_UNKNOWN); + + m_Resources.push_back(desc); + + break; + } + case OPCODE_DCL_RESOURCE_RAW: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_RESOURCE || dcl.operand.type == TYPE_UNORDERED_ACCESS_VIEW); + RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices[0].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + + StringFormat::snprintf(buf, 63, "bytebuffer%u", idx); + + desc.name = buf; + desc.type = dcl.operand.type == TYPE_RESOURCE ? ShaderInputBind::TYPE_BYTEADDRESS : ShaderInputBind::TYPE_UAV_RWBYTEADDRESS; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = 0; + desc.retType = ShaderInputBind::RETTYPE_MIXED; + desc.dimension = ShaderInputBind::DIM_BUFFER; + desc.numSamples = 0; + + m_Resources.push_back(desc); + + break; + } + case OPCODE_DCL_RESOURCE_STRUCTURED: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_RESOURCE); + RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices[0].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + + StringFormat::snprintf(buf, 63, "structuredbuffer%u", idx); + + desc.name = buf; + desc.type = ShaderInputBind::TYPE_STRUCTURED; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = 0; + desc.retType = ShaderInputBind::RETTYPE_MIXED; + desc.dimension = ShaderInputBind::DIM_BUFFER; + desc.numSamples = dcl.stride; + + m_Resources.push_back(desc); + + break; + } + case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_UNORDERED_ACCESS_VIEW); + RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices[0].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + + StringFormat::snprintf(buf, 63, "uav%u", idx); + + desc.name = buf; + desc.type = ShaderInputBind::TYPE_UAV_RWSTRUCTURED; // doesn't seem to be anything that determines append vs consume vs rwstructured + if(dcl.hasCounter) + desc.type = ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = 0; + desc.retType = ShaderInputBind::RETTYPE_MIXED; + desc.dimension = ShaderInputBind::DIM_BUFFER; + desc.numSamples = dcl.stride; + + m_Resources.push_back(desc); + + break; + } + case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_UNORDERED_ACCESS_VIEW); + RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices[0].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + + StringFormat::snprintf(buf, 63, "uav%u", idx); + + desc.name = buf; + desc.type = ShaderInputBind::TYPE_UAV_RWTYPED; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = 0; + desc.retType = (ShaderInputBind::RetType)dcl.resType[0]; + desc.dimension = dcl.dim == RESOURCE_DIMENSION_TEXTURE1D ? ShaderInputBind::DIM_TEXTURE1D : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2D ? ShaderInputBind::DIM_TEXTURE2D : + dcl.dim == RESOURCE_DIMENSION_TEXTURE3D ? ShaderInputBind::DIM_TEXTURE3D : + dcl.dim == RESOURCE_DIMENSION_TEXTURECUBE ? ShaderInputBind::DIM_TEXTURECUBE : + dcl.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY ? ShaderInputBind::DIM_TEXTURE1DARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY ? ShaderInputBind::DIM_TEXTURE2DARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY ? ShaderInputBind::DIM_TEXTURECUBEARRAY : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DMS ? ShaderInputBind::DIM_TEXTURE2DMS : + dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY ? ShaderInputBind::DIM_TEXTURE2DARRAY : + ShaderInputBind::DIM_UNKNOWN; + desc.numSamples = (uint32_t)-1; + + m_Resources.push_back(desc); + + break; + } + case OPCODE_DCL_CONSTANT_BUFFER: + { + ShaderInputBind desc; + + RDCASSERT(dcl.operand.type == TYPE_CONSTANT_BUFFER); + RDCASSERT(dcl.operand.indices.size() == 2); + RDCASSERT(dcl.operand.indices[0].absolute && dcl.operand.indices[1].absolute); + + uint32_t idx = (uint32_t)dcl.operand.indices[0].index; + uint32_t numVecs = (uint32_t)dcl.operand.indices[1].index; + + StringFormat::snprintf(buf, 63, "cbuffer%u", idx); + + desc.name = buf; + desc.type = ShaderInputBind::TYPE_CBUFFER; + desc.bindPoint = idx; + desc.bindCount = 1; + desc.flags = 1; + desc.retType = ShaderInputBind::RETTYPE_UNKNOWN; + desc.dimension = ShaderInputBind::DIM_UNKNOWN; + desc.numSamples = 0; + + m_Resources.push_back(desc); + + CBuffer cb; + + cb.name = desc.name; + + cb.descriptor.name = cb.name; + cb.descriptor.byteSize = numVecs*4; + cb.descriptor.type = CBuffer::Descriptor::TYPE_CBUFFER; + cb.descriptor.flags = 0; + cb.descriptor.numVars = numVecs; + + cb.variables.reserve(numVecs); + + for(uint32_t v = 0; v < numVecs; v++) + { + CBufferVariable var; + + StringFormat::snprintf(buf, 63, "cb%u_v%u", desc.bindPoint, v); + + var.name = buf; + + var.descriptor.defaultValue.resize(4*sizeof(float)); + + var.descriptor.name = var.name; + var.descriptor.offset = 4*sizeof(float)*v; + var.descriptor.flags = 0; + + var.descriptor.startTexture = (uint32_t)-1; + var.descriptor.startSampler = (uint32_t)-1; + var.descriptor.numSamplers = 0; + var.descriptor.numTextures = 0; + + var.type.descriptor.bytesize = 4*sizeof(float); + var.type.descriptor.rows = 1; + var.type.descriptor.cols = 4; + var.type.descriptor.elements = 0; + var.type.descriptor.members = 0; + var.type.descriptor.type = VARTYPE_FLOAT; + var.type.descriptor.varClass = CLASS_VECTOR; + var.type.descriptor.name = TypeName(var.type.descriptor); + + cb.variables.push_back(var); + } + + m_CBuffers.resize(RDCMAX((uint32_t)m_CBuffers.size(), desc.bindPoint+1)); + m_CBuffers[desc.bindPoint] = cb; + + break; + } + } + } +} + +SDBGChunk::SDBGChunk(void *data) +{ + m_HasDebugInfo = false; + + { + uint32_t *raw = (uint32_t *)data; + + if(raw[0] != FOURCC_SDBG) + return; + + m_RawData.resize(raw[1]); + memcpy(&m_RawData[0], &raw[2], m_RawData.size()); + } + + char *dbgData = (char *)&m_RawData[0]; + + m_Header = *( (SDBGHeader *)dbgData ); + + m_ShaderFlags = m_Header.shaderFlags; + + char *dbgPostHeader = dbgData+sizeof(SDBGHeader); + + SDBGFileHeader *Files = (SDBGFileHeader *)(dbgPostHeader+m_Header.files.offset); + SDBGAsmInstruction *Instructions = (SDBGAsmInstruction *)(dbgPostHeader+m_Header.instructions.offset); + SDBGVariable *Variables = (SDBGVariable *)(dbgPostHeader+m_Header.variables.offset); + SDBGInputRegister *Inputs = (SDBGInputRegister *)(dbgPostHeader+m_Header.inputRegisters.offset); + SDBGSymbol *SymbolTable = (SDBGSymbol *)(dbgPostHeader+m_Header.symbolTable.offset); + SDBGScope *Scopes = (SDBGScope *)(dbgPostHeader+m_Header.scopes.offset); + SDBGType *Types = (SDBGType *)(dbgPostHeader+m_Header.types.offset); + int32_t *Int32DB = (int32_t *)(dbgPostHeader+m_Header.int32DBOffset); + + m_FileHeaders = vector(Files, Files + m_Header.files.count); + m_Instructions = vector(Instructions, Instructions + m_Header.instructions.count); + m_Variables = vector(Variables, Variables + m_Header.variables.count); + m_Inputs = vector(Inputs, Inputs + m_Header.inputRegisters.count); + m_SymbolTable = vector(SymbolTable, SymbolTable + m_Header.symbolTable.count); + m_Scopes = vector(Scopes, Scopes + m_Header.scopes.count); + m_Types = vector(Types, Types + m_Header.types.count); + m_Int32Database = vector(Int32DB, Int32DB + (m_Header.asciiDBOffset-m_Header.int32DBOffset)/sizeof(int32_t)); + + char *asciiDatabase = dbgPostHeader+m_Header.asciiDBOffset; + + m_CompilerSig = asciiDatabase+m_Header.compilerSigOffset; + m_Profile = asciiDatabase+m_Header.profileOffset; + m_Entry = asciiDatabase+m_Header.entryFuncOffset; + + for(size_t i=0; i < m_FileHeaders.size(); i++) + { + string filename = string(asciiDatabase+m_FileHeaders[i].filenameOffset, m_FileHeaders[i].filenameLen); + string source = string(asciiDatabase+m_FileHeaders[i].sourceOffset, m_FileHeaders[i].sourceLen); + + this->Files.push_back(make_pair(filename, source)); + } + + // successful grab of info + m_HasDebugInfo = true; +} + +void SDBGChunk::GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const +{ + if(instruction < m_Instructions.size()) + { + int32_t symID = m_Instructions[instruction].symbol; + if(symID > 0 && symID < (int32_t)m_SymbolTable.size()) + { + const SDBGSymbol &sym = m_SymbolTable[symID]; + + fileIdx = sym.fileID; + lineNum = sym.lineNum-1; + } + } +} + +string SDBGChunk::GetSymbolName(int symbolID) +{ + RDCASSERT(symbolID >= 0 && symbolID < (int)m_SymbolTable.size()); + + SDBGSymbol &sym = m_SymbolTable[symbolID]; + + return GetSymbolName(sym.symbol.offset, sym.symbol.count); +} + +string SDBGChunk::GetSymbolName(int32_t symbolOffset, int32_t symbolLength) +{ + RDCASSERT(symbolOffset < m_Header.compilerSigOffset); + RDCASSERT(symbolOffset+symbolLength <= m_Header.compilerSigOffset); + + int32_t offset = sizeof(m_Header)+m_Header.asciiDBOffset+symbolOffset; + + return string(&m_RawData[offset], symbolLength); +} + +uint32_t ReadVarLenUInt(byte *&s) +{ + // check top two bits. 0b00 (or 0b01) means we just return the byte value. + // 0b10 means we take this byte as high-end byte and next as the low-end + // in a word. (with top two bits masked off) + // 0b11 similar, but for a dword. + + if((*s & 0xC0) == 0x00 || (*s & 0xC0) == 0x40) + { + return (uint32_t)*(s++); + } + else if((*s & 0xC0) == 0x80) + { + byte first = *(s++); first &= 0x7f; + byte second = *(s++); + + return (uint32_t(first)<<8) | uint32_t(second); + } + else if((*s & 0xC0) == 0xC0) + { + byte first = *(s++); first &= 0x3f; + byte second = *(s++); + byte third = *(s++); + byte fourth = *(s++); + + return (uint32_t(first)<<24) | (uint32_t(second)<<16) | (uint32_t(third)<<8) | uint32_t(fourth); + } + else + { + // impossible + return 0; + } +} + +SPDBChunk::SPDBChunk(void *chunk, uint32_t firstInstructionOffset) +{ + m_HasDebugInfo = false; + + byte *data = NULL; + + uint32_t len; + { + uint32_t *raw = (uint32_t *)chunk; + + if(raw[0] != FOURCC_SPDB) + return; + + len = raw[1]; + + data = (byte *)&raw[2]; + } + + m_ShaderFlags = 0; + + FileHeaderPage *header = (FileHeaderPage *)data; + + if(memcmp(header->identifier, "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0", sizeof(header->identifier))) + { + RDCWARN("Unexpected SPDB type"); + return; + } + + RDCASSERT(header->PageCount*header->PageSize == len); + + const byte **pages = new const byte*[header->PageCount]; + for(uint32_t i=0; i < header->PageCount; i++) + pages[i] = &data[i*header->PageSize]; + + uint32_t rootdirCount = header->PagesForByteSize(header->RootDirSize); + uint32_t rootDirIndicesCount = header->PagesForByteSize(rootdirCount*sizeof(uint32_t)); + + PageMapping rootdirIndicesMapping(pages, header->PageSize, header->RootDirectory, rootDirIndicesCount); + const byte *rootdirIndices = rootdirIndicesMapping.Data(); + + PageMapping directoryMapping(pages, header->PageSize, (uint32_t *)rootdirIndices, rootdirCount); + const uint32_t *dirContents = (const uint32_t *)directoryMapping.Data(); + + vector streams; + + streams.resize(*dirContents); dirContents++; + + for(size_t i=0; i < streams.size(); i++) + { + streams[i].byteLength = *dirContents; dirContents++; + } + + for(size_t i=0; i < streams.size(); i++) + { + if(streams[i].byteLength == 0) continue; + + for(uint32_t p=0; p < header->PagesForByteSize(streams[i].byteLength); p++) + { + streams[i].pageIndices.push_back(*dirContents); dirContents++; + } + } + + RDCASSERT(streams.size() > 1); + + // stream 1: GUID + stream names + PageMapping guidMapping(pages, header->PageSize, &streams[1].pageIndices[0], (uint32_t)streams[1].pageIndices.size()); + GuidPageHeader *guid = (GuidPageHeader *)guidMapping.Data(); + + uint32_t *hashtable = (uint32_t *)(guid->Strings + guid->StringBytes); + + uint32_t numSetBits = hashtable[0]; hashtable++; + uint32_t maxBit = hashtable[0]; hashtable++; + uint32_t setBitsetWords = hashtable[0]; hashtable++; + uint32_t *setBitset = hashtable; hashtable += setBitsetWords; + RDCASSERT(hashtable[0] == 0); hashtable++; + + map StreamNames; + + uint32_t numset=0; + for(uint32_t i=0; i < maxBit; i++) + { + if((setBitset[ (i/32) ] & (1 << (i%32) )) != 0) + { + uint32_t strOffs = hashtable[0]; hashtable++; + uint32_t stream = hashtable[0]; hashtable++; + + char *streamName = guid->Strings + strOffs; + + StreamNames[streamName] = stream; + + numset++; + } + } + RDCASSERT(numset == numSetBits); + + for(auto it=StreamNames.begin(); it != StreamNames.end(); ++it) + { + if(!strncmp(it->first.c_str(), "/src/files/", 11)) + { + PDBStream &s = streams[it->second]; + PageMapping fileContents(pages, header->PageSize, &s.pageIndices[0], (uint32_t)s.pageIndices.size()); + + char *filename = (char *)it->first.c_str(); + filename += sizeof("/src/files/")-1; + + Files.push_back( make_pair(filename, (char *)fileContents.Data()) ); + } + } + + vector functions; + + if(streams.size() >= 5) + { + PDBStream &s = streams[4]; + PageMapping fileContents(pages, header->PageSize, &s.pageIndices[0], (uint32_t)s.pageIndices.size()); + + byte *bytes = (byte *)fileContents.Data(); + byte *start = bytes; + byte *end = bytes + s.byteLength; + + uint32_t *u32 = (uint32_t *)start; + + // seems to be accurate, but we'll just iterate to end + uint32_t numFuncs = u32[6]; + + // skip header + bytes += 57; + + while(bytes < end) + { + Function f; + memcpy(&f, bytes, 11); bytes += 11; + f.funcName = (const char *)bytes; bytes += 1+f.funcName.length(); + + while(*bytes) { f.things.push_back(*(int8_t*)bytes); bytes++; } + + functions.push_back(f); + } + } + + { + Function mainFunc; + mainFunc.funcName = "entrypoint"; + + functions.push_back(mainFunc); + } + + map Names; + + if(StreamNames.find("/names") != StreamNames.end()) + { + PDBStream &s = streams[StreamNames["/names"]]; + PageMapping namesMapping(pages, header->PageSize, &s.pageIndices[0], (uint32_t)s.pageIndices.size()); + const uint32_t *contents = (const uint32_t *)namesMapping.Data(); + + RDCASSERT(contents[0] == 0xeffeeffe && contents[1] == 1); + + uint32_t StringBytes = contents[2]; + char *Strings = (char *)&contents[3]; + + contents += 3; + + contents = (uint32_t *)((byte *)contents + StringBytes); + + uint32_t numHashes = contents[0]; contents++; + + for(uint32_t i=0; i < numHashes; i++) + { + uint32_t idx = contents[0]; contents++; + + if(idx != 0) + Names[idx] = Strings+idx; + } + } + + vector modules; + + { + PageMapping dbiMapping(pages, header->PageSize, &streams[3].pageIndices[0], (uint32_t)streams[3].pageIndices.size()); + DBIHeader *dbi = (DBIHeader *)dbiMapping.Data(); + + RDCASSERT(dbi->sig == 0xffffffff); + RDCASSERT(dbi->ver == 19990903); + + byte *cur = (byte *)(dbi+1); + byte *end = cur + dbi->gpmodiSize; + while(cur < end) + { + DBIModule *mod = (DBIModule *)cur; + cur += sizeof(DBIModule) - sizeof(string)*2; + + char *moduleName = (char *)cur; + cur += strlen(moduleName)+1; + + char *objectName = (char *)cur; + cur += strlen(objectName)+1; + + // align up to DWORD boundary + while((uintptr_t)cur & 0x3) + cur++; + + DBIModule m; + memcpy(&m, mod, sizeof(DBIModule) - sizeof(string)*2); + m.moduleName = moduleName; + m.objectName = objectName; + + modules.push_back(m); + } + RDCASSERT(cur == end); + } + + vector funcCalls; + + map FileMapping; // mapping from hash chunk to index in Files[], or -1 + + for(size_t m=0; m < modules.size(); m++) + { + if(modules[m].stream == -1) + continue; + + PDBStream &s = streams[modules[m].stream]; + PageMapping modMapping(pages, header->PageSize, &s.pageIndices[0], (uint32_t)s.pageIndices.size()); + uint32_t *data = (uint32_t *)modMapping.Data(); + + RDCASSERT(data[0] == 4); + + byte *cur = (byte *)&data[1]; + byte *end = (byte *)data + modules[m].cbSyms; + while(cur < end) + { + uint16_t *sym = (uint16_t *)cur; + + uint16_t len = sym[0]; + uint16_t type = sym[1]; len -= sizeof(uint16_t); // len includes type uint16, subtract for ease of use + + cur += sizeof(uint16_t) * 2; + + byte *contents = cur; + + if(type == 0x1110) + { + ProcHeader *header = (ProcHeader *)contents; + char *name = (char *)(header + 1); + + //RDCDEBUG("Got global procedure start %hs %x -> %x", name, header->Offset, header->Offset+header->Length); + } + else if(type == 0x113c) + { + CompilandDetails *details = (CompilandDetails *)contents; + char *compilerString = (char *)&details->CompilerSig; + + memcpy(&m_CompilandDetails, details, sizeof(CompilandDetails)-sizeof(string)); + m_CompilandDetails.CompilerSig = compilerString; + + /* + RDCDEBUG("CompilandDetails: %hs (%d.%d.%d.%d)", compilerString, + details->FrontendVersion.Major, details->FrontendVersion.Minor, + details->FrontendVersion.Build, details->FrontendVersion.QFE);*/ + + // for hlsl/fxc + //RDCASSERT(details->Language == 16 && details->Platform == 256); + } + else if(type == 0x113d) + { + // for hlsl/fxc? + //RDCASSERT(contents[0] == 0x1); + char *key = (char *)contents + 1; + while(key[0]) + { + char *value = key + strlen(key) + 1; + + //RDCDEBUG("CompilandEnv: %hs = \"%hs\"", key, value); + + if(!strcmp(key, "hlslEntry")) + { + m_Entry = value; + } + else if(!strcmp(key, "hlslTarget")) + { + m_Profile = value; + } + else if(!strcmp(key, "hlslFlags")) + { + if(value[0] == '0' && value[1] == 'x') + { + int i = 2; + + m_ShaderFlags = 0; + + while(value[i] != 0) + { + uint32_t digit = 0; + if(value[i] >= '0' && value[i] <= '9') + digit = (uint32_t)(value[i]-'0'); + if(value[i] >= 'a' && value[i] <= 'f') + digit = (uint32_t)(value[i]-'a'); + if(value[i] >= 'A' && value[i] <= 'F') + digit = (uint32_t)(value[i]-'A'); + + m_ShaderFlags <<= 4; + m_ShaderFlags |= digit; + + i++; + } + } + } + + key = value + strlen(value) + 1; + } + } + else if(type == 0x114D) + { + //RDCDEBUG("0x%04x, %d bytes", uint32_t(type), uint32_t(len)); + + FuncCallLineNumbers func; + func.fileOffs = 0; + func.baseLineNum = 0; + + byte *iterator = (byte *)contents; + byte *end = contents + len; + + uint32_t *adsf = (uint32_t *)iterator; + + //RDCDEBUG("funcdef for %hs (%x) flags??=0x%x offset/length??=0x%x", functions[adsf[2]&0xfff].funcName.c_str(), adsf[2], adsf[0], adsf[1]); + iterator += 3*sizeof(uint32_t); + + bool working = true; + uint32_t currentBytes = firstInstructionOffset; + uint32_t currentLine = 0; + uint32_t currentColStart = 1; + uint32_t currentColEnd = 100000; + + while(iterator < end) + { + uint32_t type = (uint32_t)*iterator; + FuncCallBytestreamOpcodes opcode = (FuncCallBytestreamOpcodes)type; + iterator++; + + if(opcode == PrologueEnd || + opcode == EpilogueBegin) + { + uint32_t data = ReadVarLenUInt(iterator); + //RDCDEBUG("type %02x: unk=%02x", type, data); + + if(opcode == EpilogueBegin) + { + //RDCDEBUG(" (endloc: %04x - %u [%u,%u] )", currentBytes, currentLine, currentColStart, currentColEnd); + working = false; + } + } + else if(opcode == FunctionEndNoAdvance) + { + uint32_t data = ReadVarLenUInt(iterator); + + //RDCDEBUG(" type %02x: %02x: adjust line by 4(?!) & bytes by %x", type, data, data); + + if(working) + { + InstructionLocation loc; + loc.offset = currentBytes; + loc.line = currentLine; + loc.colStart = currentColStart; + loc.colEnd = currentColEnd; + func.locations.push_back(loc); + + loc.offset = currentBytes+data; + loc.funcEnd = true; + func.locations.push_back(loc); + + //RDCDEBUG(" (loc: %04x - %u [%u,%u] )", currentBytes, currentLine, currentColStart, currentColEnd); + } + + currentBytes += data; + } + else if(opcode == AdvanceBytesAndLines) + { + uint32_t data = (uint32_t)*iterator; iterator++; + + uint32_t byteMod = (data&0xf); + uint32_t lineMod = (data>>4); + + currentBytes += byteMod; + currentLine += lineMod/2; + + //RDCDEBUG(" type %02x: %02x: adjust line by %u & bytes by %x", type, data, lineMod/2, byteMod); + + } + else if(opcode == EndOfFunction) + { + //RDCDEBUG("type %02x:", type); + + byte lenbyte = *iterator; + + uint32_t retlen = ReadVarLenUInt(iterator); + uint32_t byteAdv = ReadVarLenUInt(iterator); + + //RDCDEBUG(" retlen=%x, byteAdv=%x", retlen, byteAdv); + + currentBytes += byteAdv; + + if(working) + { + InstructionLocation loc; + loc.offset = currentBytes; + loc.line = currentLine; + loc.colStart = currentColStart; + loc.colEnd = currentColEnd; + func.locations.push_back(loc); + + loc.offset = currentBytes+retlen; + loc.funcEnd = true; + func.locations.push_back(loc); + } + + currentBytes += retlen; + } + else if(opcode == SetByteOffset) + { + currentBytes = ReadVarLenUInt(iterator); + //RDCDEBUG(" type %02x: start at byte offset %x", type, currentBytes); + } + else if(opcode == AdvanceBytes) + { + uint32_t offs = ReadVarLenUInt(iterator); + + currentBytes += offs; + + //RDCDEBUG(" type %02x: advance %x bytes", type, offs); + + if(working) + { + InstructionLocation loc; + loc.offset = currentBytes; + loc.line = currentLine; + loc.colStart = currentColStart; + loc.colEnd = currentColEnd; + func.locations.push_back(loc); + + //RDCDEBUG(" (loc: %04x - %u [%u,%u] )", currentBytes, currentLine, currentColStart, currentColEnd); + } + } + else if(opcode == AdvanceLines) + { + uint32_t linesAdv = ReadVarLenUInt(iterator); + + if(linesAdv&0x1) + currentLine -= (linesAdv/2); + else + currentLine += (linesAdv/2); + + //RDCDEBUG(" type %02x: advance %u (%u) lines", type, linesAdv/2, linesAdv); + } + else if(opcode == ColumnStart) + { + currentColStart = ReadVarLenUInt(iterator); + //RDCDEBUG(" type %02x: col < %u", type, currentColStart); + } + else if(opcode == ColumnEnd) + { + currentColEnd = ReadVarLenUInt(iterator); + //RDCDEBUG(" type %02x: col > %u", type, currentColEnd); + } + else if(opcode == EndStream) + { + while(*iterator == 0 && iterator < end) iterator++; + RDCASSERT(iterator == end); + } + else + { + RDCLOG("Unrecognised: %02x", type); + break; + } + } + + if(func.locations.size() == 1) + { + // not sure what this means, but it seems to just be intended to match + // one instruction offset and we don't have an 0xc to 'cap' things off. + // just insert a dummy location at the same file line but with a slightly + // higher offset so we have a valid range to match against + auto loc = func.locations[0]; + loc.offset++; + func.locations.push_back(loc); + } + + RDCASSERT(func.locations.size() > 1); + + funcCalls.push_back(func); + + //RDCDEBUG("Lost %d bytes after we stopped processing", end - iterator); + } + else if(type == 0x113E) + { + // not currently used + /* + //RDCDEBUG("0x%04x, %d bytes", uint32_t(type), uint32_t(len)); + + RegisterVariableAssign *var = (RegisterVariableAssign *)contents; + + string funcName = "undefined"; + + if((size_t)(var->func&0xfff) < functions.size()) + funcName = functions[var->func&0xfff].funcName; + + //RDCDEBUG(" in %hs (%x) flags??=%04x, %hs:", funcName.c_str(), var->func, var->unkflags, var->name); + + byte *afterName = (byte *)var->name + (strlen(var->name) + 1); + + byte *end = contents + len; + + // seems to always be 0s + while(afterName < end) + { + RDCASSERT(*afterName == 0); + afterName++; + } + */ + } + else if(type == 0x1150) + { + // not currently used + /* + RDCASSERT(len %4 == 0); + //RDCDEBUG("0x%04x, %d bytes", uint32_t(type), uint32_t(len)); + + RegisterVariableAssignComponent *comp = (RegisterVariableAssignComponent *)contents; + + OperandType t = comp->Type(); + const char *type = ""; + switch(t) + { + case TYPE_TEMP: type = "r"; break; + case TYPE_INPUT: type = "v"; break; + case TYPE_OUTPUT: type = "o"; break; + case TYPE_INDEXABLE_TEMP: type = "x"; break; + case TYPE_INPUT_THREAD_ID: type = "globalIdx"; break; + case TYPE_INPUT_THREAD_ID_IN_GROUP: type = "localIdx"; break; + case TYPE_INPUT_THREAD_GROUP_ID: type = "groupIdx"; break; + default: break; + } + + uint16_t destComp = comp->destComp; + if(len == 24) + destComp = comp->unkE; + if(len > 24) + { + uint16_t *end = (uint16_t *)(contents + len); + + destComp = end[-1]; + } + + char comps[] = "xyzw"; + + //RDCDEBUG("%hs%d.%c (%x, %x) <- .%c @ 0x%x", type, (destComp)>>4, comps[(destComp&0xf)>>2], comp->destComp, comp->unkE, comps[(comp->srcComp&0xf)>>2], comp->instrOffset); + + //RDCDEBUG(" A:%04x B:%04x C:%04x D:%04x", comp->unkA, comp->unkB, comp->unkC, comp->unkD); + //RDCDEBUG(" E(d):%04x", comp->unkE); + + uint32_t *extra = (uint32_t *)(comp+1); + + for(uint16_t l=20; l < len; l+=4) + { + //RDCDEBUG(" %08x", extra[0]); + extra++; + } + */ + } + else if(type == 0x114E) + { + RDCASSERT(len == 0); + //RDCDEBUG("0x%04x, %d bytes", uint32_t(type), uint32_t(len)); + } + else if(type == 0x0006) + { + //RDCDEBUG("end"); + } + else + { + //RDCDEBUG("(unexpected?) 0x%04x", uint32_t(type)); + } + + cur += len; + } + RDCASSERT(cur == end); + + end = cur + modules[m].cbLines; + + while(cur < end) + { + uint16_t *type = (uint16_t *)cur; + + if(*type == 0xF4) // hash + { + uint32_t *len = (uint32_t *)(type+2); + + cur = (byte *)(len + 1); + + byte *start = cur; + while(cur < start + *len) + { + uint32_t *hashData = (uint32_t *)cur; cur += sizeof(uint32_t); + uint16_t *unknown = (uint16_t *)cur; cur += sizeof(uint16_t); + + uint32_t chunkOffs = uint32_t((byte *)hashData - start); + + uint32_t nameoffset = hashData[0]; + + // if this is 0, we don't have a hash + if(*unknown) + { + byte hash[16]; + memcpy(hash, cur, sizeof(hash)); + cur += sizeof(hash); + + int32_t fileIdx = -1; + + for(size_t i=0; i < Files.size(); i++) + { + if(!_stricmp(Files[i].first.c_str(), Names[nameoffset].c_str())) + { + fileIdx = (int32_t)i; + break; + } + } + + FileMapping[chunkOffs] = fileIdx; + } + else + { + // this is a 'virtual' file. Create a source file that we can map lines to just for something, + // as we won't be able to reliably get the real source lines back. The PDB lies convincingly about the + // source according to #line + if(Names.find(nameoffset) != Names.end()) + { + string name = Names[nameoffset]; + Files.push_back( make_pair(name, "") ); + + FileMapping[chunkOffs] = (int32_t)Files.size()-1; + } + else + { + RDCERR("Processing SPDB chunk, encountered nameoffset %d that doesn't correspond to any name.", nameoffset); + + FileMapping[chunkOffs] = -1; + } + } + + unknown = (uint16_t *)cur; cur += sizeof(uint16_t); + // another unknown + } + RDCASSERT(cur == start + *len); + } + else if(*type == 0xF2) + { + uint32_t *len = (uint32_t *)(type+2); + + cur = (byte *)(len + 1); + + byte *start = cur; + + LineNumbersHeader *hdr = (LineNumbersHeader *)cur; + + cur = (byte *)(hdr + 1); + + bool hasExtra = (hdr->flags & 0x1); + + while(cur < start + *len) + { + FileLineNumbers *file = (FileLineNumbers *)cur; + cur = (byte *)(file + 1); + + uint32_t *data = (uint32_t *)cur; + + cur += (sizeof(uint32_t) + sizeof(uint32_t)) * file->numLines; + if(hasExtra) + cur += (sizeof(uint16_t) + sizeof(uint16_t)) * file->numLines; + + int32_t fileIdx = -1; + + if(FileMapping.find(file->fileIdx) == FileMapping.end()) + { + RDCERR("SPDB chunk - line numbers file references index %u not encountered in file mapping", file->fileIdx); + } + else + { + fileIdx = FileMapping[file->fileIdx]; + } + + for(uint32_t l=0; l < file->numLines; l++) + { + uint32_t offs = data[0]; + uint32_t lineNum = data[1]&0x00fffff; + uint32_t unknown = data[1]>>24; + + data += 2; + + m_LineNumbers[offs] = make_pair(fileIdx, lineNum); + + //RDCDEBUG("Offset %x is line %d", offs, lineNum); + } + + uint16_t *extraData = (uint16_t *)data; + + for(uint32_t l=0; l < file->numLines; l++) + { + uint16_t unkA = extraData[0]; + uint16_t unkB = extraData[1]; + + extraData += 2; + } + + RDCASSERT((byte *)extraData == cur); + } + RDCASSERT(cur == start + *len); + } + else if(*type == 0xF6) + { + uint32_t *len = (uint32_t *)(type+2); + + cur = (byte *)(len + 1); + + uint32_t *calls = (uint32_t *)cur; + uint32_t *end = (uint32_t *)(cur + *len); + + // 0 seems to indicate no files, 1 indicates files but we don't need + // to care as we can just handle this below. + //RDCDEBUG("start: %x", calls[0]); + calls++; + + int idx = 0; + while(calls < end) + { + // some kind of control bytes? they have n file mappings following but I'm not sure what + // they mean + if(calls[0] <= 0xf) + { + calls += 1 + calls[0]; + } + else + { + // function call - 3 uint32s: (function idx | 0x1000, FileMapping idx, line # of start of function) + + //RDCDEBUG("Call to %hs(%x) - file %x, line %d", functions[calls[0]&0xfff].funcName.c_str(), calls[0], calls[1], calls[2]); + + funcCalls[idx].fileOffs = calls[1]; + funcCalls[idx].baseLineNum = calls[2]; + + idx++; + + calls += 3; + } + } + + cur += *len; + } + else + { + break; + } + } + } + + for(size_t i=0; i < funcCalls.size(); i++) + { + RDCASSERT(funcCalls[i].locations.size() > 1); + + if(funcCalls[i].locations.empty() || funcCalls[i].locations.size() == 1) + { + RDCWARN("Skipping patching function call with %d locations", funcCalls[i].locations.size()); + continue; + } + + RDCASSERT(FileMapping.find(funcCalls[i].fileOffs) != FileMapping.end()); + + if(FileMapping.find(funcCalls[i].fileOffs) == FileMapping.end()) + { + RDCWARN("Got function call patch with fileoffs %x - skipping", funcCalls[i].fileOffs); + continue; + } + + //RDCDEBUG("Function call %d", i); + + for(size_t j=0; j < funcCalls[i].locations.size()-1; j++) + { + auto &loc = funcCalls[i].locations[j]; + auto &locNext = funcCalls[i].locations[j+1]; + + // don't apply between function end and next section (if there is one) + if(loc.funcEnd) + continue; + + int nPatched = 0; + + for(auto it=m_LineNumbers.begin(); it != m_LineNumbers.end(); ++it) + { + if(it->first >= loc.offset && it->first < locNext.offset) + { + int32_t fileIdx = FileMapping[funcCalls[i].fileOffs]; + + /* + RDCDEBUG("Patching offset %x between [%x,%x] from (%d,%u) to (%d,%u [%u->%u])", + it->first, loc.offset, locNext.offset, + it->second.first, it->second.second, + fileIdx, loc.line+funcCalls[i].baseLineNum, + loc.colStart, loc.colEnd); + */ + + it->second.first = fileIdx; + it->second.second = loc.line+funcCalls[i].baseLineNum; + nPatched++; + } + } + + /* + if(nPatched == 0) + RDCDEBUG("Can't find anything between offsets %x,%x as desired", loc.offset, locNext.offset);*/ + } + } + + delete[] pages; + + m_HasDebugInfo = true; +} + +void SPDBChunk::GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const +{ + for(auto it=m_LineNumbers.begin(); it != m_LineNumbers.end(); ++it) + { + if((uintptr_t)it->first <= offset) + { + fileIdx = it->second.first; + lineNum = it->second.second-1; // 0-indexed + } + else + { + return; + } + } +} + +}; // namespace DXBC \ No newline at end of file diff --git a/renderdoc/driver/d3d11/shaders/dxbc_inspect.h b/renderdoc/driver/d3d11/shaders/dxbc_inspect.h new file mode 100644 index 0000000000..f545649d4a --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_inspect.h @@ -0,0 +1,410 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include +#include +#include +using std::vector; +using std::pair; +using std::string; +using std::map; + +#pragma once + +#include "common/common.h" +#include "replay/renderdoc.h" + +#include "dxbc_disassemble.h" + +enum D3D11_SHADER_VERSION_TYPE; + +// many thanks to winehq for information of format of RDEF, STAT and SIGN chunks: +// http://source.winehq.org/git/wine.git/blob/HEAD:/dlls/d3dcompiler_43/reflection.c +namespace DXBC +{ + +enum VariableType +{ + VARTYPE_VOID = 0, + VARTYPE_BOOL, + VARTYPE_INT, + VARTYPE_FLOAT, + VARTYPE_STRING, + VARTYPE_TEXTURE, + VARTYPE_TEXTURE1D, + VARTYPE_TEXTURE2D, + VARTYPE_TEXTURE3D, + VARTYPE_TEXTURECUBE, + VARTYPE_SAMPLER, + VARTYPE_SAMPLER1D, + VARTYPE_SAMPLER2D, + VARTYPE_SAMPLER3D, + VARTYPE_SAMPLERCUBE, + VARTYPE_PIXELSHADER, + VARTYPE_VERTEXSHADER, + VARTYPE_PIXELFRAGMENT, + VARTYPE_VERTEXFRAGMENT, + VARTYPE_UINT, + VARTYPE_UINT8, + VARTYPE_GEOMETRYSHADER, + VARTYPE_RASTERIZER, + VARTYPE_DEPTHSTENCIL, + VARTYPE_BLEND, + VARTYPE_BUFFER, + VARTYPE_CBUFFER, + VARTYPE_TBUFFER, + VARTYPE_TEXTURE1DARRAY, + VARTYPE_TEXTURE2DARRAY, + VARTYPE_RENDERTARGETVIEW, + VARTYPE_DEPTHSTENCILVIEW, + VARTYPE_TEXTURE2DMS, + VARTYPE_TEXTURE2DMSARRAY, + VARTYPE_TEXTURECUBEARRAY, + VARTYPE_HULLSHADER, + VARTYPE_DOMAINSHADER, + VARTYPE_INTERFACE_POINTER, + VARTYPE_COMPUTESHADER, + VARTYPE_DOUBLE, + VARTYPE_RWTEXTURE1D, + VARTYPE_RWTEXTURE1DARRAY, + VARTYPE_RWTEXTURE2D, + VARTYPE_RWTEXTURE2DARRAY, + VARTYPE_RWTEXTURE3D, + VARTYPE_RWBUFFER, + VARTYPE_BYTEADDRESS_BUFFER, + VARTYPE_RWBYTEADDRESS_BUFFER, + VARTYPE_STRUCTURED_BUFFER, + VARTYPE_RWSTRUCTURED_BUFFER, + VARTYPE_APPEND_STRUCTURED_BUFFER, + VARTYPE_CONSUME_STRUCTURED_BUFFER, +}; + +struct ShaderInputBind +{ + string name; + + enum InputType + { + TYPE_CBUFFER = 0, + TYPE_TBUFFER, + TYPE_TEXTURE, + TYPE_SAMPLER, + TYPE_UAV_RWTYPED, + TYPE_STRUCTURED, + TYPE_UAV_RWSTRUCTURED, + TYPE_BYTEADDRESS, + TYPE_UAV_RWBYTEADDRESS, + TYPE_UAV_APPEND_STRUCTURED, + TYPE_UAV_CONSUME_STRUCTURED, + TYPE_UAV_RWSTRUCTURED_WITH_COUNTER, + } type; + + uint32_t bindPoint; + uint32_t bindCount; + + uint32_t flags; + + enum RetType + { + RETTYPE_UNKNOWN = 0, + RETTYPE_UNORM = 1, + RETTYPE_SNORM, + RETTYPE_SINT, + RETTYPE_UINT, + RETTYPE_FLOAT, + RETTYPE_MIXED, + RETTYPE_DOUBLE, + RETTYPE_CONTINUED, + } retType; + + enum Dimension + { + DIM_UNKNOWN = 0, + DIM_BUFFER, + DIM_TEXTURE1D, + DIM_TEXTURE1DARRAY, + DIM_TEXTURE2D, + DIM_TEXTURE2DARRAY, + DIM_TEXTURE2DMS, + DIM_TEXTURE2DMSARRAY, + DIM_TEXTURE3D, + DIM_TEXTURECUBE, + DIM_TEXTURECUBEARRAY, + DIM_BUFFEREX, + } dimension; + + uint32_t numSamples; +}; + + +///////////////////////////////////////////////////////////////////////// +// the below classes basically mimics the existing reflection interface. +// +// essentially all information comes from the wine project. +///////////////////////////////////////////////////////////////////////// + +// this struct is the whole STAT chunk, since it's just a series of fixed numbers +// preceded by FourCC and chunk length as usual +// +// This should correspond to D3D11_SHADER_DESC, some elements aren't identified yet. +struct ShaderStatistics +{ + uint32_t instructionCount; + uint32_t tempRegisterCount; + uint32_t unknown_a; + uint32_t dclCount; + uint32_t fltInstructionCount; + uint32_t intInstructionCount; + uint32_t uintInstructionCount; + uint32_t staticFlowControlCount; + uint32_t dynamicFlowControlCount; + uint32_t unknown_b; + uint32_t tempArrayCount; + uint32_t arrayInstructionCount; + uint32_t cutInstructionCount; + uint32_t emitInstructionCount; + uint32_t sampleTexCount; + uint32_t loadTexCount; + uint32_t cmpTexCount; + uint32_t sampleBiasTexCount; + uint32_t sampleGradTexCount; + uint32_t movInstructionCount; + uint32_t unknown_c; + uint32_t convInstructionCount; + uint32_t unknown_d; + uint32_t inputPrimCount; + uint32_t gsOutputTopology; + uint32_t gsMaxOutputVtxCount; + uint32_t unknown_e[3]; + + // below won't exist for dx10 shaders. They'll be filled with 0 + + uint32_t unknown_f; + uint32_t cControlPoints; + uint32_t hsOutputPrim; + uint32_t hsPartitioning; + uint32_t tessellatorDomain; + uint32_t unknown_g[3]; + + enum Version + { + STATS_UNKNOWN = 0, + STATS_DX10, + STATS_DX11, + } version; +}; + +struct CBufferVariable; + +enum VariableClass +{ + CLASS_SCALAR = 0, + CLASS_VECTOR, + CLASS_MATRIX_ROWS, + CLASS_MATRIX_COLUMNS, + CLASS_OBJECT, + CLASS_STRUCT, + CLASS_INTERFACE_CLASS, + CLASS_INTERFACE_POINTER, +}; + +struct CBufferVariableType +{ + struct Descriptor + { + VariableClass varClass; + VariableType type; + uint32_t rows; + uint32_t cols; + uint32_t elements; + uint32_t members; + uint32_t bytesize; + string name; + } descriptor; + + // if a struct, these are variables for each member (this can obviously nest). Not all + // elements of the nested member descriptor are valid, as this might not be in a cbuffer, + // but might be a loose structure + vector members; +}; + +struct CBufferVariable +{ + string name; + + struct + { + string name; + uint32_t offset; // offset in parent (cbuffer or nested struct) + uint32_t flags; + std::vector defaultValue; + uint32_t startTexture; // first texture + uint32_t numTextures; + uint32_t startSampler; // first sampler + uint32_t numSamplers; + } descriptor; + + // type details of this variable + CBufferVariableType type; +}; + +struct CBuffer +{ + string name; + + struct Descriptor + { + string name; + + enum Type + { + TYPE_CBUFFER = 0, + TYPE_TBUFFER, + TYPE_INTERFACE_POINTERS, + TYPE_RESOURCE_BIND_INFO, + } type; + + uint32_t numVars; + uint32_t byteSize; + uint32_t flags; + } descriptor; + + std::vector variables; +}; + +struct RDEFHeader; + +class DXBCDebugChunk +{ + public: + virtual ~DXBCDebugChunk() {} + virtual string GetCompilerSig() const = 0; + virtual string GetEntryFunction() const = 0; + virtual string GetShaderProfile() const = 0; + + virtual uint32_t GetShaderCompileFlags() const = 0; + + vector< pair > Files; // + + virtual void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const = 0; + + virtual DXBCDebugChunk *Clone() const = 0; +}; + +// declare one of these and pass in your shader bytecode, then inspect +// the members that are populated with the shader information. +class DXBCFile +{ + public: + DXBCFile(const void *ByteCode, size_t ByteCodeLength); + ~DXBCFile() { SAFE_DELETE(m_DebugInfo); } + + DXBCFile(const DXBCFile &o) + { + *this = o; + } + + DXBCFile &operator =(const DXBCFile &o) + { + m_Type = o.m_Type; + m_Version = o.m_Version; + + m_ShaderStats = o.m_ShaderStats; + + m_DebugInfo = NULL; + if(o.m_DebugInfo) + m_DebugInfo = o.m_DebugInfo->Clone(); + + m_Resources = o.m_Resources; + + m_CBuffers = o.m_CBuffers; + + m_Interfaces = o.m_Interfaces; + + m_Immediate = o.m_Immediate; + + m_ResourceBinds = o.m_ResourceBinds; + + m_InputSig = o.m_InputSig; + m_OutputSig = o.m_OutputSig; + m_PatchConstantSig = o.m_PatchConstantSig; + m_Declarations = o.m_Declarations; + m_Instructions = o.m_Instructions; + m_Disassembly = o.m_Disassembly; + + m_HexDump = o.m_HexDump; + + m_ShaderBlob = o.m_ShaderBlob; + + return *this; + } + + D3D11_SHADER_VERSION_TYPE m_Type; + struct { uint32_t Major, Minor; } m_Version; + + ShaderStatistics m_ShaderStats; + DXBCDebugChunk *m_DebugInfo; + + vector m_Immediate; + + vector m_Resources; + + vector m_CBuffers; + + CBuffer m_Interfaces; + + map m_ResourceBinds; + + vector m_InputSig; + vector m_OutputSig; + vector m_PatchConstantSig; + + vector m_Declarations; // declarations of inputs, outputs, constant buffers, temp registers etc. + vector m_Instructions; + string m_Disassembly; + + vector m_HexDump; + + vector m_ShaderBlob; + + size_t NumOperands(OpcodeType op); + private: + void DisassembleHexDump(); + void MakeDisassembly(); + void GuessResources(); + + // these functions modify tokenStream pointer to point after the item + bool ExtractOperation(uint32_t *&tokenStream, ASMOperation &op); // returns false if not an operation (ie. it's a declaration) + bool ExtractDecl(uint32_t *&tokenStream, ASMDecl &decl); // as above + bool ExtractOperand(uint32_t *&tokenStream, ASMOperand &oper); + + bool IsDeclaration(OpcodeType op); + + CBufferVariableType ParseRDEFType(RDEFHeader *h, char *chunk, uint32_t offset); + map m_Variables; +}; + +}; // namespace DXBC \ No newline at end of file diff --git a/renderdoc/driver/d3d11/shaders/dxbc_sdbg.h b/renderdoc/driver/d3d11/shaders/dxbc_sdbg.h new file mode 100644 index 0000000000..5b516d95e0 --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_sdbg.h @@ -0,0 +1,279 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include +#include +#include +using std::vector; +using std::pair; +using std::string; +using std::map; + +#pragma once + +#include "dxbc_disassemble.h" + +namespace DXBC +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Partial (and by that I mean very partial) spec of the SDBG debug information chunk in shader bytecode. +// +// Very much work in progress, feel free to contribute if you figure out what some of the fields are or have +// a correction. +// +// I've documented assumptions/guesses/suppositions where relevant. There are plenty of them. +// +// Current completely understood structures: +// * SDBGHeader +// * SDBGFileHeader +// * SDBGSymbol +// * SDBGType +// * SDBGScope +// +// Structures that are understood but with unknown elements: +// * SDBGAsmInstruction +// +// Structures that are partly understood, but their place/purpose is still vague: +// * SDBGVariable +// * SDBGInputRegister +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +struct CountOffset +{ + int32_t count; + int32_t offset; +}; + +// Completely understood +struct SDBGHeader +{ + int32_t version; // Always 0x00000054 it seems. Probably a version number, might be some other ID + + int32_t compilerSigOffset; // offset from asciiOffset at the end of this structure. + int32_t entryFuncOffset; // offset from asciiOffset at the end of this structure. + int32_t profileOffset; // offset from asciiOffset at the end of this structure. + + uint32_t shaderFlags; // Shader flags - same as from reflection. + + // All offsets are after this header. + CountOffset files; // total unique files opened and used via #include + CountOffset instructions; // assembly instructions + CountOffset variables; // Looks to be the variables (one per component) used in the shader + CountOffset inputRegisters; // This lists which bits of which inputs are used - e.g. the components in input + // signature elements and cbuffers. + CountOffset symbolTable; // This is a symbol table definitely, also includes 'virtual' symbols to match + // up ASM instructions to lines. + CountOffset scopes; // These are scopes - like for structures/functions. Also Globals/Locals lists of variables + // in scope for reference in ASM instructions + CountOffset types; // Type specifications + + int32_t int32DBOffset; // offset after this header. Same principle as ASCII db, but for int32s + + int32_t asciiDBOffset; // offset after this header to the ASCII data. This is a general "ascii database section" + // or similar because it has file sources, generated symbol names, etc. Hefty deduping goes + // on here, so if the hlsl source is included then offsets for symbols etc in that source + // point inside that source - only generated names like "structure::member" that don't exist + // in the source are duplicated after. Same goes for hlsl include file names, they're always + // obviously in the source somewhere. +}; + + + +// Completely understood +// one per included file (unique). First always exists and is the hlsl file passed to the compiler +struct SDBGFileHeader +{ + int32_t filenameOffset; // offset into the ascii Database where the filename sits. + int32_t filenameLen; // filename path. Absolute for root file, relative for other headers + + int32_t sourceOffset; // offset into the ascii Database where this file's source lives + int32_t sourceLen; // bytes in source file. Valid for all file headers +}; + +// Partly understood, many unknown/guessed elements. Completely understood how this fits in in the overall structure +// Details of each assembly instruction +struct SDBGAsmInstruction +{ + int32_t instructionNum; + + OpcodeType opCode; + + int32_t unknown_a[2]; + int32_t destRegister; + int32_t unknown_b; + + int32_t destXMask; // 00 if writing to this component in dest register, -1 if not writing + int32_t destYMask; // 01 " " " " + int32_t destZMask; // 02 " " " " + int32_t destWMask; // 03 " " " " + + struct Component + { + int32_t varID; // matches SDBGVariable below + float lowBounds[2]; // what's this? defaults 0.0 to -QNAN. Some kind of bound. + float highBounds[2]; // what's this? -0.0 to QNAN. Some kind of bound. + float minBound; // min value this components's dest can be + float maxBound; // max value " " " + int32_t unknown_a[2]; + } component[4]; + + int32_t unknown_c[9]; + + // I don't know what this is, but it's 9 int32s and 4 of them, so sounds like + // something that's per-component + struct Something + { + int32_t unknown[9]; + } somethings[4]; + + int32_t unknown_d[2]; + + int32_t symbol; // symbol, usually virtual I think, that links this instruction + // to somewhere in hlsl - e.g. a line number and such + + int32_t callstackDepth; // 0-indexed current level of the callstack. ie. 0 is in the main function, 1 is in a sub-function, etc etc. + + CountOffset scopes; // The scopeIDs that show the call trace in each instruction (or rather, where this instruction takes place). + // it has several elements: N Locals entries, with different locals for different scopes or branches + // (this doesn't quite make sense yet. Some Locals lists can contain variables from if AND else branches, + // or include variables that have gone out of scope). Then it contains a single element pointing to the current + // function, then a globals list showing all variables and return-value functions in global scope at this point. + CountOffset varTypes; // The Type IDs of variables involved in this instruction. Possibly in source,source,dest order but + // maybe not. +}; + +// Mostly understood, a couple of unknown elements and/or not sure how it fits together in the grand scheme +struct SDBGVariable +{ + int32_t symbolID; // Symbol this assignment depends on + VariableType type; + int32_t unknown[2]; + int32_t typeID; // refers to SDBGType. -1 if a constant + union + { + int32_t component; // x=0,y=1,z=2,w=3 + float value; // const value + }; +}; + +// Mostly understood, a couple of unknown elements and/or not sure how it fits together in the grand scheme +struct SDBGInputRegister +{ + int32_t varID; + int32_t type; // 2 = from cbuffer, 0 = from input signature, 6 = from texture, 7 = from sampler + int32_t cbuffer_register; // -1 if input signature + int32_t cbuffer_packoffset; // index of input signature + int32_t component; // x=0,y=1,z=2,w=3 + int32_t initValue; // I think this is a value? -1 or some value. Or maybe an index. +}; + +// Completely understood +struct SDBGSymbol +{ + int32_t fileID; // index into SDBGFileHeader array + int32_t lineNum; + int32_t characterNum; // not column, so after a tab would just be 1. + CountOffset symbol; // offset can be 0 for 'virtual' symbols +}; + +// Almost entirely understood, there is sometimes redundancy in that the same scope appears with +// different tree entries that overlap and are supersets. Seems like MAYBE each new instruction it +// shows all the variables in scope up to that point, but the scope tree is inconsistent e.g. in what +// ends up in Globals. Still useful for resolving types though +struct SDBGScope +{ + int32_t type; // what kind of type I have no idea. 0 = Globals, 1 = Locals, 3 = Structure, 4 = Function + int32_t symbolNameOffset; // offset from start of ascii Database + int32_t symbolNameLength; + CountOffset scopeTree; +}; + +// Completely understood +struct SDBGType +{ + int32_t symbolID; + int32_t isFunction; // 0 / 1 + int32_t type; // 0 == scalar, 1 == vector, 3 == matrix, 4 == texture/sampler + int32_t typeNumRows; // number of floats in the height of the base type (mostly for matrices) + int32_t typeNumColumns; // number of floats in the width of the base type. 0 for functions or structure types + int32_t scopeID; // if type is a complex type (including function return type), the scope of this type. + int32_t arrayDimension; // 0, 1, 2, ... + int32_t arrayLenOffset; // offset into the int32 database. Contains an array length for each dimension + int32_t stridesOffset; // offset into the int32 database. Contains the stride for that level, for each dimension. + // so with array[a][b][c] it has b*c*baseSize, then c*baseSize then baseSize + int32_t numFloats; // number of floats in this type (or maybe 32bit words, not sure). + int32_t varID; // Variable ID, or -1 if this variable isn't used. +}; + + +// SDBG chunk gets its own class since it's so complex. Deliberately fairly leaky too +// since the data + use is a bit unclear still +class SDBGChunk : public DXBCDebugChunk +{ + public: + SDBGChunk(void *data); + + string GetCompilerSig() const { return m_CompilerSig; } + string GetEntryFunction() const { return m_Entry; } + string GetShaderProfile() const { return m_Profile; } + + uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; } + + void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const; + + DXBCDebugChunk *Clone() const { return new SDBGChunk(*this); } + private: + bool m_HasDebugInfo; + + string GetSymbolName(int symbolID); + string GetSymbolName(int32_t symbolOffset, int32_t symbolLength); + + vector m_Instructions; + vector m_Variables; + vector m_Inputs; + vector m_SymbolTable; + vector m_Scopes; + vector m_Types; + vector m_Int32Database; + + uint32_t m_ShaderFlags; + + string m_CompilerSig; + string m_Entry; + string m_Profile; + + SDBGChunk(); + + // these don't need to be exposed, a more processed and friendly + // version is exposed + SDBGHeader m_Header; + vector m_FileHeaders; + + vector m_RawData; +}; + +}; diff --git a/renderdoc/driver/d3d11/shaders/dxbc_spdb.h b/renderdoc/driver/d3d11/shaders/dxbc_spdb.h new file mode 100644 index 0000000000..2ba317a388 --- /dev/null +++ b/renderdoc/driver/d3d11/shaders/dxbc_spdb.h @@ -0,0 +1,308 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include + +#include +#include +#include +#include +using std::vector; +using std::pair; +using std::string; +using std::map; + +#pragma once + +#include "dxbc_disassemble.h" + +namespace DXBC +{ + +class PageMapping +{ + public: + PageMapping(const byte **pages, uint32_t PageSize, uint32_t *indices, uint32_t numIndices) + { + direct = NULL; + + if(numIndices == 1) + { + direct = pages[indices[0]]; + } + else + { + contiguous.resize(numIndices*PageSize); + for(uint32_t i=0; i < numIndices; i++) + memcpy(&contiguous[i*PageSize], pages[indices[i]], PageSize); + } + } + + const byte *Data() + { if(direct) return direct; return &contiguous[0]; } + private: + const byte *direct; + vector contiguous; +}; + +struct FileHeaderPage +{ + char identifier[32]; + uint32_t PageSize; + uint32_t FreePageMapIdx; + uint32_t PageCount; + uint32_t RootDirSize; + uint32_t zero; + uint32_t RootDirectory[73]; + + uint32_t PagesForByteSize(uint32_t ByteSize) + { + // align up ByteSize to PageSize + return (ByteSize + PageSize - 1) / PageSize; + } +}; + +struct GuidPageHeader +{ + uint32_t Version; + uint32_t Signature; + uint32_t Age; + GUID Guid; + uint32_t StringBytes; + char Strings[1]; +}; + +struct DBIHeader +{ + uint32_t sig; + int32_t ver; + int32_t age; + int16_t gssymStream; + uint16_t vers; + int16_t pssymStream; + uint16_t pdbver; + int16_t symrecStream; + uint16_t pdbver2; + int32_t gpmodiSize; + int32_t secconSize; + int32_t secmapSize; + int32_t filinfSize; + int32_t tsmapSize; + int32_t mfcIndex; + int32_t dbghdrSize; + int32_t ecinfoSize; + uint16_t flags; + uint16_t machine; + int32_t reserved; +}; + +struct DBIModule +{ + int32_t opened; + + // seccon + int16_t section; + int16_t pad1; + int32_t offset; + int32_t size; + uint32_t flags_; + int16_t module; + int16_t pad2; + uint32_t dataCrc; + uint32_t relocCrc; + + uint16_t flags; + int16_t stream; + int32_t cbSyms; + int32_t cbOldLines; + int32_t cbLines; + int16_t files; + int16_t pad; + uint32_t offsets; + int32_t niSource; + int32_t niCompiler; + + // invalid when this is read in-place! + string moduleName; + string objectName; +}; + +struct CompilandDetails +{ + uint8_t Language; + uint8_t Flags; + uint16_t Unknown; + uint16_t Platform; + + struct + { + uint16_t Major, Minor, Build, QFE; + } FrontendVersion, BackendVersion; + + // invalid when this is read in-place! + string CompilerSig; +}; + +struct LineNumbersHeader +{ + uint32_t offset; + uint16_t sec; + uint16_t flags; + uint32_t cod; +}; + +struct FileLineNumbers +{ + uint32_t fileIdx; // index = byte offset in hash chunk + uint32_t numLines; + uint32_t size; +}; + +#pragma pack(push,1) +struct ProcHeader +{ + uint32_t Parent; + uint32_t End; + uint32_t Next; + uint32_t Length; + uint32_t DebugStart; + uint32_t DebugEnd; + uint32_t Type; + uint32_t Offset; + byte Unknown[3]; +}; +#pragma pack(pop) + +struct InstructionLocation +{ + InstructionLocation() : funcEnd(false), offset(0), line(0), colStart(0), colEnd(0) {} + bool funcEnd; + uint32_t offset; + uint32_t line; + uint32_t colStart; + uint32_t colEnd; +}; + +struct FuncCallLineNumbers +{ + uint32_t fileOffs; + uint32_t baseLineNum; + vector locations; +}; + +struct Function +{ + uint8_t unkA; + uint32_t unkB; + uint16_t unkC; + uint16_t unkD; + uint16_t unkE; + string funcName; + vector things; +}; + +enum FuncCallBytestreamOpcodes +{ + EndStream = 0x0, + + SetByteOffset = 0x1, + // 0x2 + AdvanceBytes = 0x3, + + FunctionEndNoAdvance = 0x4, + // 0x5 + AdvanceLines = 0x6, + + PrologueEnd = 0x7, + EpilogueBegin = 0x8, + + ColumnStart = 0x9, + // 0xa + + AdvanceBytesAndLines = 0xb, + EndOfFunction = 0xc, + + ColumnEnd = 0xd, +}; + +#pragma pack(push,1) +struct RegisterVariableAssign +{ + uint32_t func; + uint16_t unkflags; + char name[1]; +}; +#pragma pack(pop) + +#pragma pack(push,1) +struct RegisterVariableAssignComponent +{ + uint16_t type; + OperandType Type() { return (OperandType) type; } + uint16_t unkA; + uint16_t srcComp; + uint16_t unkB; + uint32_t instrOffset; + uint16_t unkC; + uint16_t unkD; + uint16_t destComp; + uint16_t unkE; // destComp for len == 24 +}; +#pragma pack(pop) + +struct PDBStream +{ + uint32_t byteLength; + vector pageIndices; +}; + +class SPDBChunk : public DXBCDebugChunk +{ + public: + SPDBChunk(void *data, uint32_t firstInstruction); + + string GetCompilerSig() const { return m_CompilandDetails.CompilerSig; } + string GetEntryFunction() const { return m_Entry; } + string GetShaderProfile() const { return m_Profile; } + + uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; } + + void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const; + + DXBCDebugChunk *Clone() const { return new SPDBChunk(*this); } + private: + bool m_HasDebugInfo; + + CompilandDetails m_CompilandDetails; + + string m_Entry; + string m_Profile; + + uint32_t m_ShaderFlags; + + map > m_LineNumbers; +}; + +}; \ No newline at end of file diff --git a/renderdoc/driver/dxgi/dxgi_wrapped.cpp b/renderdoc/driver/dxgi/dxgi_wrapped.cpp new file mode 100644 index 0000000000..a3707fccb7 --- /dev/null +++ b/renderdoc/driver/dxgi/dxgi_wrapped.cpp @@ -0,0 +1,448 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/dxgi/dxgi_wrapped.h" +#include "driver/d3d11/d3d11_context.h" +#include "driver/d3d11/d3d11_renderstate.h" +#include "driver/d3d11/d3d11_resources.h" + +#include +#include + +WRAPPED_POOL_INST(WrappedIDXGIDevice); +WRAPPED_POOL_INST(WrappedIDXGIDevice1); + +HRESULT WrappedIDXGIFactory::CreateSwapChain( + /* [annotation][in] */ + __in IUnknown *pDevice, + /* [annotation][in] */ + __in DXGI_SWAP_CHAIN_DESC *pDesc, + /* [annotation][out] */ + __out IDXGISwapChain **ppSwapChain) +{ + if(WrappedID3D11Device::IsAlloc(pDevice) || + WrappedIDXGIDevice::IsAlloc(pDevice) || + WrappedIDXGIDevice1::IsAlloc(pDevice)) + { + WrappedID3D11Device *wrapDevice = (WrappedID3D11Device *)pDevice; + + if(WrappedIDXGIDevice::IsAlloc(pDevice)) + wrapDevice = (WrappedID3D11Device *)((WrappedIDXGIDevice *)(IDXGIDevice *)pDevice)->GetD3DDevice(); + if(WrappedIDXGIDevice1::IsAlloc(pDevice)) + wrapDevice = (WrappedID3D11Device *)((WrappedIDXGIDevice1 *)(IDXGIDevice1 *)pDevice)->GetD3DDevice(); + + if(!RenderDoc::Inst().GetCaptureOptions().AllowFullscreen && pDesc) + { + pDesc->Windowed = TRUE; + } + + HRESULT ret = m_pReal->CreateSwapChain(wrapDevice->GetReal(), pDesc, ppSwapChain); + + if(SUCCEEDED(ret)) + *ppSwapChain = new WrappedIDXGISwapChain(*ppSwapChain, wrapDevice); + + return ret; + } + else + { + RDCERR("Creating swap chain with non-hooked device!"); + } + + return m_pReal->CreateSwapChain(pDevice, pDesc, ppSwapChain); +} + +HRESULT WrappedIDXGIFactory1::CreateSwapChain( + /* [annotation][in] */ + __in IUnknown *pDevice, + /* [annotation][in] */ + __in DXGI_SWAP_CHAIN_DESC *pDesc, + /* [annotation][out] */ + __out IDXGISwapChain **ppSwapChain) +{ + if(WrappedID3D11Device::IsAlloc(pDevice) || + WrappedIDXGIDevice::IsAlloc(pDevice) || + WrappedIDXGIDevice1::IsAlloc(pDevice)) + { + WrappedID3D11Device *wrapDevice = (WrappedID3D11Device *)pDevice; + + if(WrappedIDXGIDevice::IsAlloc(pDevice)) + wrapDevice = (WrappedID3D11Device *)((WrappedIDXGIDevice *)(IDXGIDevice *)pDevice)->GetD3DDevice(); + if(WrappedIDXGIDevice1::IsAlloc(pDevice)) + wrapDevice = (WrappedID3D11Device *)((WrappedIDXGIDevice1 *)(IDXGIDevice1 *)pDevice)->GetD3DDevice(); + + if(!RenderDoc::Inst().GetCaptureOptions().AllowFullscreen && pDesc) + { + pDesc->Windowed = TRUE; + } + + HRESULT ret = m_pReal->CreateSwapChain(wrapDevice->GetReal(), pDesc, ppSwapChain); + + if(SUCCEEDED(ret)) + *ppSwapChain = new WrappedIDXGISwapChain(*ppSwapChain, wrapDevice); + + return ret; + } + else + { + RDCERR("Creating swap chain with non-hooked device!"); + } + + return m_pReal->CreateSwapChain(pDevice, pDesc, ppSwapChain); +} + +WrappedIDXGISwapChain::WrappedIDXGISwapChain(IDXGISwapChain* real, WrappedID3D11Device *device) + : RefCountDXGIObject(real), m_pReal(real), m_pDevice(device), m_iRefcount(1) +{ + DXGI_SWAP_CHAIN_DESC desc; + real->GetDesc(&desc); + + int bufCount = desc.BufferCount; + + if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD) + bufCount = 1; + + RDCASSERT(bufCount < MAX_NUM_BACKBUFFERS); + + for(int i=0; i < MAX_NUM_BACKBUFFERS; i++) + { + m_pBackBuffers[i] = NULL; + + if(i < bufCount) + { + GetBuffer(i, __uuidof(ID3D11Texture2D), (void **)&m_pBackBuffers[i]); + + WrappedID3D11Texture2D *wrapped = (WrappedID3D11Texture2D *)m_pBackBuffers[i]; + + if(wrapped) + { + // keep ref as a 'view' (invisible to user) + wrapped->ViewAddRef(); + wrapped->Release(); + } + } + } + + m_bFullscreen = desc.Windowed == FALSE; + + SAFE_ADDREF(m_pDevice); +} + +WrappedIDXGISwapChain::~WrappedIDXGISwapChain() +{ + m_pDevice->ReleaseSwapchainResources(this); + + SAFE_RELEASE(m_pReal); + for(int i=0; i < MAX_NUM_BACKBUFFERS; i++) + { + WrappedID3D11Texture2D *wrapped = (WrappedID3D11Texture2D *)m_pBackBuffers[i]; + if(wrapped) + wrapped->ViewRelease(); + m_pBackBuffers[i] = NULL; + } + + SAFE_RELEASE(m_pDevice); +} + +HRESULT WrappedIDXGISwapChain::ResizeBuffers( + /* [in] */ UINT BufferCount, + /* [in] */ UINT Width, + /* [in] */ UINT Height, + /* [in] */ DXGI_FORMAT NewFormat, + /* [in] */ UINT SwapChainFlags) +{ + for(int i=0; i < MAX_NUM_BACKBUFFERS; i++) + { + WrappedID3D11Texture2D *wrapped = (WrappedID3D11Texture2D*)m_pBackBuffers[i]; + if(wrapped) + { + m_pDevice->GetImmediateContext()->GetCurrentPipelineState()->UnbindIUnknownForWrite(wrapped); + m_pDevice->GetImmediateContext()->GetCurrentPipelineState()->UnbindForRead(wrapped); + + wrapped->ViewRelease(); + } + + wrapped = NULL; + } + + m_pDevice->ReleaseSwapchainResources(this); + + HRESULT ret = m_pReal->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); + + DXGI_SWAP_CHAIN_DESC desc; + m_pReal->GetDesc(&desc); + + int bufCount = desc.BufferCount; + + if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD) + bufCount = 1; + + RDCASSERT(bufCount < MAX_NUM_BACKBUFFERS); + + for(int i=0; i < MAX_NUM_BACKBUFFERS; i++) + { + m_pBackBuffers[i] = NULL; + + if(i < bufCount) + { + GetBuffer(i, __uuidof(ID3D11Texture2D), (void **)&m_pBackBuffers[i]); + + WrappedID3D11Texture2D *wrapped = (WrappedID3D11Texture2D *)m_pBackBuffers[i]; + + if(wrapped) + { + // keep ref as a 'view' (invisible to user) + wrapped->ViewAddRef(); + wrapped->Release(); + } + } + } + + return ret; +} + +HRESULT WrappedIDXGISwapChain::SetFullscreenState( + /* [in] */ BOOL Fullscreen, + /* [in] */ IDXGIOutput *pTarget) +{ + m_bFullscreen = Fullscreen == TRUE; + + if(RenderDoc::Inst().GetCaptureOptions().AllowFullscreen) + return m_pReal->SetFullscreenState(Fullscreen, pTarget); + + return S_OK; +} + +HRESULT WrappedIDXGISwapChain::GetFullscreenState( + /* [out] */ BOOL *pFullscreen, + /* [out] */ IDXGIOutput **ppTarget) +{ + if(RenderDoc::Inst().GetCaptureOptions().AllowFullscreen) + return m_pReal->GetFullscreenState(pFullscreen, ppTarget); + + if(!pFullscreen) + return E_INVALIDARG; + + *pFullscreen = m_bFullscreen == true ? TRUE : FALSE; + return S_OK; +} + +HRESULT WrappedIDXGISwapChain::GetBuffer( + /* [in] */ UINT Buffer, + /* [in] */ REFIID riid, + /* [out][in] */ void **ppSurface) +{ + if(ppSurface == NULL) return E_INVALIDARG; + + HRESULT ret = m_pReal->GetBuffer(Buffer, riid, ppSurface); + + RDCASSERT(riid == __uuidof(ID3D11Texture2D) || riid == __uuidof(ID3D11Resource)); + + ID3D11Texture2D *realSurface = (ID3D11Texture2D *)*ppSurface; + ID3D11Texture2D *tex = realSurface; + if(FAILED(ret)) + { + RDCERR("Failed to get swapchain backbuffer %d: %08x", Buffer, ret); + SAFE_RELEASE(realSurface); + tex = NULL; + } + else if(m_pDevice->GetResourceManager()->HasWrapper(realSurface)) + { + tex = (ID3D11Texture2D *)m_pDevice->GetResourceManager()->GetWrapper(realSurface); + tex->AddRef(); + + realSurface->Release(); + } + else + { + tex = new WrappedID3D11Texture2D(realSurface, m_pDevice, TEXDISPLAY_UNKNOWN); + + DXGI_SWAP_CHAIN_DESC desc; + m_pReal->GetDesc(&desc); + + m_pDevice->SetSwapChainTexture(this, &desc, Buffer, tex); + + SetDebugName(tex, "Swap Chain Backbuffer"); + } + + *ppSurface = tex; + + return ret; +} + +HRESULT WrappedIDXGISwapChain::GetDevice( + /* [in] */ REFIID riid, + /* [retval][out] */ void **ppDevice) +{ + HRESULT ret = m_pReal->GetDevice(riid, ppDevice); + + if(SUCCEEDED(ret)) + { + // try one of the trivial wraps, we don't mind making a new one of those + if(riid == __uuidof(ID3D11Device)) + { + // probably they're asking for the device device. + *ppDevice = m_pDevice; + m_pDevice->AddRef(); + } + else if(riid == __uuidof(IDXGISwapChain)) + { + // don't think anyone would try this, but what the hell. + *ppDevice = this; + AddRef(); + } + else if(!HandleWrap(riid, ppDevice)) + { + // can probably get away with returning the real result here, + // but it worries me a bit. + RDCUNIMPLEMENTED("Not returning trivial type"); + } + } + + return ret; +} + +HRESULT WrappedIDXGISwapChain::Present( + /* [in] */ UINT SyncInterval, + /* [in] */ UINT Flags) +{ + if(!RenderDoc::Inst().GetCaptureOptions().AllowVSync) + { + SyncInterval = 0; + } + + m_pDevice->Present(this, SyncInterval, Flags); + + return m_pReal->Present(SyncInterval, Flags); +} + +bool RefCountDXGIObject::HandleWrap(REFIID riid, void **ppvObject) +{ + if(riid == __uuidof(IDXGIDevice)) + { + // should have been handled elsewhere, so we can properly create this device + RDCERR("Unexpected uuid in RefCountDXGIObject::HandleWrap"); + return false; + } + else if(riid == __uuidof(IDXGIAdapter)) + { + IDXGIAdapter *real = (IDXGIAdapter *)(*ppvObject); + *ppvObject = new WrappedIDXGIAdapter(real); + return true; + } + else if(riid == __uuidof(IDXGIFactory)) + { + // yes I know PRECISELY how fucked up this is. Speak to microsoft - after KB2670838 the internal D3D11 + // device creation function will pass in __uuidof(IDXGIFactory) then attempt to call EnumDevices1 (which + // is in the IDXGIFactory1 vtable). Doing this *should* be safe as using a IDXGIFactory1 like a IDXGIFactory + // should all just work by definition, but there's no way to know now if someone trying to create a IDXGIFactory + // really means it or not. + IDXGIFactory1 *real = (IDXGIFactory1 *)(*ppvObject); + *ppvObject = new WrappedIDXGIFactory1(real); + return true; + } + + + else if(riid == __uuidof(IDXGIDevice1)) + { + // should have been handled elsewhere, so we can properly create this device + RDCERR("Unexpected uuid in RefCountDXGIObject::HandleWrap"); + return false; + } + else if(riid == __uuidof(IDXGIAdapter1)) + { + IDXGIAdapter1 *real = (IDXGIAdapter1 *)(*ppvObject); + *ppvObject = new WrappedIDXGIAdapter1(real); + return true; + } + else if(riid == __uuidof(IDXGIFactory1)) + { + IDXGIFactory1 *real = (IDXGIFactory1 *)(*ppvObject); + *ppvObject = new WrappedIDXGIFactory1(real); + return true; + } + else + { + string guid = ToStr::Get(riid); + RDCWARN("Querying IDXGIObject for interface: %hs", guid.c_str()); + } + + return false; +} + +HRESULT STDMETHODCALLTYPE RefCountDXGIObject::GetParent( + /* [in] */ REFIID riid, + /* [retval][out] */ void **ppParent) +{ + HRESULT ret = m_pReal->GetParent(riid, ppParent); + + if(SUCCEEDED(ret)) + HandleWrap(riid, ppParent); + + return ret; +} + +HRESULT RefCountDXGIObject::WrapQueryInterface(IUnknown *real, REFIID riid, void **ppvObject) +{ + HRESULT ret = real->QueryInterface(riid, ppvObject); + + if(SUCCEEDED(ret)) + HandleWrap(riid, ppvObject); + + return ret; +} + +HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice::QueryInterface( REFIID riid, void **ppvObject ) +{ + if(riid == __uuidof(ID3D11Device)) + { + m_pD3DDevice->AddRef(); + *ppvObject = m_pD3DDevice; + return S_OK; + } + else + { + string guid = ToStr::Get(riid); + RDCWARN("Querying IDXGIDevice for interface: %hs", guid.c_str()); + } + + return RefCountDXGIObject::QueryInterface(riid, ppvObject); +} + +HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice1::QueryInterface( REFIID riid, void **ppvObject ) +{ + if(riid == __uuidof(ID3D11Device)) + { + m_pD3DDevice->AddRef(); + *ppvObject = m_pD3DDevice; + return S_OK; + } + else + { + string guid = ToStr::Get(riid); + RDCWARN("Querying IDXGIDevice1 for interface: %hs", guid.c_str()); + } + + return RefCountDXGIObject::QueryInterface(riid, ppvObject); +} diff --git a/renderdoc/driver/dxgi/dxgi_wrapped.h b/renderdoc/driver/dxgi/dxgi_wrapped.h new file mode 100644 index 0000000000..43d3c9d09e --- /dev/null +++ b/renderdoc/driver/dxgi/dxgi_wrapped.h @@ -0,0 +1,550 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include + +#include "common/common.h" +#include "common/wrapped_pool.h" + +class RefCountDXGIObject : public IDXGIObject +{ + IDXGIObject *m_pReal; + unsigned int m_iRefcount; +public: + RefCountDXGIObject(IDXGIObject *real) : m_pReal(real), m_iRefcount(1) {} + virtual ~RefCountDXGIObject() {} + + static bool HandleWrap(REFIID riid, void **ppvObject); + static HRESULT WrapQueryInterface(IUnknown *real, REFIID riid, void **ppvObject); + + ////////////////////////////// + // implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface( + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + __RPC__deref_out void **ppvObject) + { return WrapQueryInterface(m_pReal, riid, ppvObject); } + + ULONG STDMETHODCALLTYPE AddRef() { return ++m_iRefcount; } + ULONG STDMETHODCALLTYPE Release() { ULONG ret = --m_iRefcount; if(m_iRefcount == 0) delete this; return ret; } + + ////////////////////////////// + // implement IDXGIObject + + virtual HRESULT STDMETHODCALLTYPE SetPrivateData( + /* [in] */ REFGUID Name, + /* [in] */ UINT DataSize, + /* [in] */ const void *pData) + { return m_pReal->SetPrivateData(Name, DataSize, pData); } + + virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + /* [in] */ REFGUID Name, + /* [in] */ const IUnknown *pUnknown) + { return m_pReal->SetPrivateDataInterface(Name, pUnknown); } + + virtual HRESULT STDMETHODCALLTYPE GetPrivateData( + /* [in] */ REFGUID Name, + /* [out][in] */ UINT *pDataSize, + /* [out] */ void *pData) + { return m_pReal->GetPrivateData(Name, pDataSize, pData); } + + virtual HRESULT STDMETHODCALLTYPE GetParent( + /* [in] */ REFIID riid, + /* [retval][out] */ void **ppParent); +}; + +#define IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT \ + ULONG STDMETHODCALLTYPE AddRef() { return RefCountDXGIObject::AddRef(); } \ + ULONG STDMETHODCALLTYPE Release() { return RefCountDXGIObject::Release(); } \ + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { return RefCountDXGIObject::QueryInterface(riid, ppvObject); } \ + HRESULT STDMETHODCALLTYPE SetPrivateData(REFIID Name, UINT DataSize, const void *pData) { return RefCountDXGIObject::SetPrivateData(Name, DataSize, pData); } \ + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFIID Name, const IUnknown *pUnknown) { return RefCountDXGIObject::SetPrivateDataInterface(Name, pUnknown); } \ + HRESULT STDMETHODCALLTYPE GetPrivateData(REFIID Name, UINT *pDataSize, void *pData) { return RefCountDXGIObject::GetPrivateData(Name, pDataSize, pData); } \ + HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void **ppvObject) { return RefCountDXGIObject::GetParent(riid, ppvObject); } + +#define IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT_CUSTOMQUERY \ + ULONG STDMETHODCALLTYPE AddRef() { return RefCountDXGIObject::AddRef(); } \ + ULONG STDMETHODCALLTYPE Release() { return RefCountDXGIObject::Release(); } \ + HRESULT STDMETHODCALLTYPE SetPrivateData(REFIID Name, UINT DataSize, const void *pData) { return RefCountDXGIObject::SetPrivateData(Name, DataSize, pData); } \ + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFIID Name, const IUnknown *pUnknown) { return RefCountDXGIObject::SetPrivateDataInterface(Name, pUnknown); } \ + HRESULT STDMETHODCALLTYPE GetPrivateData(REFIID Name, UINT *pDataSize, void *pData) { return RefCountDXGIObject::GetPrivateData(Name, pDataSize, pData); } \ + HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void **ppvObject) { return RefCountDXGIObject::GetParent(riid, ppvObject); } + +class WrappedID3D11Device; +struct ID3D11Resource; + +class WrappedIDXGISwapChain : public IDXGISwapChain, public RefCountDXGIObject +{ + IDXGISwapChain* m_pReal; + WrappedID3D11Device *m_pDevice; + unsigned int m_iRefcount; + + static const int MAX_NUM_BACKBUFFERS = 4; + + ID3D11Resource *m_pBackBuffers[MAX_NUM_BACKBUFFERS]; + + bool m_bFullscreen; +public: + WrappedIDXGISwapChain(IDXGISwapChain* real, WrappedID3D11Device *device); + virtual ~WrappedIDXGISwapChain(); + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT; + + ////////////////////////////// + // implement IDXGIDeviceSubObject + + virtual HRESULT STDMETHODCALLTYPE GetDevice( + /* [in] */ REFIID riid, + /* [retval][out] */ void **ppDevice); + + ////////////////////////////// + // implement IDXGISwapChain + + virtual HRESULT STDMETHODCALLTYPE Present( + /* [in] */ UINT SyncInterval, + /* [in] */ UINT Flags); + + virtual HRESULT STDMETHODCALLTYPE GetBuffer( + /* [in] */ UINT Buffer, + /* [in] */ REFIID riid, + /* [out][in] */ void **ppSurface); + + virtual HRESULT STDMETHODCALLTYPE SetFullscreenState( + /* [in] */ BOOL Fullscreen, + /* [in] */ IDXGIOutput *pTarget); + + virtual HRESULT STDMETHODCALLTYPE GetFullscreenState( + /* [out] */ BOOL *pFullscreen, + /* [out] */ IDXGIOutput **ppTarget); + + virtual HRESULT STDMETHODCALLTYPE GetDesc( + /* [out] */ DXGI_SWAP_CHAIN_DESC *pDesc) + { + return m_pReal->GetDesc(pDesc); + } + + virtual HRESULT STDMETHODCALLTYPE ResizeBuffers( + /* [in] */ UINT BufferCount, + /* [in] */ UINT Width, + /* [in] */ UINT Height, + /* [in] */ DXGI_FORMAT NewFormat, + /* [in] */ UINT SwapChainFlags); + + virtual HRESULT STDMETHODCALLTYPE ResizeTarget( + /* [in] */ const DXGI_MODE_DESC *pNewTargetParameters) + { + return m_pReal->ResizeTarget(pNewTargetParameters); + } + + virtual HRESULT STDMETHODCALLTYPE GetContainingOutput( + IDXGIOutput **ppOutput) + { + return m_pReal->GetContainingOutput(ppOutput); + } + + virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics( + /* [out] */ DXGI_FRAME_STATISTICS *pStats) + { + return m_pReal->GetFrameStatistics(pStats); + } + + virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount( + /* [out] */ UINT *pLastPresentCount) + { + return m_pReal->GetLastPresentCount(pLastPresentCount); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// Crap classes we don't really care about, except capturing the swap chain + +class WrappedIDXGIAdapter : public IDXGIAdapter, public RefCountDXGIObject +{ + IDXGIAdapter* m_pReal; + unsigned int m_iRefcount; +public: + WrappedIDXGIAdapter(IDXGIAdapter* real) : RefCountDXGIObject(real), m_pReal(real), m_iRefcount(1) {} + virtual ~WrappedIDXGIAdapter() { SAFE_RELEASE(m_pReal); } + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT; + + ////////////////////////////// + // implement IDXGIAdapter + + virtual HRESULT STDMETHODCALLTYPE EnumOutputs( + /* [in] */ UINT Output, + /* [annotation][out][in] */ + __out IDXGIOutput **ppOutput) + { + return m_pReal->EnumOutputs(Output, ppOutput); + } + + virtual HRESULT STDMETHODCALLTYPE GetDesc( + /* [annotation][out] */ + __out DXGI_ADAPTER_DESC *pDesc) + { + return m_pReal->GetDesc(pDesc); + } + + virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport( + /* [annotation][in] */ + __in REFGUID InterfaceName, + /* [annotation][out] */ + __out LARGE_INTEGER *pUMDVersion) + { + return m_pReal->CheckInterfaceSupport(InterfaceName, pUMDVersion); + } +}; + +class WrappedIDXGIDevice : public IDXGIDevice, public RefCountDXGIObject +{ + IDXGIDevice* m_pReal; + ID3D11Device* m_pD3DDevice; +public: + WrappedIDXGIDevice(IDXGIDevice* real, ID3D11Device *d3d) : + RefCountDXGIObject(real), m_pReal(real), m_pD3DDevice(d3d) { m_pD3DDevice->AddRef(); } + + virtual ~WrappedIDXGIDevice() { SAFE_RELEASE(m_pReal); SAFE_RELEASE(m_pD3DDevice); } + + static const public int AllocPoolCount = 4; + ALLOCATE_WITH_WRAPPED_POOL(WrappedIDXGIDevice, AllocPoolCount); + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT_CUSTOMQUERY; + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + ID3D11Device *GetD3DDevice() { return m_pD3DDevice; } + + ////////////////////////////// + // implement IDXGIDevice + + virtual HRESULT STDMETHODCALLTYPE GetAdapter( + /* [annotation][out] */ + __out IDXGIAdapter **pAdapter) + { + HRESULT ret = m_pReal->GetAdapter(pAdapter); + if(SUCCEEDED(ret)) *pAdapter = new WrappedIDXGIAdapter(*pAdapter); + return ret; + } + + virtual HRESULT STDMETHODCALLTYPE CreateSurface( + /* [annotation][in] */ + __in const DXGI_SURFACE_DESC *pDesc, + /* [in] */ UINT NumSurfaces, + /* [in] */ DXGI_USAGE Usage, + /* [annotation][in] */ + __in_opt const DXGI_SHARED_RESOURCE *pSharedResource, + /* [annotation][out] */ + __out IDXGISurface **ppSurface) + { + return m_pReal->CreateSurface(pDesc, NumSurfaces, Usage, pSharedResource, ppSurface); + } + + virtual HRESULT STDMETHODCALLTYPE QueryResourceResidency( + /* [annotation][size_is][in] */ + __in_ecount(NumResources) IUnknown *const *ppResources, + /* [annotation][size_is][out] */ + __out_ecount(NumResources) DXGI_RESIDENCY *pResidencyStatus, + /* [in] */ UINT NumResources) + { + return m_pReal->QueryResourceResidency(ppResources, pResidencyStatus, NumResources); + } + + virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority( + /* [in] */ INT Priority) + { + return m_pReal->SetGPUThreadPriority(Priority); + } + + virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority( + /* [annotation][retval][out] */ + __out INT *pPriority) + { + return m_pReal->GetGPUThreadPriority(pPriority); + } +}; + +class WrappedIDXGIFactory : public IDXGIFactory, public RefCountDXGIObject +{ + IDXGIFactory* m_pReal; + unsigned int m_iRefcount; +public: + WrappedIDXGIFactory(IDXGIFactory* real) : RefCountDXGIObject(real), m_pReal(real), m_iRefcount(1) {} + virtual ~WrappedIDXGIFactory() { SAFE_RELEASE(m_pReal); } + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT; + + ////////////////////////////// + // implement IDXGIFactory + + virtual HRESULT STDMETHODCALLTYPE EnumAdapters( + /* [in] */ UINT Adapter, + /* [annotation][out] */ + __out IDXGIAdapter **ppAdapter) + { + HRESULT ret = m_pReal->EnumAdapters(Adapter, ppAdapter); + if(SUCCEEDED(ret)) *ppAdapter = new WrappedIDXGIAdapter(*ppAdapter); + return ret; + } + + virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation( + HWND WindowHandle, + UINT Flags) + { + return m_pReal->MakeWindowAssociation(WindowHandle, Flags); + } + + virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation( + /* [annotation][out] */ + __out HWND *pWindowHandle) + { + return m_pReal->GetWindowAssociation(pWindowHandle); + } + + virtual HRESULT STDMETHODCALLTYPE CreateSwapChain( + /* [annotation][in] */ + __in IUnknown *pDevice, + /* [annotation][in] */ + __in DXGI_SWAP_CHAIN_DESC *pDesc, + /* [annotation][out] */ + __out IDXGISwapChain **ppSwapChain); + + virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter( + /* [in] */ HMODULE Module, + /* [annotation][out] */ + __out IDXGIAdapter **ppAdapter) + { + HRESULT ret = m_pReal->CreateSoftwareAdapter(Module, ppAdapter); + if(SUCCEEDED(ret)) *ppAdapter = new WrappedIDXGIAdapter(*ppAdapter); + return ret; + } +}; + +// version 1 + +class WrappedIDXGIAdapter1 : public IDXGIAdapter1, public RefCountDXGIObject +{ + IDXGIAdapter1* m_pReal; + unsigned int m_iRefcount; +public: + WrappedIDXGIAdapter1(IDXGIAdapter1* real) : RefCountDXGIObject(real), m_pReal(real), m_iRefcount(1) {} + virtual ~WrappedIDXGIAdapter1() { SAFE_RELEASE(m_pReal); } + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT; + + ////////////////////////////// + // implement IDXGIAdapter + + virtual HRESULT STDMETHODCALLTYPE EnumOutputs( + /* [in] */ UINT Output, + /* [annotation][out][in] */ + __out IDXGIOutput **ppOutput) + { + return m_pReal->EnumOutputs(Output, ppOutput); + } + + virtual HRESULT STDMETHODCALLTYPE GetDesc( + /* [annotation][out] */ + __out DXGI_ADAPTER_DESC *pDesc) + { + return m_pReal->GetDesc(pDesc); + } + + virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport( + /* [annotation][in] */ + __in REFGUID InterfaceName, + /* [annotation][out] */ + __out LARGE_INTEGER *pUMDVersion) + { + return m_pReal->CheckInterfaceSupport(InterfaceName, pUMDVersion); + } + + ////////////////////////////// + // implement IDXGIAdapter1 + + virtual HRESULT STDMETHODCALLTYPE GetDesc1( + /* [out] */ DXGI_ADAPTER_DESC1 *pDesc) + { + return m_pReal->GetDesc1(pDesc); + } +}; + +class WrappedIDXGIDevice1 : public IDXGIDevice1, public RefCountDXGIObject +{ + IDXGIDevice1* m_pReal; + ID3D11Device* m_pD3DDevice; +public: + WrappedIDXGIDevice1(IDXGIDevice1* real, ID3D11Device *d3d) : + RefCountDXGIObject(real), m_pReal(real), m_pD3DDevice(d3d) { m_pD3DDevice->AddRef(); } + virtual ~WrappedIDXGIDevice1() { SAFE_RELEASE(m_pReal); SAFE_RELEASE(m_pD3DDevice); } + + static const public int AllocPoolCount = 4; + ALLOCATE_WITH_WRAPPED_POOL(WrappedIDXGIDevice1, AllocPoolCount); + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT_CUSTOMQUERY; + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + ID3D11Device *GetD3DDevice() { return m_pD3DDevice; } + + ////////////////////////////// + // implement IDXGIDevice + + virtual HRESULT STDMETHODCALLTYPE GetAdapter( + /* [annotation][out] */ + __out IDXGIAdapter **pAdapter) + { + HRESULT ret = m_pReal->GetAdapter(pAdapter); + if(SUCCEEDED(ret)) *pAdapter = new WrappedIDXGIAdapter(*pAdapter); + return ret; + } + + virtual HRESULT STDMETHODCALLTYPE CreateSurface( + /* [annotation][in] */ + __in const DXGI_SURFACE_DESC *pDesc, + /* [in] */ UINT NumSurfaces, + /* [in] */ DXGI_USAGE Usage, + /* [annotation][in] */ + __in_opt const DXGI_SHARED_RESOURCE *pSharedResource, + /* [annotation][out] */ + __out IDXGISurface **ppSurface) + { + return m_pReal->CreateSurface(pDesc, NumSurfaces, Usage, pSharedResource, ppSurface); + } + + virtual HRESULT STDMETHODCALLTYPE QueryResourceResidency( + /* [annotation][size_is][in] */ + __in_ecount(NumResources) IUnknown *const *ppResources, + /* [annotation][size_is][out] */ + __out_ecount(NumResources) DXGI_RESIDENCY *pResidencyStatus, + /* [in] */ UINT NumResources) + { + return m_pReal->QueryResourceResidency(ppResources, pResidencyStatus, NumResources); + } + + virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority( + /* [in] */ INT Priority) + { + return m_pReal->SetGPUThreadPriority(Priority); + } + + virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority( + /* [annotation][retval][out] */ + __out INT *pPriority) + { + return m_pReal->GetGPUThreadPriority(pPriority); + } + + ////////////////////////////// + // implement IDXGIDevice1 + + virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency( + /* [in] */ UINT MaxLatency) + { + return m_pReal->SetMaximumFrameLatency(MaxLatency); + } + + virtual HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency( + /* [annotation][out] */ + __out UINT *pMaxLatency) + { + return m_pReal->GetMaximumFrameLatency(pMaxLatency); + } +}; + +class WrappedIDXGIFactory1 : public IDXGIFactory1, public RefCountDXGIObject +{ + IDXGIFactory1* m_pReal; + unsigned int m_iRefcount; +public: + WrappedIDXGIFactory1(IDXGIFactory1* real) : RefCountDXGIObject(real), m_pReal(real), m_iRefcount(1) {} + virtual ~WrappedIDXGIFactory1() { SAFE_RELEASE(m_pReal); } + + IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT; + + ////////////////////////////// + // implement IDXGIFactory + + virtual HRESULT STDMETHODCALLTYPE EnumAdapters( + /* [in] */ UINT Adapter, + /* [annotation][out] */ + __out IDXGIAdapter **ppAdapter) + { + HRESULT ret = m_pReal->EnumAdapters(Adapter, ppAdapter); + if(SUCCEEDED(ret)) *ppAdapter = new WrappedIDXGIAdapter(*ppAdapter); + return ret; + } + + virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation( + HWND WindowHandle, + UINT Flags) + { + return m_pReal->MakeWindowAssociation(WindowHandle, Flags); + } + + virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation( + /* [annotation][out] */ + __out HWND *pWindowHandle) + { + return m_pReal->GetWindowAssociation(pWindowHandle); + } + + virtual HRESULT STDMETHODCALLTYPE CreateSwapChain( + /* [annotation][in] */ + __in IUnknown *pDevice, + /* [annotation][in] */ + __in DXGI_SWAP_CHAIN_DESC *pDesc, + /* [annotation][out] */ + __out IDXGISwapChain **ppSwapChain); + + virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter( + /* [in] */ HMODULE Module, + /* [annotation][out] */ + __out IDXGIAdapter **ppAdapter) + { + HRESULT ret = m_pReal->CreateSoftwareAdapter(Module, ppAdapter); + if(SUCCEEDED(ret)) *ppAdapter = new WrappedIDXGIAdapter(*ppAdapter); + return ret; + } + + ////////////////////////////// + // implement IDXGIFactory1 + + virtual HRESULT STDMETHODCALLTYPE EnumAdapters1( + /* [in] */ UINT Adapter, + /* [annotation][out] */ + __out IDXGIAdapter1 **ppAdapter) + { + HRESULT ret = m_pReal->EnumAdapters1(Adapter, ppAdapter); + if(SUCCEEDED(ret)) *ppAdapter = new WrappedIDXGIAdapter1(*ppAdapter); + return ret; + } + + virtual BOOL STDMETHODCALLTYPE IsCurrent( void) + { + return m_pReal->IsCurrent(); + } +}; diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp new file mode 100644 index 0000000000..4b95447c0f --- /dev/null +++ b/renderdoc/driver/gl/gl_common.cpp @@ -0,0 +1,3444 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "core/core.h" +#include "common/string_utils.h" +#include "gl_common.h" +#include "gl_driver.h" + +namespace TrackedResource +{ + static volatile int64_t globalIDCounter; + + ResourceId GetNewUniqueID() + { + return ResourceId(Atomic::Inc64(&globalIDCounter), true); + } + + void SetReplayResourceIDs() + { + globalIDCounter = RDCMAX(uint64_t(globalIDCounter), uint64_t(globalIDCounter|0x1000000000000000ULL)); + } +}; + +ResourceFormat MakeResourceFormat(WrappedOpenGL &gl, GLenum target, GLenum fmt) +{ + ResourceFormat ret; + + ret.compByteWidth = 1; + ret.compCount = 4; + ret.compType = eCompType_Float; + + ret.rawType = (uint32_t)fmt; + ret.special = false; + ret.specialFormat = eSpecial_Unknown; + + GLint data[8]; + GLenum *edata = (GLenum *)data; + + GLint iscol = 0, isdepth = 0, isstencil = 0; + gl.glGetInternalformativ(target, fmt, eGL_COLOR_COMPONENTS, sizeof(GLint), &iscol); + gl.glGetInternalformativ(target, fmt, eGL_DEPTH_COMPONENTS, sizeof(GLint), &isdepth); + gl.glGetInternalformativ(target, fmt, eGL_STENCIL_COMPONENTS, sizeof(GLint), &isstencil); + + if(iscol == GL_TRUE) + { + // colour format + + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_RED_SIZE, sizeof(GLint), &data[0]); + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_GREEN_SIZE, sizeof(GLint), &data[1]); + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_BLUE_SIZE, sizeof(GLint), &data[2]); + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_ALPHA_SIZE, sizeof(GLint), &data[3]); + + ret.compCount = 0; + for(int i=0; i < 4; i++) + if(data[i] > 0) + ret.compCount++; + + for(int i=ret.compCount; i < 4; i++) + data[i] = data[0]; + + if(data[0] == data[1] && + data[1] == data[2] && + data[2] == data[3]) + { + ret.compByteWidth = (uint32_t)(data[0]/8); + + // wasn't a byte format (8, 16, 32) + if(ret.compByteWidth*8 != (uint32_t)data[0]) + ret.special = true; + } + else + { + ret.special = true; + } + + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_RED_TYPE, sizeof(GLint), &data[0]); + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_GREEN_TYPE, sizeof(GLint), &data[1]); + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_BLUE_TYPE, sizeof(GLint), &data[2]); + gl.glGetInternalformativ(target, fmt, eGL_INTERNALFORMAT_ALPHA_TYPE, sizeof(GLint), &data[3]); + + for(int i=ret.compCount; i < 4; i++) + data[i] = data[0]; + + if(data[0] == data[1] && + data[1] == data[2] && + data[2] == data[3]) + { + switch(edata[0]) + { + case eGL_UNSIGNED_INT: + ret.compType = eCompType_UInt; + break; + case eGL_UNSIGNED_NORMALIZED: + ret.compType = eCompType_UNorm; + break; + case eGL_SIGNED_NORMALIZED: + ret.compType = eCompType_SNorm; + break; + case eGL_FLOAT: + ret.compType = eCompType_Float; + break; + case eGL_INT: + ret.compType = eCompType_SInt; + break; + default: + RDCERR("Unexpected texture type"); + } + } + else + { + ret.special = true; + } + + gl.glGetInternalformativ(target, fmt, eGL_COLOR_ENCODING, sizeof(GLint), &data[0]); + ret.srgbCorrected = (edata[0] == eGL_SRGB); + + if(ret.compType == eCompType_UNorm && ret.srgbCorrected) + ret.compType = eCompType_UNorm_SRGB; + } + else if(isdepth == GL_TRUE || isstencil == GL_TRUE) + { + // depth format + GLNOTIMP("Not getting depth format yet"); + ret.specialFormat = eSpecial_D24S8; + ret.special = true; + + ret.compType = eCompType_Depth; + } + else + { + // not colour or depth! + RDCERR("Unexpected texture type, not colour or depth"); + } + + ret.strname = widen(ToStr::Get(fmt)).substr(3); // 3 == strlen("GL_") + + return ret; +} + +template<> +string ToStrHelper::Get(const RDCGLenum &el) +{ +#undef GLenum + +// egrep -ih '#define[ \t]*[A-Z_0-9]*[ \t]*0x[0-9A-F]{4,}\s*$' glcorearb.h glext.h wglext.h glxext.h +// | awk '{print $2" "$3}' | grep -v '_BIT[_ ]' | sed -e '{s# 0x0*# #g}' | awk -F"[. ]" '!a[$2]++' +// | sed -e '{s%\(.*\) \(.*\)%\t\tTOSTR_CASE_STRINGIZE_GLENUM(\1)%g}' | sort -u + +#define TOSTR_CASE_STRINGIZE_GLENUM(a) case e##a: return #a; + + switch((unsigned int)el) + { + TOSTR_CASE_STRINGIZE_GLENUM(ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(ERROR_INVALID_PIXEL_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(ERROR_INVALID_PROFILE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(ERROR_INVALID_VERSION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(ERROR_MISSING_AFFINITY_MASK_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX0_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX3_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX5_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX6_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX7_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_AUX9_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_BACK_BUFFER_AGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_BACK_LEFT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_BACK_RIGHT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_BIND_TO_MIPMAP_TEXTURE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_BIND_TO_TEXTURE_TARGETS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_DEVICE_ID_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_FRONT_LEFT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_FRONT_RIGHT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_LATE_SWAPS_TEAR_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_MAX_SWAP_INTERVAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_MIPMAP_TEXTURE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_PBUFFER_CLOBBER_MASK) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_ACCELERATED_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_DEVICE_ID_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_PREFERRED_PROFILE_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_VERSION_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_RENDERER_VIDEO_MEMORY_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_STEREO_TREE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_SWAP_INTERVAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_1D_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_2D_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_FORMAT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_FORMAT_NONE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_FORMAT_RGBA_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_FORMAT_RGB_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_RECTANGLE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_TEXTURE_TARGET_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GLX_Y_INVERTED_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_1PASS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_2PASS_0_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_2PASS_1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_422_AVERAGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_422_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_422_REV_AVERAGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_422_REV_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_4PASS_0_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_4PASS_1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_4PASS_2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_4PASS_3_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ABGR_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACCUM_ADJACENT_PAIRS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_ATTRIBUTES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_PROGRAM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_RESOURCES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_STENCIL_FACE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_SUBROUTINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_SUBROUTINE_MAX_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_SUBROUTINE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_UNIFORM_MAX_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_VARIABLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_VARYINGS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_VARYING_MAX_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ACTIVE_VERTEX_UNITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ADD_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ADD_SIGNED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ADJACENT_PAIRS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AFFINE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AFFINE_3D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALIASED_LINE_WIDTH_RANGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALIASED_POINT_SIZE_RANGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALLOW_DRAW_FRG_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALLOW_DRAW_MEM_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALLOW_DRAW_OBJ_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALLOW_DRAW_WIN_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALL_COMPLETED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALL_SHADER_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA12_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA16F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA16I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA16UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA16_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA32F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA32I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA32UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA8I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA8UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA_MAX_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA_MAX_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA_MIN_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA_MIN_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALPHA_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALREADY_SIGNALED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALWAYS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALWAYS_FAST_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ALWAYS_SOFT_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AND) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AND_INVERTED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AND_REVERSE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ANY_SAMPLES_PASSED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ANY_SAMPLES_PASSED_CONSERVATIVE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_ELEMENT_LOCK_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_ELEMENT_LOCK_FIRST_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_OBJECT_BUFFER_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_OBJECT_OFFSET_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ARRAY_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ASYNC_DRAW_PIXELS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ASYNC_HISTOGRAM_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ASYNC_MARKER_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ASYNC_READ_PIXELS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ASYNC_TEX_IMAGE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATOMIC_COUNTER_BUFFER_START) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATTACHED_SHADERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ATTENUATION_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AUTO_GENERATE_MIPMAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AUX_DEPTH_STENCIL_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AVERAGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_AVERAGE_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BACK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BACK_LEFT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BACK_NORMALS_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BACK_PRIMARY_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BACK_RIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BACK_SECONDARY_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BEVEL_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BGRA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BGRA_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BGR_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BIAS_BY_NEGATIVE_ONE_HALF_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BINORMAL_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BINORMAL_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BINORMAL_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BINORMAL_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_ADVANCED_COHERENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_DST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_DST_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_DST_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_EQUATION_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_EQUATION_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_OVERLAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_PREMULTIPLIED_SRC_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_SRC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_SRC_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLEND_SRC_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLOCK_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLUE_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLUE_MAX_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BLUE_MIN_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BOOL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BOOL_VEC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BOOL_VEC3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BOOL_VEC4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BOUNDING_BOX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_ACCESS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_ACCESS_FLAGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_DATA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_FLUSHING_UNMAP_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_GPU_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_IMMUTABLE_STORAGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_MAPPED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_MAP_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_MAP_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_MAP_POINTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_OBJECT_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_SERIALIZED_MODIFY_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_STORAGE_FLAGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_USAGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUFFER_VARIABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUMP_ENVMAP_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUMP_NUM_TEX_UNITS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUMP_ROT_MATRIX_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUMP_ROT_MATRIX_SIZE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUMP_TARGET_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BUMP_TEX_UNITS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_BYTE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CALLIGRAPHIC_FRAGMENT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CAVEAT_SUPPORT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CCW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLAMP_FRAGMENT_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLAMP_READ_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLAMP_TO_BORDER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLAMP_TO_EDGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLAMP_VERTEX_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLEAR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLEAR_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLEAR_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIENT_ACTIVE_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE0) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE6) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE7) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_DISTANCE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_FAR_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_NEAR_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CLIP_VOLUME_CLIPPING_HINT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CMYKA_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CMYK_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CND0_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CND_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLORBURN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLORDODGE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ALPHA_PAIRING_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT0) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT10) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT11) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT12) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT13) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT14) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT15) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT6) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT7) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ATTACHMENT9) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_CLEAR_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_ENCODING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_FLOAT_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_INDEX12_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_INDEX16_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_INDEX1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_INDEX2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_INDEX4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_INDEX8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_LOGIC_OP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_MATRIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_MATRIX_STACK_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_RENDERABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_SAMPLES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_SUM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_SUM_CLAMP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_ALPHA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_BLUE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_GREEN_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_INTENSITY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_LUMINANCE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_RED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_TABLE_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COLOR_WRITEMASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINE4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER0_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER1_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER5_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER6_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER7_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_AB_DOT_PRODUCT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_AB_OUTPUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_CD_DOT_PRODUCT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_CD_OUTPUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_COMPONENT_USAGE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_INPUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_MAPPING_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_MUX_SUM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINER_SUM_OUTPUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINE_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMBINE_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPARE_REF_TO_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPATIBLE_SUBROUTINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPILE_STATUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_INTENSITY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_LUMINANCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_LUMINANCE_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_LUMINANCE_LATC1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_R11_EAC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RED_RGTC1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RG) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RG11_EAC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB8_ETC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA8_ETC2_EAC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_10x10_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_10x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_10x6_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_10x8_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_12x10_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_12x12_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_4x4_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_5x4_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_5x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_6x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_6x6_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_8x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_8x6_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_ASTC_8x8_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_BPTC_UNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_FXT1_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB_FXT1_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RGB_S3TC_DXT1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_RG_RGTC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SIGNED_R11_EAC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SIGNED_RED_RGTC1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SIGNED_RG11_EAC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SIGNED_RG_RGTC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SLUMINANCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SLUMINANCE_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_ETC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPRESSED_TEXTURE_FORMATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_PROGRAM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_SUBROUTINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_SUBROUTINE_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COMPUTE_WORK_GROUP_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONDITION_SATISFIED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONJOINT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSERVE_MEMORY_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSTANT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSTANT_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSTANT_BORDER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSTANT_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSTANT_COLOR0_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONSTANT_COLOR1_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONST_EYE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONTEXT_FLAGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONTEXT_PROFILE_MASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONTINUOUS_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONTRAST_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVEX_HULL_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_BORDER_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_BORDER_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_FILTER_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_FILTER_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_HINT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CONVOLUTION_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_0_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_10_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_11_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_12_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_13_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_14_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_15_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_16_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_17_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_18_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_19_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_1_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_20_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_21_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_22_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_23_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_24_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_25_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_26_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_27_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_28_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_29_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_2_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_30_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_31_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_3_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_4_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_5_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_6_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_7_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_8_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CON_9_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COORD_REPLACE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COPY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COPY_INVERTED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COPY_READ_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COPY_WRITE_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COUNTER_RANGE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COUNTER_TYPE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COUNT_DOWN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_COUNT_UP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CUBIC_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CUBIC_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_FACE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_FACE_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_FRAGMENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_MODES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_VERTEX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_VERTEX_EYE_POSITION_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CULL_VERTEX_OBJECT_POSITION_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_BINORMAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_FOG_COORDINATE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_MATRIX_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_MATRIX_INDEX_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_MATRIX_STACK_DEPTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_PALETTE_MATRIX_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_PROGRAM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_QUERY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_RASTER_NORMAL_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_RASTER_SECONDARY_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_SECONDARY_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_TANGENT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_VERTEX_ATTRIB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_VERTEX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_VERTEX_WEIGHT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CURRENT_WEIGHT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_CW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DARKEN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DATA_BUFFER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CALLBACK_FUNCTION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CALLBACK_USER_PARAM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_API_ERROR_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_APPLICATION_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_DEPRECATION_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_OTHER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_PERFORMANCE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_GROUP_STACK_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_LOGGED_MESSAGES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_OUTPUT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_OUTPUT_SYNCHRONOUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SEVERITY_HIGH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SEVERITY_LOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SEVERITY_MEDIUM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SEVERITY_NOTIFICATION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SOURCE_API) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SOURCE_APPLICATION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SOURCE_OTHER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SOURCE_SHADER_COMPILER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SOURCE_THIRD_PARTY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_SOURCE_WINDOW_SYSTEM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_ERROR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_MARKER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_OTHER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_PERFORMANCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_POP_GROUP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_PORTABILITY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_PUSH_GROUP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DECODE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DECR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DECR_WRAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEFORMATIONS_MASK_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DELETE_STATUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPENDENT_AR_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPENDENT_GB_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPENDENT_HILO_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPENDENT_RGB_TEXTURE_3D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH24_STENCIL8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH32F_STENCIL8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH32F_STENCIL8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_ATTACHMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_BOUNDS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_BOUNDS_TEST_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_BUFFER_FLOAT_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_CLAMP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_CLAMP_FAR_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_CLAMP_NEAR_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_CLEAR_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENT16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENT24) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENT32) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENT32F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENT32F_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_FUNC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_RANGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_RENDERABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_STENCIL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_STENCIL_ATTACHMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_STENCIL_TEXTURE_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_STENCIL_TO_BGRA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_STENCIL_TO_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_TEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_TEXTURE_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DEPTH_WRITEMASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DETAIL_TEXTURE_2D_BINDING_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DETAIL_TEXTURE_2D_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DETAIL_TEXTURE_LEVEL_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DETAIL_TEXTURE_MODE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DIFFERENCE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISCARD_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISCARD_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISCRETE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISJOINT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISPATCH_INDIRECT_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISPATCH_INDIRECT_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DISPLAY_LIST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DITHER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DONT_CARE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT2_ADD_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT3_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT3_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT3_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT3_RGB_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT4_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_DEPTH_REPLACE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_PASS_THROUGH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_TEXTURE_1D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_TEXTURE_3D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLEBUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT2x3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT2x4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT3x2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT3x4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT4x2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_MAT4x3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_VEC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_VEC3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DOUBLE_VEC4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER0) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER10) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER11) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER12) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER13) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER14) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER15) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER6) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER7) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_BUFFER9) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_FRAMEBUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_INDIRECT_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_INDIRECT_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_INDIRECT_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_INDIRECT_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_INDIRECT_UNIFIED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DRAW_PIXELS_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT8_MAG8_INTENSITY8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT8_MAG8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT_MAG_INTENSITY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT_MAG_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT_MAG_VIB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DSDT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_ATOP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_IN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_OUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DST_OVER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DS_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DS_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DT_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DT_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DU8DV8_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_ALPHA12_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_ALPHA16_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_ALPHA4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_ALPHA8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_INTENSITY12_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_INTENSITY16_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_INTENSITY4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_INTENSITY8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_LUMINANCE12_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_LUMINANCE16_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_LUMINANCE4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_LUMINANCE8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_LUMINANCE_ALPHA4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_LUMINANCE_ALPHA8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUAL_TEXTURE_SELECT_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DUDV_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DYNAMIC_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DYNAMIC_COPY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DYNAMIC_DRAW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_DYNAMIC_READ) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EDGE_FLAG_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_POINTER_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_POINTER_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_TYPE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_TYPE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ELEMENT_ARRAY_UNIFIED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EMBOSS_CONSTANT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EMBOSS_LIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EMBOSS_MAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EQUAL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EQUIV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_FRACTIONAL_TESSELLATION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_TRIANGULAR_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB0_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB10_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB11_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB12_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB13_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB14_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB15_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB1_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB5_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB6_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB7_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EVAL_VERTEX_ATTRIB9_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EXCLUSION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EXPAND_NEGATE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EXPAND_NORMAL_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EXTENSIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EYE_DISTANCE_TO_LINE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EYE_DISTANCE_TO_POINT_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EYE_LINE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EYE_PLANE_ABSOLUTE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EYE_POINT_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_EYE_RADIAL_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_E_TIMES_F_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FACTOR_MAX_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FACTOR_MIN_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FAILURE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FASTEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FENCE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FENCE_CONDITION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FENCE_STATUS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIELDS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIELD_LOWER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIELD_UPPER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FILE_NAME_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FILL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FILTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FILTER4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIRST_TO_REST_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIRST_VERTEX_CONVENTION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIXED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FIXED_ONLY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT16_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT16_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT16_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_32_UNSIGNED_INT_24_8_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_CLEAR_COLOR_VALUE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT2x3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT2x4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT3x2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT3x4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT4x2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_MAT4x3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_R16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_R32_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RG16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RG32_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGB16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGB32_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGBA16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGBA32_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGBA_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_RG_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_R_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_VEC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_VEC3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FLOAT_VEC4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE_ARRAY_POINTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE_ARRAY_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE_ARRAY_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORDINATE_SOURCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORD_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_COORD_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_DISTANCE_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_FUNC_POINTS_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_FUNC_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_OFFSET_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_OFFSET_VALUE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FOG_SPECULAR_TEXTURE_WIN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FORCE_BLUE_TO_ONE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FORMAT_SUBSAMPLE_244_244_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FORMAT_SUBSAMPLE_24_24_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRACTIONAL_EVEN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRACTIONAL_ODD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_COLOR_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_COLOR_MATERIAL_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT0_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT1_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT2_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT3_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT4_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT5_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT6_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT7_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHTING_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_MATERIAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_NORMAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_PROGRAM_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_PROGRAM_BINDING_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_PROGRAM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_SHADER_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_SHADER_DERIVATIVE_HINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_SUBROUTINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_SUBROUTINE_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAGMENT_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_LAYERED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_BLEND) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_COMPLETE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_DEFAULT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_DEFAULT_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_DEFAULT_LAYERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_DEFAULT_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_DEFAULT_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_RENDERABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_RENDERABLE_LAYERED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_SRGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_UNDEFINED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEBUFFER_UNSUPPORTED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEZOOM_FACTOR_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAMEZOOM_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRAME_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRONT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRONT_AND_BACK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRONT_FACE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRONT_LEFT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FRONT_RIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FULL_RANGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FULL_STIPPLE_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FULL_SUPPORT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FUNC_ADD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FUNC_REVERSE_SUBTRACT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_FUNC_SUBTRACT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GENERATE_MIPMAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GENERATE_MIPMAP_HINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GENERIC_ATTRIB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_DEFORMATION_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_INPUT_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_INPUT_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_OUTPUT_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_OUTPUT_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_PROGRAM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_SHADER_INVOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_SUBROUTINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_SUBROUTINE_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_VERTICES_OUT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEOMETRY_VERTICES_OUT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GEQUAL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GET_TEXTURE_IMAGE_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GET_TEXTURE_IMAGE_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GLOBAL_ALPHA_FACTOR_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GLOBAL_ALPHA_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GPU_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GREATER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GREEN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GREEN_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GREEN_MAX_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GREEN_MIN_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_GUILTY_CONTEXT_RESET_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HALF_BIAS_NEGATE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HALF_BIAS_NORMAL_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HALF_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HARDLIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HARDMIX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HIGH_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HIGH_INT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HILO16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HILO8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HILO_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_ALPHA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_BLUE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_GREEN_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_LUMINANCE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_RED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_SINK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HISTOGRAM_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HI_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HI_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HSL_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HSL_HUE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HSL_LUMINOSITY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_HSL_SATURATION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IDENTITY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IGNORE_BORDER_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_2D_RECT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BINDING_ACCESS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BINDING_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BINDING_LAYER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BINDING_LAYERED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BINDING_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BINDING_NAME) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_10_10_10_2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_11_11_10) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_1_X_16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_1_X_32) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_1_X_8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_2_X_16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_2_X_32) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_2_X_8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_4_X_16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_4_X_32) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CLASS_4_X_8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_COMPATIBILITY_CLASS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CUBE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_CUBIC_WEIGHT_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_FORMAT_COMPATIBILITY_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_MAG_FILTER_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_MIN_FILTER_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_PIXEL_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_PIXEL_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_ROTATE_ANGLE_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_ROTATE_ORIGIN_X_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_ROTATE_ORIGIN_Y_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_SCALE_X_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_SCALE_Y_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_TEXEL_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_TRANSFORM_2D_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_TRANSLATE_X_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMAGE_TRANSLATE_Y_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMPLEMENTATION_COLOR_READ_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IMPLEMENTATION_COLOR_READ_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INCR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INCR_WRAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_MATERIAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_MATERIAL_FACE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_MATERIAL_PARAMETER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_TEST_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_TEST_FUNC_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INDEX_TEST_REF_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INFO_LOG_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INNOCENT_CONTEXT_RESET_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INSTRUMENT_BUFFER_POINTER_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INSTRUMENT_MEASUREMENTS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT16_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT16_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT16_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT64_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT64_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT64_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT64_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT8_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT8_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT8_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY12_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY16F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY16I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY16UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY16_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY32F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY32I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY32UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY8I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY8UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTENSITY_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERLACE_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERLACE_READ_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERLACE_READ_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERLACE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERLEAVED_ATTRIBS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_ALPHA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_ALPHA_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_BLUE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_BLUE_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_DEPTH_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_DEPTH_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_GREEN_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_GREEN_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_PREFERRED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_RED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_RED_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_SHARED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_STENCIL_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_STENCIL_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERNALFORMAT_SUPPORTED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INTERPOLATE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_2_10_10_10_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_2D_RECT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_CUBE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_IMAGE_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_2D_RECT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_BUFFER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_CUBE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_SAMPLER_RENDERBUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_VEC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_VEC3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INT_VEC4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVALID_ENUM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVALID_FRAMEBUFFER_OPERATION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVALID_OPERATION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVALID_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVARIANT_DATATYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVARIANT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVARIANT_VALUE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVERSE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVERSE_TRANSPOSE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVERT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVERTED_SCREEN_W_REND) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVERT_OVG_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_INVERT_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IR_INSTRUMENT1_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ISOLINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IS_PER_PATCH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IS_ROW_MAJOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IUI_N3F_V2F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IUI_N3F_V3F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IUI_V2F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_IUI_V3F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_KEEP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LAST_VERTEX_CONVENTION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LAST_VIDEO_CAPTURE_STATUS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LAYER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LAYER_PROVOKING_VERTEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LEFT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LEQUAL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LERP_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LESS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LIGHTEN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LIGHT_ENV_MODE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LIGHT_MODEL_COLOR_CONTROL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEARBURN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEARDODGE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEARLIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_CLIPMAP_LINEAR_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_CLIPMAP_NEAREST_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_DETAIL_ALPHA_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_DETAIL_COLOR_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_DETAIL_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_MIPMAP_LINEAR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_MIPMAP_NEAREST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_SHARPEN_ALPHA_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_SHARPEN_COLOR_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINEAR_SHARPEN_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINES_ADJACENCY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_LOOP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_SMOOTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_SMOOTH_HINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_STRIP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_STRIP_ADJACENCY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_WIDTH_GRANULARITY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINE_WIDTH_RANGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LINK_STATUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LIST_PRIORITY_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCAL_CONSTANT_DATATYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCAL_CONSTANT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCAL_CONSTANT_VALUE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCATION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCATION_COMPONENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOCATION_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOGIC_OP_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOSE_CONTEXT_ON_RESET_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOWER_LEFT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOW_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LOW_INT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LO_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LO_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE12_ALPHA12_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE12_ALPHA4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE12_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16_ALPHA16_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16_ALPHA16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE32F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE32I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE32UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE4_ALPHA4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE6_ALPHA2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE8I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE8UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE8_ALPHA8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE8_ALPHA8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA16F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA16I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA16UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA32F_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA32I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA32UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA8I_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA8UI_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA_INTEGER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_ALPHA_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_INTEGER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_LUMINANCE_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAD_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAGNITUDE_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAGNITUDE_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAJOR_VERSION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MANUAL_GENERATE_MIPMAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_BINORMAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_TANGENT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB0_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB10_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB11_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB12_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB13_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB14_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB15_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB1_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB2_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB3_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB4_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB5_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB6_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB7_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB8_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP1_VERTEX_ATTRIB9_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_BINORMAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_TANGENT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB0_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB10_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB11_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB12_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB13_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB14_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB15_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB1_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB2_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB3_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB4_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB5_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB6_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB8_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP2_VERTEX_ATTRIB9_4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP_ATTRIB_U_ORDER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP_ATTRIB_V_ORDER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAP_TESSELLATION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATERIAL_SIDE_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX0_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX0_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX10_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX11_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX12_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX13_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX14_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX15_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX16_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX17_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX18_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX19_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX1_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX1_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX20_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX21_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX22_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX23_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX24_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX25_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX26_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX27_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX28_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX29_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX2_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX30_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX31_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX3_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX4_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX5_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX5_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX6_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX6_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX7_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX7_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX8_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX9_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_INDEX_ARRAY_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_INDEX_ARRAY_POINTER_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_INDEX_ARRAY_SIZE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_INDEX_ARRAY_STRIDE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_INDEX_ARRAY_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_PALETTE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MATRIX_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_3D_TEXTURE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_4D_TEXTURE_SIZE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ACTIVE_LIGHTS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ARRAY_TEXTURE_LAYERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ASYNC_DRAW_PIXELS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ASYNC_HISTOGRAM_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ASYNC_READ_PIXELS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ASYNC_TEX_IMAGE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_BINDABLE_UNIFORM_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_CLIPMAP_DEPTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_CLIP_DISTANCES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COLOR_ATTACHMENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COLOR_MATRIX_STACK_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COLOR_TEXTURE_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_DIMENSIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_WORK_GROUP_COUNT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_COMPUTE_WORK_GROUP_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_CONVOLUTION_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_CONVOLUTION_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_CUBE_MAP_TEXTURE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEBUG_GROUP_STACK_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEBUG_LOGGED_MESSAGES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEBUG_MESSAGE_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEFORMATION_ORDER_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DEPTH_TEXTURE_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DRAW_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ELEMENTS_INDICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ELEMENTS_VERTICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_ELEMENT_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FOG_FUNC_POINTS_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_INPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_LIGHTS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAGMENT_UNIFORM_VECTORS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAMEBUFFER_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAMEBUFFER_LAYERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAMEBUFFER_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAMEBUFFER_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_FRAMEZOOM_FACTOR_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GENERAL_COMBINERS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_INPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_OUTPUT_VERTICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_SHADER_INVOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_IMAGE_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_INTEGER_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_LABEL_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_LAYERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_MAP_TESSELLATION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_NAME_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_NUM_ACTIVE_VARIABLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_NUM_COMPATIBLE_SUBROUTINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PALETTE_MATRICES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PATCH_VERTICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_ATTRIBS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_CALL_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_ENV_PARAMETERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_GENERIC_RESULTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_IF_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_LOOP_COUNT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_LOOP_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_MATRICES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_OUTPUT_VERTICES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_PARAMETERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_PATCH_ATTRIBS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_RESULT_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_SUBROUTINE_NUM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TEMPORARIES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TEXEL_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_RATIONAL_EVAL_ORDER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_RECTANGLE_TEXTURE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_RENDERBUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SAMPLE_MASK_WORDS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SERVER_WAIT_TIMEOUT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SHADER_BUFFER_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SHADER_STORAGE_BLOCK_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SHININESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SPARSE_TEXTURE_SIZE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SPOT_EXPONENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SUBROUTINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_INPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_GEN_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TESS_PATCH_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_COORDS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_LOD_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TEXTURE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_UNIFORM_BLOCK_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_UNIFORM_BUFFER_BINDINGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_UNIFORM_LOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VARYING_FLOATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VARYING_VECTORS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ATOMIC_COUNTERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ATTRIBS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ATTRIB_BINDINGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_ATTRIB_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_IMAGE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_OUTPUT_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_SHADER_INVARIANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_SHADER_LOCALS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_SHADER_VARIANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_STREAMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_STREAMS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_UNIFORM_BLOCKS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_UNIFORM_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_UNIFORM_VECTORS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_UNITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VERTEX_VARYING_COMPONENTS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VIEWPORTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_VIEWPORT_DIMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MAX_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MEDIUM_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MEDIUM_INT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MINMAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MINMAX_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MINMAX_SINK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MINOR_VERSION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MINUS_CLAMPED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MINUS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_LOD_WARNING_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_MAP_BUFFER_ALIGNMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_PROGRAM_TEXEL_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_SAMPLE_SHADING_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIN_SPARSE_LEVEL_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIPMAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIRRORED_REPEAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIRROR_CLAMP_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIRROR_CLAMP_TO_BORDER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MIRROR_CLAMP_TO_EDGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MITER_REVERT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MITER_TRUNCATE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW0_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW0_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW0_STACK_DEPTH_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW10_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW11_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW12_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW13_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW14_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW15_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW16_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW17_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW18_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW19_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW1_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW1_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW1_STACK_DEPTH_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW20_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW21_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW22_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW23_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW24_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW25_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW26_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW27_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW28_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW29_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW2_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW30_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW31_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW3_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW4_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW5_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW6_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW7_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW8_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW9_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODELVIEW_PROJECTION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODULATE_ADD_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODULATE_SIGNED_ADD_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MODULATE_SUBTRACT_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MOVE_TO_CONTINUES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MOVE_TO_RESETS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MOV_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MULTIPLY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MULTISAMPLE_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MULTISAMPLE_COVERAGE_MODES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MULTISAMPLE_FILTER_HINT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MUL_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_MVP_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NAMED_STRING_LENGTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NAMED_STRING_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NAME_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NAND) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NATIVE_GRAPHICS_END_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NATIVE_GRAPHICS_HANDLE_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEAREST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEAREST_CLIPMAP_LINEAR_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEAREST_CLIPMAP_NEAREST_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEAREST_MIPMAP_LINEAR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEAREST_MIPMAP_NEAREST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEGATIVE_ONE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEGATIVE_W_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEGATIVE_X_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEGATIVE_Y_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEGATIVE_Z_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEVER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NICEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NOOP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMALIZED_RANGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NORMAL_MAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NOTEQUAL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NO_RESET_NOTIFICATION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_ACTIVE_VARIABLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_COMPATIBLE_SUBROUTINES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_COMPRESSED_TEXTURE_FORMATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_EXTENSIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_FILL_STREAMS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_FRAGMENT_CONSTANTS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_FRAGMENT_REGISTERS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_GENERAL_COMBINERS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_INSTRUCTIONS_PER_PASS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_INSTRUCTIONS_TOTAL_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_LOOPBACK_COMPONENTS_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_PASSES_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_PROGRAM_BINARY_FORMATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_SAMPLE_COUNTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_SHADER_BINARY_FORMATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_SHADING_LANGUAGE_VERSIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_VIDEO_CAPTURE_STREAMS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_NUM_VIRTUAL_PAGE_SIZES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OBJECT_DISTANCE_TO_LINE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OBJECT_DISTANCE_TO_POINT_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OBJECT_LINE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OBJECT_POINT_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OBJECT_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OBJECT_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OCCLUSION_QUERY_EVENT_MASK_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OCCLUSION_TEST_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OCCLUSION_TEST_RESULT_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_HILO_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_TEXTURE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_TEXTURE_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_TEXTURE_MATRIX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_TEXTURE_RECTANGLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OFFSET_TEXTURE_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_CONSTANT_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_CONSTANT_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_DST_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_DST_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_SRC1_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_SRC1_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_SRC_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ONE_MINUS_SRC_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND0_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND0_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND1_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND1_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND2_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND2_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND3_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OPERAND3_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_ADD_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_CLAMP_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_CROSS_PRODUCT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_DOT3_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_DOT4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_EXP_BASE_2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_FLOOR_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_FRAC_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_INDEX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_LOG_BASE_2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_MADD_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_MAX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_MIN_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_MOV_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_MULTIPLY_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_MUL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_NEGATE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_POWER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_RECIP_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_RECIP_SQRT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_ROUND_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_SET_GE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_SET_LT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OP_SUB_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OR_INVERTED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OR_REVERSE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_COLOR0_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_COLOR1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_FOG_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD0_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD10_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD11_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD12_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD13_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD14_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD15_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD16_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD17_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD18_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD19_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD1_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD20_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD21_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD22_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD23_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD24_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD25_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD26_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD27_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD28_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD29_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD30_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD31_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD3_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD4_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD5_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD6_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD7_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD8_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_TEXTURE_COORD9_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUTPUT_VERTEX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OUT_OF_MEMORY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_OVERLAY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_ALIGNMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_CMYK_HINT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_COMPRESSED_BLOCK_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_COMPRESSED_BLOCK_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_COMPRESSED_BLOCK_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_COMPRESSED_BLOCK_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_IMAGE_DEPTH_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_IMAGE_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_INVERT_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_LSB_FIRST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_RESAMPLE_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_RESAMPLE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_ROW_BYTES_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_ROW_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_SKIP_IMAGES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_SKIP_PIXELS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_SKIP_ROWS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_SKIP_VOLUMES_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_SUBSAMPLE_RATE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PACK_SWAP_BYTES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE4_R5_G6_B5_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE4_RGB5_A1_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE4_RGB8_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE4_RGBA4_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE4_RGBA8_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE8_R5_G6_B5_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE8_RGB5_A1_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE8_RGB8_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE8_RGBA4_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PALETTE8_RGBA8_OES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PARALLEL_ARRAYS_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PARAMETER_BUFFER_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PARAMETER_BUFFER_BINDING_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PARTIAL_SUCCESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PASS_THROUGH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATCHES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATCH_DEFAULT_INNER_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATCH_DEFAULT_OUTER_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATCH_VERTICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_CLIENT_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_COMMAND_COUNT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_COMPUTED_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_COORD_COUNT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_COVER_DEPTH_FUNC_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_DASH_ARRAY_COUNT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_DASH_CAPS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_DASH_OFFSET_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_DASH_OFFSET_RESET_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_END_CAPS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_ERROR_POSITION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FILL_BOUNDING_BOX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FILL_COVER_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FILL_MASK_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FILL_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FOG_GEN_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FORMAT_PS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_FORMAT_SVG_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_GEN_COEFF_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_GEN_COLOR_FORMAT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_GEN_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_GEN_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_INITIAL_DASH_CAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_INITIAL_END_CAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_JOIN_STYLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_MITER_LIMIT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_OBJECT_BOUNDING_BOX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STENCIL_FUNC_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STENCIL_REF_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STENCIL_VALUE_MASK_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STROKE_BOUNDING_BOX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STROKE_COVER_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STROKE_MASK_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_STROKE_WIDTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_TERMINAL_DASH_CAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PATH_TERMINAL_END_CAP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERCENTAGE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFMON_RESULT_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFMON_RESULT_AVAILABLE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFMON_RESULT_SIZE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFORMANCE_MONITOR_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_EVENT_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_RAW_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_DONOT_FLUSH_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_FLUSH_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERFQUERY_WAIT_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PERTURB_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PER_STAGE_CONSTANTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PHONG_HINT_WIN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PHONG_WIN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PINLIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_CUBIC_WEIGHT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_GROUP_COLOR_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_MAG_FILTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_MIN_FILTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_PACK_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_PACK_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_SUBSAMPLE_2424_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_SUBSAMPLE_4242_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_SUBSAMPLE_4444_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TEXTURE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TEX_GEN_MODE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TEX_GEN_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_CACHE_INCREMENT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_CACHE_SIZE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_GRID_DEPTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_GRID_HEIGHT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_GRID_WIDTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_HEIGHT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TILE_WIDTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TRANSFORM_2D_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TRANSFORM_2D_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_UNPACK_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PIXEL_UNPACK_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PLUS_CLAMPED_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PLUS_CLAMPED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PLUS_DARKER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PLUS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_NORMAL_MODE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_POINT_MODE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_DISTANCE_ATTENUATION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_FADE_THRESHOLD_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SIZE_GRANULARITY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SIZE_MAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SIZE_MIN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SIZE_RANGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SPRITE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SPRITE_COORD_ORIGIN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POINT_SPRITE_R_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_OFFSET_BIAS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_OFFSET_FACTOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_OFFSET_FILL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_OFFSET_LINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_OFFSET_POINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_OFFSET_UNITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_SMOOTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POLYGON_SMOOTH_HINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_ALPHA_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_ALPHA_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_BLUE_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_BLUE_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_COLOR_TABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_GREEN_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_GREEN_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_RED_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_COLOR_MATRIX_RED_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_ALPHA_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_ALPHA_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_BLUE_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_BLUE_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_COLOR_TABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_GREEN_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_GREEN_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_RED_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_CONVOLUTION_RED_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_TEXTURE_FILTER_BIAS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_POST_TEXTURE_FILTER_SCALE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PREFER_DOUBLEBUFFER_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRESENT_DURATION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRESENT_TIME_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRESERVE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PREVIOUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PREVIOUS_TEXTURE_INPUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMARY_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMARY_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVES_GENERATED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_ID_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_RESTART) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_RESTART_FIXED_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_RESTART_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_RESTART_INDEX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PRIMITIVE_RESTART_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_ADDRESS_REGISTERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_ALU_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_ATTRIBS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_ATTRIB_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_BINARY_FORMATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_BINARY_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_BINARY_RETRIEVABLE_HINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_BINDING_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_ERROR_POSITION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_ERROR_STRING_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_FORMAT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_FORMAT_ASCII_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_INPUT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_LENGTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_MATRIX_STACK_DEPTH_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_ATTRIBS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_PARAMETERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_TEMPORARIES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_OBJECT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_OUTPUT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_PARAMETERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_PARAMETER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_PIPELINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_PIPELINE_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_PIPELINE_OBJECT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_RESIDENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_RESULT_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_SEPARABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_STRING_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_TARGET_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_TEMPORARIES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_TEX_INDIRECTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_TEX_INSTRUCTIONS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROVOKING_VERTEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_COLOR_TABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_HISTOGRAM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_POST_CONVOLUTION_COLOR_TABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_1D_STACK_MESAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_2D_STACK_MESAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_4D_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_COLOR_TABLE_SGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_CUBE_MAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PROXY_TEXTURE_RECTANGLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_PURGEABLE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUADS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_ALPHA4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_ALPHA8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_INTENSITY4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_INTENSITY8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_LUMINANCE4_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_LUMINANCE8_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_MESH_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUAD_TEXTURE_SELECT_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_BY_REGION_NO_WAIT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_BY_REGION_WAIT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_COUNTER_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_NO_WAIT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_OBJECT_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_RESULT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_RESULT_AVAILABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_RESULT_NO_WAIT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_QUERY_WAIT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R11F_G11F_B10F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R16F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R16I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R16UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_C3F_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_C4F_N3F_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_C4UB_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_N3F_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_T2F_C4F_N3F_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_T2F_N3F_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_T2F_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R1UI_V3F_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R32F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R32I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R32UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R3_G3_B2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R8I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R8UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_R8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RASTERIZER_DISCARD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RASTER_POSITION_UNCLIPPED_IBM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_FRAMEBUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_FRAMEBUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_ONLY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_PIXELS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_PIXELS_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_PIXELS_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_PIXEL_DATA_RANGE_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_PIXEL_DATA_RANGE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_PIXEL_DATA_RANGE_POINTER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_READ_WRITE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RECLAIM_MEMORY_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REDUCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RED_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RED_MAX_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RED_MIN_CLAMP_INGR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RED_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCED_BY_COMPUTE_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCED_BY_FRAGMENT_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCED_BY_GEOMETRY_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCED_BY_TESS_CONTROL_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCED_BY_TESS_EVALUATION_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCED_BY_VERTEX_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCE_PLANE_EQUATION_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFERENCE_PLANE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REFLECTION_MAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REGISTER_COMBINERS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_0_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_10_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_11_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_12_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_13_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_14_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_15_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_16_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_17_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_18_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_19_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_1_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_20_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_21_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_22_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_23_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_24_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_25_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_26_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_27_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_28_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_29_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_2_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_30_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_31_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_3_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_4_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_5_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_6_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_7_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_8_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REG_9_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RELEASED_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_ALPHA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_BLUE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_COLOR_SAMPLES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_DEPTH_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_FREE_MEMORY_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_GREEN_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_INTERNAL_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_RED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_STENCIL_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERBUFFER_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RENDERER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPEAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACEMENT_CODE_ARRAY_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACEMENT_CODE_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLACE_VALUE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_REPLICATE_BORDER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_AVERAGE_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_DECIMATE_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_DECIMATE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_REPLICATE_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_REPLICATE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_ZERO_FILL_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESAMPLE_ZERO_FILL_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESCALE_NORMAL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RESET_NOTIFICATION_STRATEGY_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RETAINED_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG16F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG16I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG16UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG32F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG32I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG32UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG8I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG8UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB10) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB10_A2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB10_A2UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB12) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB16F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB16I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB16UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB2_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB32F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB32I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB32UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB4_S3TC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB565) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB5_A1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB8I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB8UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB9_E5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA12) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA16F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA16I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA16UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA16_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA32F) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA32I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA32UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA4_DXT5_S3TC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA4_S3TC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA8I) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA8UI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA8_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_DXT5_S3TC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_FLOAT_MODE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_INTEGER_MODE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_S3TC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_SIGNED_COMPONENTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB_422_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB_RAW_422_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB_S3TC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB_SCALE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RGB_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RG_SNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_RIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ROUND_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_1D_ARRAY_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_1D_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_ARRAY_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_RECT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_RECT_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_2D_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_BUFFER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_CUBE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_CUBE_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_OBJECT_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLER_RENDERBUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLES_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLES_PASSED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_ALPHA_TO_COVERAGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_ALPHA_TO_ONE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_BUFFERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_BUFFERS_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_COVERAGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_COVERAGE_INVERT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_COVERAGE_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_MASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_MASK_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_PATTERN_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_POSITION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SAMPLE_SHADING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALAR_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALEBIAS_HINT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALED_RESOLVE_FASTEST_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALED_RESOLVE_NICEST_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALE_BY_FOUR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALE_BY_ONE_HALF_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCALE_BY_TWO_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCISSOR_BOX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCISSOR_TEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCREEN_COORDINATES_REND) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SCREEN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_POINTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_ARRAY_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SECONDARY_INTERPOLATOR_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SEPARABLE_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SEPARATE_ATTRIBS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SEPARATE_SPECULAR_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SET_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_BINARY_FORMATS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_COMPILER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_CONSISTENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_IMAGE_ATOMIC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_IMAGE_LOAD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_IMAGE_STORE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_INCLUDE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_OBJECT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_OPERATION_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_SOURCE_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_STORAGE_BLOCK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_STORAGE_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_STORAGE_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_STORAGE_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_STORAGE_BUFFER_START) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADER_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADING_LANGUAGE_VERSION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHADOW_ATTENUATION_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHARED_TEXTURE_PALETTE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SHORT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNALED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_ALPHA8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_HILO16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_HILO8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_HILO_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_IDENTITY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_INTENSITY8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_INTENSITY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_LUMINANCE8_ALPHA8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_LUMINANCE8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_LUMINANCE_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_LUMINANCE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_NEGATE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_NORMALIZED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_RGB8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_RGBA8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIGNED_RGB_UNSIGNED_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SINGLE_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SKIP_DECODE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SKIP_MISSING_GLYPH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SLICE_ACCUM_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SLUMINANCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SLUMINANCE8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SLUMINANCE8_ALPHA8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SLUMINANCE_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SM_COUNT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOFTLIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE0_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE0_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE1_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE2_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE2_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE3_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SOURCE3_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPARE0_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPARE0_PLUS_SECONDARY_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPARE1_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_AXIAL_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_AXIS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_EYE_ALIGNED_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_MODE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_OBJECT_ALIGNED_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SPRITE_TRANSLATION_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SQUARE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC1_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC1_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_ALPHA_SATURATE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_ATOP_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_IN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_OUT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRC_OVER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB8_ALPHA8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB_ALPHA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB_DECODE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB_READ) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SRGB_WRITE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STACK_OVERFLOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STACK_UNDERFLOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STANDARD_FONT_NAME_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STATIC_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STATIC_COPY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STATIC_DRAW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STATIC_READ) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_ATTACHMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_FAIL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_FUNC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_OP_VALUE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_PASS_DEPTH_FAIL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_PASS_DEPTH_PASS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_REF) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_VALUE_MASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_BACK_WRITEMASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_CLEAR_TAG_VALUE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_CLEAR_VALUE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_COMPONENTS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_FAIL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_FUNC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_INDEX1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_INDEX16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_INDEX4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_INDEX8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_OP_VALUE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_PASS_DEPTH_FAIL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_PASS_DEPTH_PASS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_REF) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_RENDERABLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_TAG_BITS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_TEST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_TEST_TWO_SIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_VALUE_MASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STENCIL_WRITEMASK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STEREO) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STORAGE_CACHED_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STORAGE_CLIENT_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STORAGE_PRIVATE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STORAGE_SHARED_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STREAM_COPY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STREAM_DRAW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STREAM_RASTERIZATION_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STREAM_READ) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STRICT_DEPTHFUNC_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STRICT_LIGHTING_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_STRICT_SCISSOR_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SUBPIXEL_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SUBSAMPLE_DISTANCE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SUBTRACT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SUB_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SUCCESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SURFACE_MAPPED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SURFACE_REGISTERED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SURFACE_STATE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SWIZZLE_STQ_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SWIZZLE_STQ_DQ_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SWIZZLE_STRQ_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SWIZZLE_STRQ_DQ_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SWIZZLE_STR_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SWIZZLE_STR_DR_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_CL_EVENT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_CL_EVENT_COMPLETE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_CONDITION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_FENCE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_FLAGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_GPU_COMMANDS_COMPLETE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_STATUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYNC_X11_FENCE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_SYSTEM_FONT_NAME_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_T2F_IUI_N3F_V2F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_T2F_IUI_N3F_V3F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_T2F_IUI_V2F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_T2F_IUI_V3F_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TABLE_TOO_LARGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TANGENT_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TANGENT_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TANGENT_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TANGENT_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESSELLATION_FACTOR_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESSELLATION_MODE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_OUTPUT_VERTICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_PROGRAM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_SUBROUTINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_SUBROUTINE_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_CONTROL_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_EVALUATION_PROGRAM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_EVALUATION_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_EVALUATION_SUBROUTINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_EVALUATION_SUBROUTINE_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_EVALUATION_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_GEN_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_GEN_POINT_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_GEN_SPACING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TESS_GEN_VERTEX_ORDER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE0) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE10) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE11) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE12) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE13) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE14) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE15) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE16) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE17) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE18) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE19) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE20) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE21) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE22) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE23) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE24) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE25) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE26) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE27) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE28) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE29) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE30) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE31) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE6) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE7) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE9) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_1D_STACK_BINDING_MESAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_1D_STACK_MESAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_2D_STACK_BINDING_MESAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_2D_STACK_MESAX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_4DSIZE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_4D_BINDING_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_4D_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_ALPHA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_ALPHA_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_APPLICATION_MODE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BASE_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_CUBE_MAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_RECTANGLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BINDING_RENDERBUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BLUE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BLUE_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BORDER_COLOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BORDER_VALUES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BUFFER_DATA_STORE_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BUFFER_FORMAT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BUFFER_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CLIPMAP_CENTER_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CLIPMAP_DEPTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CLIPMAP_FRAME_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CLIPMAP_OFFSET_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COLOR_SAMPLES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COLOR_TABLE_SGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COLOR_WRITEMASK_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPARE_FAIL_VALUE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPARE_FUNC) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPARE_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPARE_OPERATOR_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPARE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPRESSED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPRESSED_BLOCK_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPRESSED_BLOCK_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPRESSED_IMAGE_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COMPRESSION_HINT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CONSTANT_DATA_SUNX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COORD_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_COVERAGE_SAMPLES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_X) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_X) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_Y) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_Z) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_CUBE_MAP_SEAMLESS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_DEFORMATION_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_DEPTH_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_DEPTH_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_DS_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_DT_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_ENV_BIAS_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_FILTER4_SIZE_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_FILTER_CONTROL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_FLOAT_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_FREE_MEMORY_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_GATHER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_GATHER_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_GEQUAL_R_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_GREEN_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_GREEN_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_HI_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_IMAGE_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_IMAGE_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_IMMUTABLE_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_IMMUTABLE_LEVELS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_INDEX_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_INTENSITY_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_INTENSITY_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_INTERNAL_FORMAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LEQUAL_R_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LIGHTING_MODE_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LIGHT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LOD_BIAS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LOD_BIAS_R_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LOD_BIAS_S_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LOD_BIAS_T_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LO_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LUMINANCE_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_LUMINANCE_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAG_FILTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAG_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MATERIAL_FACE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MATERIAL_PARAMETER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAX_ANISOTROPY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAX_CLAMP_R_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAX_CLAMP_S_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAX_CLAMP_T_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAX_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MAX_LOD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MEMORY_LAYOUT_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MIN_FILTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MIN_LOD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_MULTI_BUFFER_HINT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_NORMAL_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_POST_SPECULAR_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_PRE_SPECULAR_HP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_PRIORITY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RANGE_LENGTH_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RANGE_POINTER_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RECTANGLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RED_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RENDERBUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_RESIDENT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SAMPLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SHADER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SHADOW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SHARED_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SPARSE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SRGB_DECODE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_STENCIL_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_STORAGE_HINT_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SWIZZLE_A) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SWIZZLE_B) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SWIZZLE_G) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SWIZZLE_R) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_SWIZZLE_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_TOO_LARGE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_UNSIGNED_REMAP_MODE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_VIEW) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_VIEW_MIN_LAYER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_VIEW_MIN_LEVEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_VIEW_NUM_LAYERS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_VIEW_NUM_LEVELS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_WRAP_Q_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_WRAP_R) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_WRAP_S) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXTURE_WRAP_T) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TEXT_FRAGMENT_SHADER_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TIMEOUT_EXPIRED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TIMESTAMP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TIME_ELAPSED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TOP_LEVEL_ARRAY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TOP_LEVEL_ARRAY_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRACK_MATRIX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRACK_MATRIX_TRANSFORM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_ATTRIBS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_MODE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_START) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_RECORD_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_VARYING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_VARYINGS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSFORM_HINT_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSLATE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSLATE_3D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSLATE_X_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSLATE_Y_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_AFFINE_2D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_AFFINE_3D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_COLOR_MATRIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_CURRENT_MATRIX_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_MODELVIEW_MATRIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_PROGRAM_MATRIX_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_PROJECTION_MATRIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRANSPOSE_TEXTURE_MATRIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLES_ADJACENCY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLE_FAN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLE_LIST_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLE_MESH_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLE_STRIP) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGLE_STRIP_ADJACENCY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TRIANGULAR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNCORRELATED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNDEFINED_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNDEFINED_VERTEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_ARRAY_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_DATA_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_INDEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_NAME_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER_BINDING_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_BUFFER_START) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_IS_ROW_MAJOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_MATRIX_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_NAME_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNIFORM_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNKNOWN_CONTEXT_RESET_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_ALIGNMENT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_CLIENT_STORAGE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_CMYK_HINT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_COMPRESSED_BLOCK_DEPTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_COMPRESSED_BLOCK_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_COMPRESSED_BLOCK_WIDTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_CONSTANT_DATA_SUNX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_IMAGE_DEPTH_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_IMAGE_HEIGHT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_LSB_FIRST) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_RESAMPLE_OML) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_RESAMPLE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_ROW_BYTES_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_ROW_LENGTH) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_SKIP_IMAGES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_SKIP_PIXELS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_SKIP_ROWS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_SKIP_VOLUMES_SGIS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_SUBSAMPLE_RATE_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNPACK_SWAP_BYTES) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNALED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_BYTE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_BYTE_2_3_3_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_BYTE_3_3_2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_IDENTITY_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT16_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT16_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT16_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT64_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT64_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT64_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT64_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT64_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT8_VEC2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT8_VEC3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT8_VEC4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_10F_11F_11F_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_10_10_10_2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_24_8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_2_10_10_10_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_5_9_9_9_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_8_8_8_8) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_8_8_8_8_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_8_8_S8_S8_REV_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_ATOMIC_COUNTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_2D_RECT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_CUBE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_S8_S8_8_8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_1D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_1D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_2D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_2D_RECT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_3D) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_CUBE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_VEC2) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_VEC3) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INT_VEC4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_INVERT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_NORMALIZED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_1_5_5_5_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_4_4_4_4) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_4_4_4_4_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_5_5_5_1) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_5_6_5) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_5_6_5_REV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_8_8_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UNSIGNED_SHORT_8_8_REV_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UPPER_LEFT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_USE_MISSING_GLYPH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UTF16_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_UTF8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VALIDATE_STATUS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_A_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_B_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_C_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_D_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_E_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_F_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIABLE_G_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_DATATYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VARIANT_VALUE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VBO_FREE_MEMORY_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VECTOR_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VENDOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERSION) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_COUNT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_OBJECT_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_RANGE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_RANGE_POINTER_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_STORAGE_HINT_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY0_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY10_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY11_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY12_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY13_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY14_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY15_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY1_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY2_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY3_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY4_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY5_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY6_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY7_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY8_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY9_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_DIVISOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_ENABLED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_INTEGER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_LONG) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_POINTER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_TYPE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP1_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP2_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ATTRIB_RELATIVE_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_BINDING_BUFFER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_BINDING_DIVISOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_BINDING_OFFSET) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_BINDING_STRIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_BLEND_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_CONSISTENT_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_DATA_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ELEMENT_SWIZZLE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ID_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_ID_SWIZZLE_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PRECLIP_HINT_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PRECLIP_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PROGRAM_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PROGRAM_BINDING_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PROGRAM_POINT_SIZE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_PROGRAM_TWO_SIDE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_BINDING_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_INSTRUCTIONS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_INVARIANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_LOCALS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_OPTIMIZED_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SHADER_VARIANTS_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SOURCE_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STATE_PROGRAM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM0_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM1_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM2_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM3_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM4_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM5_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM6_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_STREAM7_ATI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SUBROUTINE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_SUBROUTINE_UNIFORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_TEXTURE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_WEIGHTING_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_WEIGHT_ARRAY_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIBRANCE_BIAS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIBRANCE_SCALE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_BUFFER_BINDING_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_BUFFER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_BUFFER_PITCH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_CAPTURE_FRAME_WIDTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_COLOR_CONVERSION_MATRIX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_COLOR_CONVERSION_MAX_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_COLOR_CONVERSION_MIN_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIDEO_COLOR_CONVERSION_OFFSET_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEWPORT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEWPORT_BOUNDS_RANGE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEWPORT_INDEX_PROVOKING_VERTEX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEWPORT_SUBPIXEL_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_128_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_16_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_24_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_32_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_48_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_64_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_8_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_96_BITS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_BPTC_FLOAT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_BPTC_UNORM) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_RGTC1_RED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_RGTC2_RG) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_S3TC_DXT1_RGB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_S3TC_DXT1_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_S3TC_DXT3_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_CLASS_S3TC_DXT5_RGBA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIEW_COMPATIBILITY_CLASS) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIRTUAL_PAGE_SIZE_INDEX_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIRTUAL_PAGE_SIZE_X_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIRTUAL_PAGE_SIZE_Y_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIRTUAL_PAGE_SIZE_Z_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VIVIDLIGHT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_VOLATILE_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WAIT_FAILED) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WARPS_PER_SM_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WARP_SIZE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_ARRAY_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_ARRAY_BUFFER_BINDING) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_ARRAY_POINTER_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_ARRAY_SIZE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_ARRAY_STRIDE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_ARRAY_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WEIGHT_SUM_UNITY_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WIDE_LINE_HINT_PGI) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WRAP_BORDER_SUN) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WRITE_DISCARD_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WRITE_ONLY) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WRITE_PIXEL_DATA_RANGE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_W_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_XOR) + TOSTR_CASE_STRINGIZE_GLENUM(GL_X_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCBAYCR8A_4224_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCBCR_422_APPLE) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCBCR_MESA) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCBYCR8_422_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCRCBA_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCRCB_422_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCRCB_444_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_YCRCB_SGIX) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Y_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Z4Y12Z4CB12Z4CR12_444_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV) + TOSTR_CASE_STRINGIZE_GLENUM(GL_ZERO_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(GL_Z_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ACCELERATION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ACCUM_ALPHA_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ACCUM_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ACCUM_BLUE_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ACCUM_GREEN_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ACCUM_RED_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ALPHA_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_ALPHA_SHIFT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX0_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX1_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX2_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX3_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX4_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX5_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX6_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX7_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX8_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX9_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_AUX_BUFFERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BACK_LEFT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BACK_RIGHT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RGBA_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_TEXTURE_RGB_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_VIDEO_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BIND_TO_VIDEO_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BLUE_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_BLUE_SHIFT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_COLOR_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_COLOR_SAMPLES_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_CONTEXT_FLAGS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_CONTEXT_LAYER_PLANE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_CONTEXT_MAJOR_VERSION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_CONTEXT_MINOR_VERSION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_CUBE_MAP_FACE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DEPTH_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DEPTH_COMPONENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DEPTH_FLOAT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DEPTH_TEXTURE_FORMAT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DOUBLE_BUFFER_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DRAW_TO_BITMAP_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DRAW_TO_PBUFFER_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_DRAW_TO_WINDOW_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_FLOAT_COMPONENTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_FRONT_LEFT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_FRONT_RIGHT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_FULL_ACCELERATION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GAMMA_EXCLUDE_DESKTOP_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GAMMA_TABLE_SIZE_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENERIC_ACCELERATION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_EDGE_RISING_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GENLOCK_SOURCE_MULTIVIEW_I3D) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_CLOCK_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_FASTEST_TARGET_GPUS_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_NUM_PIPES_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_NUM_RB_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_NUM_SIMD_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_NUM_SPI_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GPU_RAM_AMD) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GREEN_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_GREEN_SHIFT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_MAX_PBUFFER_HEIGHT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_MAX_PBUFFER_PIXELS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_MAX_PBUFFER_WIDTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_MIPMAP_LEVEL_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_MIPMAP_TEXTURE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NEED_PALETTE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NEED_SYSTEM_PALETTE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NO_ACCELERATION_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NO_TEXTURE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NUMBER_OVERLAYS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NUMBER_PIXEL_FORMATS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NUMBER_UNDERLAYS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NUM_VIDEO_CAPTURE_SLOTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_NUM_VIDEO_SLOTS_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_OPTIMAL_PBUFFER_HEIGHT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_OPTIMAL_PBUFFER_WIDTH_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_PBUFFER_HEIGHT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_PBUFFER_LARGEST_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_PBUFFER_LOST_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_PBUFFER_WIDTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_PIXEL_TYPE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_RED_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_RED_SHIFT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SAMPLES_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SAMPLES_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SAMPLE_BUFFERS_3DFX) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SAMPLE_BUFFERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SHARE_ACCUM_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SHARE_DEPTH_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SHARE_STENCIL_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_STENCIL_BITS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_STEREO_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_STEREO_EMITTER_DISABLE_3DL) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_STEREO_EMITTER_ENABLE_3DL) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_STEREO_POLARITY_INVERT_3DL) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_STEREO_POLARITY_NORMAL_3DL) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SUPPORT_GDI_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SUPPORT_OPENGL_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SWAP_COPY_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SWAP_EXCHANGE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SWAP_LAYER_BUFFERS_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SWAP_METHOD_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_SWAP_UNDEFINED_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_1D_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_2D_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_DEPTH_COMPONENT_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_FLOAT_RGBA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_FLOAT_RGB_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_FLOAT_RG_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_FLOAT_R_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_FORMAT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_RECTANGLE_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_RGBA_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_RGB_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TEXTURE_TARGET_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_ALPHA_VALUE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_BLUE_VALUE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_GREEN_VALUE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_INDEX_VALUE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_RED_VALUE_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TRANSPARENT_VALUE_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TYPE_COLORINDEX_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TYPE_RGBA_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TYPE_RGBA_FLOAT_ARB) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_UNIQUE_ID_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_COLOR_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_DEPTH_NV) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_FIELD_1) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_FIELD_2) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_FRAME) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_STACKED_FIELDS_1_2) + TOSTR_CASE_STRINGIZE_GLENUM(WGL_VIDEO_OUT_STACKED_FIELDS_2_1) + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "GLenum<%x>", (uint32_t)el); + + return tostrBuf; + +#define GLenum RDCGLenum +} diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h new file mode 100644 index 0000000000..cbc7505b1e --- /dev/null +++ b/renderdoc/driver/gl/gl_common.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +// typed enum so that templates will pick up specialisations +#define GLenum RDCGLenum + +#include "gl_enum.h" + +#include "official/glcorearb.h" +#include "official/glext.h" + +#if defined(WIN32) +#include "official/wglext.h" + +struct GLWindowingData +{ + HDC DC; + HGLRC RC; + HWND wnd; +}; + +#elif defined(LINUX) +// cheeky way to prevent GL/gl.h from being included, as we want to use +// glcorearb.h from above +#define __gl_h_ +#include + +#include "official/glxext.h" + +struct GLWindowingData +{ + Display *dpy; + GLXContext ctx; + GLXDrawable wnd; +}; + +#else +#error "Unknown platform" +#endif + +#include "replay/renderdoc.h" + +#define GLNOTIMP(...) RDCDEBUG("OpenGL not implemented - " __VA_ARGS__) + +#define IMPLEMENT_FUNCTION_SERIALISED(ret, func) ret func; bool CONCAT(Serialise_, func); + +class WrappedOpenGL; + +ResourceFormat MakeResourceFormat(WrappedOpenGL &gl, GLenum target, GLenum fmt); +GLenum MakeGLFormat(WrappedOpenGL &gl, GLenum target, ResourceFormat fmt); + +#include "serialise/serialiser.h" +#include "core/core.h" + +enum GLChunkType +{ + DEVICE_INIT = FIRST_CHUNK_ID, + + GEN_TEXTURE, + BIND_TEXTURE, + TEXSTORAGE2D, + TEXSUBIMAGE2D, + PIXELSTORE, + TEXPARAMETERI, + GENERATE_MIPMAP, + + CREATE_SHADER, + CREATE_PROGRAM, + COMPILESHADER, + SHADERSOURCE, + ATTACHSHADER, + LINKPROGRAM, + + // legacy/immediate mode chunks + LIGHTFV, + MATERIALFV, + GENLISTS, + NEWLIST, + ENDLIST, + CALLLIST, + SHADEMODEL, + BEGIN, + END, + VERTEX3F, + NORMAL3F, + PUSHMATRIX, + POPMATRIX, + MATRIXMODE, + LOADIDENTITY, + FRUSTUM, + TRANSLATEF, + ROTATEF, + // + + CLEAR, + CLEARBUFFERF, + ENABLE, + DISABLE, + DEPTH_FUNC, + VIEWPORT, + USEPROGRAM, + BINDVERTEXARRAY, + UNIFORM_MATRIX, + UNIFORM_VECTOR, + DRAWARRAYS, + DRAWARRAYS_INSTANCEDBASEDINSTANCE, + + GEN_FRAMEBUFFERS, + FRAMEBUFFER_TEX, + + GEN_BUFFER, + BIND_BUFFER, + BUFFERDATA, + GEN_VERTEXARRAY, + BIND_VERTEXARRAY, + VERTEXATTRIBPOINTER, + ENABLEVERTEXATTRIBARRAY, + DELETE_VERTEXARRAY, + DELETE_BUFFER, + + OBJECT_LABEL, + BEGIN_EVENT, + SET_MARKER, + END_EVENT, + + CAPTURE_SCOPE, + CONTEXT_CAPTURE_HEADER, + CONTEXT_CAPTURE_FOOTER, + + NUM_OPENGL_CHUNKS, +}; diff --git a/renderdoc/driver/gl/gl_context_driver.cpp b/renderdoc/driver/gl/gl_context_driver.cpp new file mode 100644 index 0000000000..6fc4b3fbd1 --- /dev/null +++ b/renderdoc/driver/gl/gl_context_driver.cpp @@ -0,0 +1,1006 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" +#include "common/string_utils.h" +#include "gl_driver.h" + +#pragma region State functions + +void WrappedOpenGL::glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + m_Real.glBlendFunc(sfactor, dfactor); + + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } +} + +void WrappedOpenGL::glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + m_Real.glClearColor(red, green, blue, alpha); + + RDCUNIMPLEMENTED(); +} + +void WrappedOpenGL::glClearDepth(GLclampd depth) +{ + m_Real.glClearDepth(depth); + + RDCUNIMPLEMENTED(); +} + +bool WrappedOpenGL::Serialise_glDepthFunc(GLenum func) +{ + SERIALISE_ELEMENT(GLenum, f, func); + + if(m_State <= EXECUTING) + { + m_Real.glDepthFunc(func); + } + + return true; +} + +void WrappedOpenGL::glDepthFunc(GLenum func) +{ + m_Real.glDepthFunc(func); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DEPTH_FUNC); + Serialise_glDepthFunc(func); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glDisable(GLenum cap) +{ + SERIALISE_ELEMENT(GLenum, c, cap); + + if(m_State <= EXECUTING) + { + m_Real.glDisable(c); + } + + return true; +} + +void WrappedOpenGL::glDisable(GLenum cap) +{ + m_Real.glDisable(cap); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DISABLE); + Serialise_glDisable(cap); + + m_ContextRecord->AddChunk(scope.Get()); + } + if(m_State == WRITING_IDLE) + { + SCOPED_SERIALISE_CONTEXT(DISABLE); + Serialise_glDisable(cap); + + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glEnable(GLenum cap) +{ + SERIALISE_ELEMENT(GLenum, c, cap); + + if(m_State <= EXECUTING) + { + m_Real.glEnable(c); + } + + return true; +} + +void WrappedOpenGL::glEnable(GLenum cap) +{ + m_Real.glEnable(cap); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(ENABLE); + Serialise_glEnable(cap); + + m_ContextRecord->AddChunk(scope.Get()); + } + if(m_State == WRITING_IDLE) + { + SCOPED_SERIALISE_CONTEXT(ENABLE); + Serialise_glEnable(cap); + + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glHint(GLenum target, GLenum mode) +{ + m_Real.glHint(target, mode); + + RDCUNIMPLEMENTED(); +} + +bool WrappedOpenGL::Serialise_glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SERIALISE_ELEMENT(GLint, X, x); + SERIALISE_ELEMENT(GLint, Y, y); + SERIALISE_ELEMENT(GLint, W, width); + SERIALISE_ELEMENT(GLint, H, height); + + if(m_State <= EXECUTING) + { + m_Real.glViewport(X, Y, W, H); + } + + return true; +} + +void WrappedOpenGL::glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + m_Real.glViewport(x, y, width, height); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(VIEWPORT); + Serialise_glViewport(x, y, width, height); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glPolygonMode(GLenum face, GLenum mode) +{ + m_Real.glPolygonMode(face, mode); +} + +void WrappedOpenGL::glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + if(framebuffer == 0 && (m_State == READING || m_State == EXECUTING)) + framebuffer = m_FakeBB_FBO; + + m_Real.glBindFramebuffer(target, framebuffer); +} + +#pragma endregion + +#pragma region Debugging annotation + +void WrappedOpenGL::glGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) +{ + m_Real.glGetObjectLabel(identifier, name, bufSize, length, label); +} + +bool WrappedOpenGL::Serialise_glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) +{ + ResourceId liveid; + + string Label; + if(m_State >= WRITING) + { + if(length == 0) + Label = ""; + else + Label = string(label, label + (length > 0 ? length : strlen(label))); + + switch(identifier) + { + case eGL_TEXTURE: + liveid = GetResourceManager()->GetID(TextureRes(name)); + break; + case eGL_BUFFER: + liveid = GetResourceManager()->GetID(BufferRes(name)); + break; + default: + RDCERR("Unhandled namespace in glObjectLabel"); + } + } + + SERIALISE_ELEMENT(GLenum, Identifier, identifier); + SERIALISE_ELEMENT(ResourceId, id, liveid); + SERIALISE_ELEMENT(GLsizei, Length, length); + SERIALISE_ELEMENT(bool, HasLabel, label != NULL); + + m_pSerialiser->SerialiseString("label", Label); + + if(m_State == READING) + { + GLResource res = GetResourceManager()->GetLiveResource(id); + m_Real.glObjectLabel(Identifier, res.name, Length, HasLabel ? Label.c_str() : NULL); + } + + return true; +} + +void WrappedOpenGL::glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) +{ + m_Real.glObjectLabel(identifier, name, length, label); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(OBJECT_LABEL); + Serialise_glObjectLabel(identifier, name, length, label); + + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +#pragma endregion + +#pragma region Drawcalls + +bool WrappedOpenGL::Serialise_glDrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) +{ + SERIALISE_ELEMENT(GLenum, Mode, mode); + SERIALISE_ELEMENT(GLint, First, first); + SERIALISE_ELEMENT(GLsizei, Count, count); + SERIALISE_ELEMENT(GLsizei, InstanceCount, instancecount); + SERIALISE_ELEMENT(GLuint, BaseInstance, baseinstance); + + if(m_State <= EXECUTING) + { + m_Real.glDrawArraysInstancedBaseInstance(Mode, First, Count, InstanceCount, BaseInstance); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + AddEvent(DRAWARRAYS_INSTANCEDBASEDINSTANCE, desc); + string name = "glDrawArraysInstancedBaseInstance(" + + ToStr::Get(Mode) + ", " + + ToStr::Get(First) + ", " + + ToStr::Get(Count) + ", " + + ToStr::Get(InstanceCount) + ", " + + ToStr::Get(BaseInstance) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = Count; + draw.numInstances = InstanceCount; + draw.indexOffset = First; + draw.vertexOffset = 0; + draw.instanceOffset = BaseInstance; + + draw.flags |= eDraw_Drawcall|eDraw_Instanced; + + m_LastDrawMode = Mode; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedOpenGL::glDrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) +{ + m_Real.glDrawArraysInstancedBaseInstance(mode, first, count, instancecount, baseinstance); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAWARRAYS_INSTANCEDBASEDINSTANCE); + Serialise_glDrawArraysInstancedBaseInstance(mode, first, count, instancecount, baseinstance); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + SERIALISE_ELEMENT(GLenum, Mode, mode); + SERIALISE_ELEMENT(GLint, First, first); + SERIALISE_ELEMENT(GLsizei, Count, count); + + if(m_State <= EXECUTING) + { + m_Real.glDrawArrays(Mode, First, Count); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + AddEvent(DRAWARRAYS, desc); + string name = "glDrawArrays(" + + ToStr::Get(Mode) + ", " + + ToStr::Get(First) + ", " + + ToStr::Get(Count) + ", " + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.numIndices = Count; + draw.numInstances = 1; + draw.indexOffset = First; + draw.vertexOffset = 0; + draw.instanceOffset = 0; + + draw.flags |= eDraw_Drawcall|eDraw_Instanced; + + m_LastDrawMode = Mode; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedOpenGL::glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + m_Real.glDrawArrays(mode, first, count); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAWARRAYS); + Serialise_glDrawArrays(mode, first, count); + + m_ContextRecord->AddChunk(scope.Get()); + } +} +bool WrappedOpenGL::Serialise_glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) +{ + SERIALISE_ELEMENT(GLenum, buf, buffer); + SERIALISE_ELEMENT(GLint, draw, drawbuffer); + + if(buf != eGL_DEPTH && buf != eGL_STENCIL) + { + Vec4f v; + if(value) v = *((Vec4f *)value); + + m_pSerialiser->Serialise<4>("value", (float *)&v.x); + + if(m_State <= EXECUTING) + m_Real.glClearBufferfv(buf, draw, &v.x); + } + else + { + SERIALISE_ELEMENT(GLfloat, val, *value); + + if(m_State <= EXECUTING) + m_Real.glClearBufferfv(buf, draw, &val); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + AddEvent(CLEARBUFFERF, desc); + string name = "glClearBufferfv(" + + ToStr::Get(buf) + ", " + + ToStr::Get(draw) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Clear; + + AddDrawcall(draw, true); + } + + + return true; +} + +void WrappedOpenGL::glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) +{ + m_Real.glClearBufferfv(buffer, drawbuffer, value); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEARBUFFERF); + Serialise_glClearBufferfv(buffer, drawbuffer, value); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glClear(GLbitfield mask) +{ + SERIALISE_ELEMENT(GLbitfield, Mask, mask); + + if(m_State <= EXECUTING) + m_Real.glClear(Mask); + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + AddEvent(CLEARBUFFERF, desc); + string name = "glClear("; + if(Mask & GL_DEPTH_BUFFER_BIT) + name += "GL_DEPTH_BUFFER_BIT | "; + if(Mask & GL_COLOR_BUFFER_BIT) + name += "GL_COLOR_BUFFER_BIT | "; + if(Mask & GL_STENCIL_BUFFER_BIT) + name += "GL_STENCIL_BUFFER_BIT | "; + + if(Mask & (eGL_DEPTH_BUFFER_BIT|eGL_COLOR_BUFFER_BIT|eGL_STENCIL_BUFFER_BIT)) + { + name.pop_back(); // ' ' + name.pop_back(); // '|' + name.pop_back(); // ' ' + } + + name += ")"; + + FetchDrawcall draw; + draw.name = widen(name); + draw.flags |= eDraw_Clear; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedOpenGL::glClear(GLbitfield mask) +{ + m_Real.glClear(mask); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CLEAR); + Serialise_glClear(mask); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +#pragma endregion + +// most of this is just hacks to get glxgears working :) + +#pragma region Legacy/Immediate mode + +bool WrappedOpenGL::Serialise_glGenLists(GLsizei range) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(DisplayListRes((GLuint)range))); + + if(m_State == READING) + { + GLuint real = m_Real.glGenLists(1); + + GLResource res = DisplayListRes(real); + + ResourceId live = m_ResourceManager->RegisterResource(res); + GetResourceManager()->AddLiveResource(id, res); + } + + return true; +} + +GLuint WrappedOpenGL::glGenLists(GLsizei range) +{ + GLuint listret = m_Real.glGenLists(range); + + RDCASSERT(range == 1); // assumption from glxgears. + + for(GLsizei i=0; i < range; i++) + { + GLResource res = DisplayListRes(listret+i); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(GENLISTS); + Serialise_glGenLists((GLsizei)(listret+i)); + + chunk = scope.Get(); + } + + GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + } + + return listret; +} + +bool WrappedOpenGL::Serialise_glLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ + SERIALISE_ELEMENT(GLenum, Light, light); + SERIALISE_ELEMENT(GLenum, Name, pname); + + Vec4f v; + if(params) v = *((Vec4f *)params); + + m_pSerialiser->Serialise<4>("params", (float *)&v.x); + + if(m_State <= EXECUTING) + m_Real.glLightfv(Light, Name, &v.x); + + return true; +} + +void WrappedOpenGL::glLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ + RDCASSERT(pname == (GLenum)0x1203 /*eGL_POSITION*/); // assumption from glxgears. + + m_Real.glLightfv(light, pname, params); + + { + SCOPED_SERIALISE_CONTEXT(LIGHTFV); + Serialise_glLightfv(light, pname, params); + + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + SERIALISE_ELEMENT(GLenum, Face, face); + SERIALISE_ELEMENT(GLenum, Name, pname); + + Vec4f v; + if(params) v = *((Vec4f *)params); + + m_pSerialiser->Serialise<4>("params", (float *)&v.x); + + if(m_State <= EXECUTING) + m_Real.glMaterialfv(Face, Name, &v.x); + + return true; +} + +void WrappedOpenGL::glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + RDCASSERT(pname == (GLenum)0x1602 /*eGL_AMBIENT_AND_DIFFUSE*/); // assumption from glxgears. + + m_Real.glMaterialfv(face, pname, params); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(MATERIALFV); + Serialise_glMaterialfv(face, pname, params); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glNewList(GLuint list, GLenum mode) +{ + SERIALISE_ELEMENT(ResourceId, Id, GetResourceManager()->GetID(DisplayListRes(list))); + SERIALISE_ELEMENT(GLenum, Mode, mode); + + if(m_State <= EXECUTING) + { + GLResource res = GetResourceManager()->GetLiveResource(Id); + m_Real.glNewList(res.name, Mode); + } + + return true; +} + +void WrappedOpenGL::glNewList(GLuint list, GLenum mode) +{ + m_Real.glNewList(list, mode); + + RDCASSERT(m_DisplayListRecord == NULL); + m_DisplayListRecord = m_ResourceManager->GetResourceRecord(DisplayListRes(list)); + { + SCOPED_SERIALISE_CONTEXT(NEWLIST); + Serialise_glNewList(list, mode); + + m_DisplayListRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glEndList() +{ + if(m_State <= EXECUTING) + m_Real.glEndList(); + + return true; +} + +void WrappedOpenGL::glEndList() +{ + m_Real.glEndList(); + + RDCASSERT(m_DisplayListRecord); + { + SCOPED_SERIALISE_CONTEXT(ENDLIST); + Serialise_glEndList(); + + m_DisplayListRecord->AddChunk(scope.Get()); + } + m_DisplayListRecord = NULL; +} + +bool WrappedOpenGL::Serialise_glCallList(GLuint list) +{ + SERIALISE_ELEMENT(ResourceId, Id, GetResourceManager()->GetID(DisplayListRes(list))); + + if(m_State <= EXECUTING) + { + GLResource res = GetResourceManager()->GetLiveResource(Id); + m_Real.glCallList(res.name); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + if(m_State == READING) + { + GLResource res = GetResourceManager()->GetLiveResource(Id); + AddEvent(CALLLIST, desc); + string name = "glCallList(" + ToStr::Get(res.name) + ")"; + + FetchDrawcall draw; + draw.name = widen(name); + + draw.flags |= eDraw_CmdList; + + AddDrawcall(draw, true); + } + + return true; +} + +void WrappedOpenGL::glCallList(GLuint list) +{ + m_Real.glCallList(list); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(CALLLIST); + Serialise_glCallList(list); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glShadeModel(GLenum mode) +{ + SERIALISE_ELEMENT(GLenum, Mode, mode); + + if(m_State <= EXECUTING) + m_Real.glShadeModel(Mode); + + return true; +} + +void WrappedOpenGL::glShadeModel(GLenum mode) +{ + m_Real.glShadeModel(mode); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(SHADEMODEL); + Serialise_glShadeModel(mode); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glBegin(GLenum mode) +{ + SERIALISE_ELEMENT(GLenum, Mode, mode); + + if(m_State <= EXECUTING) + m_Real.glBegin(Mode); + + return true; +} + +void WrappedOpenGL::glBegin(GLenum mode) +{ + m_Real.glBegin(mode); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(BEGIN); + Serialise_glBegin(mode); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glEnd() +{ + if(m_State <= EXECUTING) + m_Real.glEnd(); + + return true; +} + +void WrappedOpenGL::glEnd() +{ + m_Real.glEnd(); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(END); + Serialise_glEnd(); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glVertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + SERIALISE_ELEMENT(GLfloat, X, x); + SERIALISE_ELEMENT(GLfloat, Y, y); + SERIALISE_ELEMENT(GLfloat, Z, z); + + if(m_State <= EXECUTING) + m_Real.glVertex3f(X, Y, Z); + + return true; +} + +void WrappedOpenGL::glVertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + m_Real.glVertex3f(x, y, z); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(VERTEX3F); + Serialise_glVertex3f(x, y, z); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ + SERIALISE_ELEMENT(GLfloat, NX, nx); + SERIALISE_ELEMENT(GLfloat, NY, ny); + SERIALISE_ELEMENT(GLfloat, NZ, nz); + + if(m_State <= EXECUTING) + m_Real.glNormal3f(NX, NY, NZ); + + return true; +} + +void WrappedOpenGL::glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ + m_Real.glNormal3f(nx, ny, nz); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(NORMAL3F); + Serialise_glNormal3f(nx, ny, nz); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glPushMatrix() +{ + if(m_State <= EXECUTING) + m_Real.glPushMatrix(); + + return true; +} + +void WrappedOpenGL::glPushMatrix() +{ + m_Real.glPushMatrix(); + + { + SCOPED_SERIALISE_CONTEXT(PUSHMATRIX); + Serialise_glPushMatrix(); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else if(m_State == WRITING_CAPFRAME) + m_ContextRecord->AddChunk(scope.Get()); + else + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glPopMatrix() +{ + if(m_State <= EXECUTING) + m_Real.glPopMatrix(); + + return true; +} + +void WrappedOpenGL::glPopMatrix() +{ + m_Real.glPopMatrix(); + + { + SCOPED_SERIALISE_CONTEXT(POPMATRIX); + Serialise_glPopMatrix(); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else if(m_State == WRITING_CAPFRAME) + m_ContextRecord->AddChunk(scope.Get()); + else + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glMatrixMode(GLenum mode) +{ + SERIALISE_ELEMENT(GLenum, Mode, mode); + + if(m_State <= EXECUTING) + m_Real.glMatrixMode(Mode); + + return true; +} + +void WrappedOpenGL::glMatrixMode(GLenum mode) +{ + m_Real.glMatrixMode(mode); + + { + SCOPED_SERIALISE_CONTEXT(MATRIXMODE); + Serialise_glMatrixMode(mode); + + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glLoadIdentity() +{ + if(m_State <= EXECUTING) + m_Real.glLoadIdentity(); + + return true; +} + +void WrappedOpenGL::glLoadIdentity() +{ + m_Real.glLoadIdentity(); + + { + SCOPED_SERIALISE_CONTEXT(LOADIDENTITY); + Serialise_glLoadIdentity(); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else if(m_State == WRITING_CAPFRAME) + m_ContextRecord->AddChunk(scope.Get()); + else + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SERIALISE_ELEMENT(GLdouble, L, left); + SERIALISE_ELEMENT(GLdouble, R, right); + SERIALISE_ELEMENT(GLdouble, B, bottom); + SERIALISE_ELEMENT(GLdouble, T, top); + SERIALISE_ELEMENT(GLdouble, N, zNear); + SERIALISE_ELEMENT(GLdouble, F, zFar); + + if(m_State <= EXECUTING) + m_Real.glFrustum(L, R, B, T, N, F); + + return true; +} + +void WrappedOpenGL::glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + m_Real.glFrustum(left, right, bottom, top, zNear, zFar); + + { + SCOPED_SERIALISE_CONTEXT(FRUSTUM); + Serialise_glFrustum(left, right, bottom, top, zNear, zFar); + + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ + SERIALISE_ELEMENT(GLfloat, X, x); + SERIALISE_ELEMENT(GLfloat, Y, y); + SERIALISE_ELEMENT(GLfloat, Z, z); + + if(m_State <= EXECUTING) + m_Real.glTranslatef(X, Y, Z); + + return true; +} + +void WrappedOpenGL::glTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ + m_Real.glTranslatef(x, y, z); + + { + SCOPED_SERIALISE_CONTEXT(TRANSLATEF); + Serialise_glTranslatef(x, y, z); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else if(m_State == WRITING_CAPFRAME) + m_ContextRecord->AddChunk(scope.Get()); + else + m_DeviceRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + SERIALISE_ELEMENT(GLfloat, ang, angle); + SERIALISE_ELEMENT(GLfloat, X, x); + SERIALISE_ELEMENT(GLfloat, Y, y); + SERIALISE_ELEMENT(GLfloat, Z, z); + + if(m_State <= EXECUTING) + m_Real.glRotatef(ang, X, Y, Z); + + return true; +} + +void WrappedOpenGL::glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + m_Real.glRotatef(angle, x, y, z); + + if(m_State == WRITING_CAPFRAME || m_DisplayListRecord) + { + SCOPED_SERIALISE_CONTEXT(ROTATEF); + Serialise_glRotatef(angle, x, y, z); + + if(m_DisplayListRecord) + m_DisplayListRecord->AddChunk(scope.Get()); + else + m_ContextRecord->AddChunk(scope.Get()); + } +} + +#pragma endregion + + diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp new file mode 100644 index 0000000000..55f8a25cba --- /dev/null +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -0,0 +1,738 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "gl_replay.h" +#include "gl_driver.h" +#include "gl_resources.h" +#include "maths/matrix.h" +#include "maths/camera.h" + +#include "common/string_utils.h" + +GLuint GLReplay::CreateShaderProgram(const char *vsSrc, const char *psSrc) +{ + if(m_pDriver == NULL) return 0; + + MakeCurrentReplayContext(m_DebugCtx); + + WrappedOpenGL &gl = *m_pDriver; + + GLuint vs = gl.glCreateShader(eGL_VERTEX_SHADER); + GLuint fs = gl.glCreateShader(eGL_FRAGMENT_SHADER); + + const char *src = vsSrc; + gl.glShaderSource(vs, 1, &src, NULL); + src = psSrc; + gl.glShaderSource(fs, 1, &src, NULL); + + gl.glCompileShader(vs); + gl.glCompileShader(fs); + + char buffer[4096]; + GLint status = 0; + + gl.glGetShaderiv(vs, eGL_COMPILE_STATUS, &status); + if(status == 0) + { + gl.glGetShaderInfoLog(vs, 4096, NULL, buffer); + RDCERR("Shader error: %hs", buffer); + } + + gl.glGetShaderiv(fs, eGL_COMPILE_STATUS, &status); + if(status == 0) + { + gl.glGetShaderInfoLog(fs, 4096, NULL, buffer); + RDCERR("Shader error: %hs", buffer); + } + + GLuint ret = gl.glCreateProgram(); + + gl.glAttachShader(ret, vs); + gl.glAttachShader(ret, fs); + + gl.glLinkProgram(ret); + + gl.glDeleteShader(vs); + gl.glDeleteShader(fs); + + return ret; +} + +void GLReplay::InitDebugData() +{ + if(m_pDriver == NULL) return; + + { + uint64_t id = MakeOutputWindow(NULL, true); + + m_DebugCtx = &m_OutputWindows[id]; + } + + DebugData.outWidth = 0.0f; DebugData.outHeight = 0.0f; + + DebugData.blitvsSource = GetEmbeddedResource(blit_vert); + DebugData.blitfsSource = GetEmbeddedResource(blit_frag); + + DebugData.blitProg = CreateShaderProgram(DebugData.blitvsSource.c_str(), DebugData.blitfsSource.c_str()); + + string texfs = GetEmbeddedResource(texdisplay_frag); + + DebugData.texDisplayProg = CreateShaderProgram(DebugData.blitvsSource.c_str(), texfs.c_str()); + + string checkerfs = GetEmbeddedResource(checkerboard_frag); + + DebugData.checkerProg = CreateShaderProgram(DebugData.blitvsSource.c_str(), checkerfs.c_str()); + + DebugData.genericvsSource = GetEmbeddedResource(generic_vert); + DebugData.genericfsSource = GetEmbeddedResource(generic_frag); + + DebugData.genericProg = CreateShaderProgram(DebugData.genericvsSource.c_str(), DebugData.genericfsSource.c_str()); + + string meshvs = GetEmbeddedResource(mesh_vert); + + DebugData.meshProg = CreateShaderProgram(meshvs.c_str(), DebugData.genericfsSource.c_str()); + + WrappedOpenGL &gl = *m_pDriver; + + { + float data[] = { + 0.0f, -1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + gl.glGenBuffers(1, &DebugData.outlineStripVB); + gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.outlineStripVB); + gl.glBufferData(eGL_ARRAY_BUFFER, sizeof(data), data, eGL_STATIC_DRAW); + + gl.glGenVertexArrays(1, &DebugData.outlineStripVAO); + gl.glBindVertexArray(DebugData.outlineStripVAO); + + gl.glVertexAttribPointer(0, 4, eGL_FLOAT, false, 0, (const void *)0); + gl.glEnableVertexAttribArray(0); + } + + gl.glGenSamplers(1, &DebugData.linearSampler); + gl.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_MIN_FILTER, eGL_LINEAR_MIPMAP_NEAREST); + gl.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_MAG_FILTER, eGL_LINEAR); + gl.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + + gl.glGenSamplers(1, &DebugData.pointSampler); + gl.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST_MIPMAP_NEAREST); + gl.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + + gl.glGenBuffers(ARRAY_COUNT(DebugData.UBOs), DebugData.UBOs); + for(size_t i=0; i < ARRAY_COUNT(DebugData.UBOs); i++) + { + gl.glBindBuffer(eGL_UNIFORM_BUFFER, DebugData.UBOs[i]); + gl.glBufferData(eGL_UNIFORM_BUFFER, DebugData.UBOSize, NULL, eGL_DYNAMIC_DRAW); + } + + DebugData.overlayTexWidth = DebugData.overlayTexHeight = 0; + DebugData.overlayTex = DebugData.overlayFBO = 0; + + gl.glGenFramebuffers(1, &DebugData.pickPixelFBO); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.pickPixelFBO); + + gl.glGenTextures(1, &DebugData.pickPixelTex); + gl.glBindTexture(eGL_TEXTURE_2D, DebugData.pickPixelTex); + + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGBA32F, 1, 1); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.pickPixelTex, 0); + + gl.glGenVertexArrays(1, &DebugData.emptyVAO); + gl.glBindVertexArray(DebugData.emptyVAO); + + gl.glGenVertexArrays(1, &DebugData.meshVAO); +} + +void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(m_DebugCtx); + + gl.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.pickPixelFBO); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, DebugData.pickPixelFBO); + + pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0.0f; + gl.glClearBufferfv(eGL_COLOR, 0, pixel); + + DebugData.outWidth = DebugData.outHeight = 1.0f; + gl.glViewport(0, 0, 1, 1); + + { + TextureDisplay texDisplay; + + texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true; + texDisplay.HDRMul = -1.0f; + texDisplay.mip = mip; + texDisplay.CustomShader = ResourceId(); + texDisplay.sliceFace = sliceFace; + texDisplay.rangemin = 0.0f; + texDisplay.rangemax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.texid = texture; + texDisplay.rawoutput = true; + texDisplay.offx = -float(x); + texDisplay.offy = -float(y); + + RenderTexture(texDisplay); + } + + gl.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixel); +} + +bool GLReplay::RenderTexture(TextureDisplay cfg) +{ + MakeCurrentReplayContext(m_DebugCtx); + + WrappedOpenGL &gl = *m_pDriver; + + gl.glUseProgram(DebugData.texDisplayProg); + + auto &texDetails = m_pDriver->m_Textures[cfg.texid]; + + gl.glActiveTexture(eGL_TEXTURE0); + gl.glBindTexture(eGL_TEXTURE_2D, texDetails.resource.name); + + if(cfg.mip == 0 && cfg.scale < 1.0f) + gl.glBindSampler(0, DebugData.linearSampler); + else + gl.glBindSampler(0, DebugData.pointSampler); + + GLint tex_x = texDetails.width, tex_y = texDetails.height, tex_z = texDetails.depth; + + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); + + struct uboData + { + Vec2f Position; + float Scale; + float HDRMul; + + Vec4f Channels; + + float RangeMinimum; + float InverseRangeSize; + float MipLevel; + float dummy2; + + Vec3f TextureResolutionPS; + int OutputDisplayFormat; + + Vec2f OutputRes; + int RawOutput; + float Slice; + }; + + uboData *ubo = (uboData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(uboData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + + RDCCOMPILE_ASSERT(sizeof(uboData) <= DebugData.UBOSize, "UBO data is too big"); + + float x = cfg.offx; + float y = cfg.offy; + + ubo->Position.x = x; + ubo->Position.y = y; + ubo->Scale = cfg.scale; + + if(cfg.scale <= 0.0f) + { + float xscale = DebugData.outWidth/float(tex_x); + float yscale = DebugData.outHeight/float(tex_y); + + ubo->Scale = RDCMIN(xscale, yscale); + + if(yscale > xscale) + { + ubo->Position.x = 0; + ubo->Position.y = (DebugData.outHeight-(tex_y*ubo->Scale) )*0.5f; + } + else + { + ubo->Position.y = 0; + ubo->Position.x = (DebugData.outWidth-(tex_x*ubo->Scale) )*0.5f; + } + } + + ubo->HDRMul = cfg.HDRMul; + + if(cfg.rangemax <= cfg.rangemin) cfg.rangemax += 0.00001f; + + ubo->Channels.x = cfg.Red ? 1.0f : 0.0f; + ubo->Channels.y = cfg.Green ? 1.0f : 0.0f; + ubo->Channels.z = cfg.Blue ? 1.0f : 0.0f; + ubo->Channels.w = cfg.Alpha ? 1.0f : 0.0f; + + ubo->RangeMinimum = cfg.rangemin; + ubo->InverseRangeSize = 1.0f/(cfg.rangemax-cfg.rangemin); + + ubo->MipLevel = (float)cfg.mip; + + ubo->OutputDisplayFormat = 0x2; // 2d. Unused for now + + ubo->RawOutput = cfg.rawoutput ? 1 : 0; + + ubo->TextureResolutionPS.x = float(tex_x); + ubo->TextureResolutionPS.y = float(tex_y); + ubo->TextureResolutionPS.z = float(tex_z); + + ubo->OutputRes.x = DebugData.outWidth; + ubo->OutputRes.y = DebugData.outHeight; + + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + if(cfg.rawoutput) + { + gl.glDisable(eGL_BLEND); + } + else + { + gl.glEnable(eGL_BLEND); + gl.glBlendFunc(eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA); + } + + gl.glBindVertexArray(DebugData.emptyVAO); + gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + + gl.glBindSampler(0, 0); + + return true; +} + +void GLReplay::RenderCheckerboard(Vec3f light, Vec3f dark) +{ + MakeCurrentReplayContext(m_DebugCtx); + + WrappedOpenGL &gl = *m_pDriver; + + gl.glUseProgram(DebugData.checkerProg); + + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); + + Vec4f *ubo = (Vec4f *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(Vec4f)*2, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + + ubo[0] = Vec4f(light.x, light.y, light.z, 1.0f); + ubo[1] = Vec4f(dark.x, dark.y, dark.z, 1.0f); + + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + gl.glBindVertexArray(DebugData.emptyVAO); + gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); +} + +void GLReplay::RenderHighlightBox(float w, float h, float scale) +{ + MakeCurrentReplayContext(m_DebugCtx); + + const float xpixdim = 2.0f/w; + const float ypixdim = 2.0f/h; + + const float xdim = scale*xpixdim; + const float ydim = scale*ypixdim; + + WrappedOpenGL &gl = *m_pDriver; + + gl.glUseProgram(DebugData.genericProg); + + GLint offsetLoc = gl.glGetUniformLocation(DebugData.genericProg, "RENDERDOC_GenericVS_Offset"); + GLint scaleLoc = gl.glGetUniformLocation(DebugData.genericProg, "RENDERDOC_GenericVS_Scale"); + GLint colLoc = gl.glGetUniformLocation(DebugData.genericProg, "RENDERDOC_GenericFS_Color"); + + Vec4f offsetVal(0.0f, 0.0f, 0.0f, 0.0f); + Vec4f scaleVal(xdim, ydim, 1.0f, 1.0f); + Vec4f colVal(1.0f, 1.0f, 1.0f, 1.0f); + + gl.glUniform4fv(offsetLoc, 1, &offsetVal.x); + gl.glUniform4fv(scaleLoc, 1, &scaleVal.x); + gl.glUniform4fv(colLoc, 1, &colVal.x); + + gl.glBindVertexArray(DebugData.outlineStripVAO); + gl.glDrawArrays(eGL_LINE_LOOP, 0, 4); + + offsetVal = Vec4f(-xpixdim, ypixdim, 0.0f, 0.0f); + scaleVal = Vec4f(xdim+xpixdim*2, ydim+ypixdim*2, 1.0f, 1.0f); + colVal = Vec4f(0.0f, 0.0f, 0.0f, 1.0f); + + gl.glUniform4fv(offsetLoc, 1, &offsetVal.x); + gl.glUniform4fv(scaleLoc, 1, &scaleVal.x); + gl.glUniform4fv(colLoc, 1, &colVal.x); + + gl.glBindVertexArray(DebugData.outlineStripVAO); + gl.glDrawArrays(eGL_LINE_LOOP, 0, 4); +} + +ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(&m_ReplayCtx); + + GLuint curProg = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg); + + GLuint curDrawFBO = 0; + GLuint curReadFBO = 0; + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&curDrawFBO); + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&curReadFBO); + + auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(curProg))]; + + if(progDetails.colOutProg == 0) + { + progDetails.colOutProg = gl.glCreateProgram(); + GLuint shad = gl.glCreateShader(eGL_FRAGMENT_SHADER); + + const char *src = DebugData.genericfsSource.c_str(); + gl.glShaderSource(shad, 1, &src, NULL); + gl.glCompileShader(shad); + gl.glAttachShader(progDetails.colOutProg, shad); + gl.glDeleteShader(shad); + + for(size_t i=0; i < progDetails.shaders.size(); i++) + { + const auto &shadDetails = m_pDriver->m_Shaders[progDetails.shaders[i]]; + + if(shadDetails.type != eGL_FRAGMENT_SHADER) + { + shad = gl.glCreateShader(shadDetails.type); + for(size_t s=0; s < shadDetails.sources.size(); s++) + { + src = shadDetails.sources[s].c_str(); + gl.glShaderSource(shad, 1, &src, NULL); + } + gl.glCompileShader(shad); + gl.glAttachShader(progDetails.colOutProg, shad); + gl.glDeleteShader(shad); + } + } + + gl.glLinkProgram(progDetails.colOutProg); + } + + auto &texDetails = m_pDriver->m_Textures[texid]; + + if(DebugData.overlayTexWidth != texDetails.width || DebugData.overlayTexHeight != texDetails.height) + { + if(DebugData.overlayFBO) + { + gl.glDeleteFramebuffers(1, &DebugData.overlayFBO); + gl.glDeleteTextures(1, &DebugData.overlayTex); + } + + gl.glGenFramebuffers(1, &DebugData.overlayFBO); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.overlayFBO); + + GLuint curTex = 0; + gl.glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint*)&curTex); + + gl.glGenTextures(1, &DebugData.overlayTex); + gl.glBindTexture(eGL_TEXTURE_2D, DebugData.overlayTex); + + DebugData.overlayTexWidth = texDetails.width; + DebugData.overlayTexHeight = texDetails.height; + + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGBA8, texDetails.width, texDetails.height); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.overlayTex, 0); + + gl.glBindTexture(eGL_TEXTURE_2D, curTex); + } + + gl.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.overlayFBO); + + if(overlay == eTexOverlay_NaN || overlay == eTexOverlay_Clipping) + { + // just need the basic texture + float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + gl.glClearBufferfv(eGL_COLOR, 0, black); + } + else if(overlay == eTexOverlay_Drawcall) + { + gl.glUseProgram(progDetails.colOutProg); + + { + // copy across uniforms + GLint numUniforms = 0; + gl.glGetProgramiv(curProg, eGL_ACTIVE_UNIFORMS, &numUniforms); + + for(GLint i=0; i < numUniforms; i++) + { + char uniName[1024] = {}; + GLint uniSize = 0; + GLenum uniType = eGL_UNKNOWN_ENUM; + gl.glGetActiveUniform(curProg, i, 1024, NULL, &uniSize, &uniType, uniName); + + GLint origloc = gl.glGetUniformLocation(curProg, uniName); + GLint newloc = gl.glGetUniformLocation(progDetails.colOutProg, uniName); + + double dv[16]; + float *fv = (float *)dv; + + if(uniSize > 1) + { + RDCERR("Array elements beyond [0] not being copied to new program"); + } + + if(origloc != -1 && newloc != -1) + { + if(uniType == eGL_FLOAT_MAT4) + { + gl.glGetUniformfv(curProg, origloc, fv); + gl.glUniformMatrix4fv(newloc, 1, false, fv); + } + else if(uniType == eGL_FLOAT_VEC3) + { + gl.glGetUniformfv(curProg, origloc, fv); + gl.glUniform3fv(newloc, 1, fv); + } + else if(uniType == eGL_FLOAT_VEC4) + { + gl.glGetUniformfv(curProg, origloc, fv); + gl.glUniform4fv(newloc, 1, fv); + } + else + { + RDCERR("Uniform type '%s' not being copied to new program", ToStr::Get(uniType).c_str()); + } + } + } + } + + float black[] = { 0.0f, 0.0f, 0.0f, 0.5f }; + gl.glClearBufferfv(eGL_COLOR, 0, black); + + GLint colLoc = gl.glGetUniformLocation(progDetails.colOutProg, "RENDERDOC_GenericFS_Color"); + float colVal[] = { 0.8f, 0.1f, 0.8f, 1.0f }; + gl.glUniform4fv(colLoc, 1, colVal); + + ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + gl.glUseProgram(curProg); + } + else if(overlay == eTexOverlay_Wireframe) + { + gl.glUseProgram(progDetails.colOutProg); + + { + // copy across uniforms + GLint numUniforms = 0; + gl.glGetProgramiv(curProg, eGL_ACTIVE_UNIFORMS, &numUniforms); + + for(GLint i=0; i < numUniforms; i++) + { + char uniName[1024] = {}; + GLint uniSize = 0; + GLenum uniType = eGL_UNKNOWN_ENUM; + gl.glGetActiveUniform(curProg, i, 1024, NULL, &uniSize, &uniType, uniName); + + GLint origloc = gl.glGetUniformLocation(curProg, uniName); + GLint newloc = gl.glGetUniformLocation(progDetails.colOutProg, uniName); + + double dv[16]; + float *fv = (float *)dv; + + if(uniSize > 1) + { + RDCERR("Array elements beyond [0] not being copied to new program"); + } + + if(origloc != -1 && newloc != -1) + { + if(uniType == eGL_FLOAT_MAT4) + { + gl.glGetUniformfv(curProg, origloc, fv); + gl.glUniformMatrix4fv(newloc, 1, false, fv); + } + else if(uniType == eGL_FLOAT_VEC3) + { + gl.glGetUniformfv(curProg, origloc, fv); + gl.glUniform3fv(newloc, 1, fv); + } + else if(uniType == eGL_FLOAT_VEC4) + { + gl.glGetUniformfv(curProg, origloc, fv); + gl.glUniform4fv(newloc, 1, fv); + } + else + { + RDCERR("Uniform type '%s' not being copied to new program", ToStr::Get(uniType).c_str()); + } + } + } + } + + float wireCol[] = { 200.0f/255.0f, 255.0f/255.0f, 0.0f/255.0f, 0.0f }; + gl.glClearBufferfv(eGL_COLOR, 0, wireCol); + + GLint colLoc = gl.glGetUniformLocation(progDetails.colOutProg, "RENDERDOC_GenericFS_Color"); + wireCol[3] = 1.0f; + gl.glUniform4fv(colLoc, 1, wireCol); + + GLint depthTest = GL_FALSE; + gl.glGetIntegerv(eGL_DEPTH_TEST, (GLint*)&depthTest); + GLenum polyMode = eGL_FILL; + gl.glGetIntegerv(eGL_POLYGON_MODE, (GLint*)&polyMode); + + gl.glDisable(eGL_DEPTH_TEST); + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE); + + ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + + if(depthTest) + gl.glEnable(eGL_DEPTH_TEST); + if(polyMode != eGL_LINE) + gl.glPolygonMode(eGL_FRONT_AND_BACK, polyMode); + + gl.glUseProgram(curProg); + } + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, curDrawFBO); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curReadFBO); + + return m_pDriver->GetResourceManager()->GetID(TextureRes(DebugData.overlayTex)); +} + +void GLReplay::RenderMesh(int frameID, vector eventID, MeshDisplay cfg) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(m_DebugCtx); + + GLuint curFBO = 0; + gl.glGetIntegerv(eGL_FRAMEBUFFER_BINDING, (GLint*)&curFBO); + + OutputWindow *outw = NULL; + for(auto it = m_OutputWindows.begin(); it != m_OutputWindows.end(); ++it) + { + if(it->second.BlitData.windowFBO == curFBO) + { + outw = &it->second; + break; + } + } + + if(!outw) return; + + MakeCurrentReplayContext(&m_ReplayCtx); + + GLint viewport[4]; + gl.glGetIntegerv(eGL_VIEWPORT, viewport); + + gl.glGetIntegerv(eGL_FRAMEBUFFER_BINDING, (GLint*)&curFBO); + + if(outw->BlitData.replayFBO == 0) + { + gl.glGenFramebuffers(1, &outw->BlitData.replayFBO); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, outw->BlitData.replayFBO); + + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, outw->BlitData.backbuffer, 0); + } + else + { + gl.glBindFramebuffer(eGL_FRAMEBUFFER, outw->BlitData.replayFBO); + } + + gl.glViewport(0, 0, (GLsizei)DebugData.outWidth, (GLsizei)DebugData.outHeight); + + GLuint curProg = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg); + + gl.glUseProgram(DebugData.meshProg); + + float wireCol[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + GLint colLoc = gl.glGetUniformLocation(DebugData.meshProg, "RENDERDOC_GenericFS_Color"); + gl.glUniform4fv(colLoc, 1, wireCol); + + Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, DebugData.outWidth/DebugData.outHeight); + + Camera cam; + if(cfg.arcballCamera) + cam.Arcball(cfg.cameraPos.x, Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + else + cam.fpsLook(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + + Matrix4f camMat = cam.GetMatrix(); + + Matrix4f ModelViewProj = projMat.Mul(camMat); + + GLint mvpLoc = gl.glGetUniformLocation(DebugData.meshProg, "ModelViewProj"); + gl.glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, ModelViewProj.Data()); + + GLuint curVAO = 0; + gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint*)&curVAO); + + GLuint curArr = 0; + gl.glGetIntegerv(eGL_ARRAY_BUFFER_BINDING, (GLint*)&curArr); + + gl.glBindVertexArray(DebugData.meshVAO); + + const auto &attr = m_CurPipelineState.m_VtxIn.attributes[0]; + const auto &vb = m_CurPipelineState.m_VtxIn.vbuffers[attr.BufferSlot]; + + // TODO: we should probably use glBindVertexBuffer, glVertexAttribFormat, glVertexAttribBinding. + // For now just assume things about the format and vbuffer. + + RDCASSERT(attr.Format.compType == eCompType_Float && attr.Format.compByteWidth == 4); + + gl.glBindBuffer(eGL_ARRAY_BUFFER, m_pDriver->GetResourceManager()->GetLiveResource(vb.Buffer).name); + gl.glVertexAttribPointer(0, attr.Format.compCount, eGL_FLOAT, GL_FALSE, 0, (void *)intptr_t(vb.Offset + attr.RelativeOffset)); + gl.glEnableVertexAttribArray(0); + + { + GLint depthTest = GL_FALSE; + gl.glGetIntegerv(eGL_DEPTH_TEST, (GLint*)&depthTest); + GLenum polyMode = eGL_FILL; + gl.glGetIntegerv(eGL_POLYGON_MODE, (GLint*)&polyMode); + + gl.glDisable(eGL_DEPTH_TEST); + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE); + + ReplayLog(frameID, 0, eventID[0], eReplay_OnlyDraw); + + if(depthTest) + gl.glEnable(eGL_DEPTH_TEST); + if(polyMode != eGL_LINE) + gl.glPolygonMode(eGL_FRONT_AND_BACK, polyMode); + } + + gl.glBindVertexArray(curVAO); + gl.glBindBuffer(eGL_ARRAY_BUFFER, curArr); + + gl.glUseProgram(curProg); + gl.glViewport(viewport[0], viewport[1], (GLsizei)viewport[2], (GLsizei)viewport[3]); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, curFBO); +} diff --git a/renderdoc/driver/gl/gl_device_driver.cpp b/renderdoc/driver/gl/gl_device_driver.cpp new file mode 100644 index 0000000000..a5dfcd0f69 --- /dev/null +++ b/renderdoc/driver/gl/gl_device_driver.cpp @@ -0,0 +1,1292 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" +#include "gl_driver.h" + +#pragma region Textures + +bool WrappedOpenGL::Serialise_glGenTextures(GLsizei n, GLuint* textures) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(TextureRes(*textures))); + SERIALISE_ELEMENT(GLint, activeTexUnit, m_TextureUnit); + RDCWARN("HACK! serialising active tex with gen - need to grab initial pipeline state to fix"); + + if(m_State == READING) + { + m_Real.glActiveTexture(RDCGLenum(GL_TEXTURE0 + activeTexUnit)); + GLuint real = 0; + m_Real.glGenTextures(1, &real); + + GLResource res = TextureRes(real); + + ResourceId live = m_ResourceManager->RegisterResource(res); + GetResourceManager()->AddLiveResource(id, res); + + m_Textures[live].resource = res; + m_Textures[live].curType = eGL_UNKNOWN_ENUM; + } + + return true; +} + +void WrappedOpenGL::glGenTextures(GLsizei n, GLuint* textures) +{ + m_Real.glGenTextures(n, textures); + + for(GLsizei i=0; i < n; i++) + { + GLResource res = TextureRes(textures[i]); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(GEN_TEXTURE); + Serialise_glGenTextures(1, textures+i); + + chunk = scope.Get(); + } + + GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + m_Textures[id].resource = res; + m_Textures[id].curType = eGL_UNKNOWN_ENUM; + } + } +} + +void WrappedOpenGL::glDeleteTextures(GLsizei n, const GLuint *textures) +{ + m_Real.glDeleteTextures(n, textures); + + for(GLsizei i=0; i < n; i++) + GetResourceManager()->UnregisterResource(TextureRes(textures[i])); +} + +bool WrappedOpenGL::Serialise_glBindTexture(GLenum target, GLuint texture) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(ResourceId, Id, GetResourceManager()->GetID(TextureRes(texture))); + + if(m_State == WRITING_IDLE) + { + m_TextureRecord[m_TextureUnit]->datatype = Target; + } + else if(m_State < WRITING) + { + GLResource res = GetResourceManager()->GetLiveResource(Id); + m_Real.glBindTexture(Target, res.name); + + m_Textures[GetResourceManager()->GetLiveID(Id)].curType = Target; + } + + return true; +} + +void WrappedOpenGL::glBindTexture(GLenum target, GLuint texture) +{ + m_Real.glBindTexture(target, texture); + + if(m_State == WRITING_CAPFRAME) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(BIND_TEXTURE); + Serialise_glBindTexture(target, texture); + + chunk = scope.Get(); + } + + m_ContextRecord->AddChunk(chunk); + } + else if(m_State < WRITING) + { + m_Textures[GetResourceManager()->GetID(TextureRes(texture))].curType = target; + } + + if(texture == 0) + { + m_TextureRecord[m_TextureUnit] = NULL; + return; + } + + if(m_State >= WRITING) + { + GLResourceRecord *r = m_TextureRecord[m_TextureUnit] = GetResourceManager()->GetResourceRecord(TextureRes(texture)); + + if(r->datatype) + { + // it's illegal to retype a texture + RDCASSERT(r->datatype == target); + } + else + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(BIND_TEXTURE); + Serialise_glBindTexture(target, texture); + + chunk = scope.Get(); + } + + r->AddChunk(chunk); + } + } +} + +bool WrappedOpenGL::Serialise_glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(GLsizei, Levels, levels); + SERIALISE_ELEMENT(GLenum, Format, internalformat); + SERIALISE_ELEMENT(GLsizei, Width, width); + SERIALISE_ELEMENT(GLsizei, Height, height); + SERIALISE_ELEMENT(ResourceId, id, m_TextureRecord[m_TextureUnit]->GetResourceID()); + + if(m_State == READING) + { + ResourceId liveId = GetResourceManager()->GetLiveID(id); + m_Textures[liveId].width = Width; + m_Textures[liveId].height = Height; + m_Textures[liveId].depth = 1; + + m_Real.glBindTexture(Target, GetResourceManager()->GetLiveResource(id).name); + m_Real.glTexStorage2D(Target, Levels, Format, Width, Height); + } + + return true; +} + +void WrappedOpenGL::glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + m_Real.glTexStorage2D(target, levels, internalformat, width, height); + + if(m_State >= WRITING) + { + RDCASSERT(m_TextureRecord[m_TextureUnit]); + + SCOPED_SERIALISE_CONTEXT(TEXSTORAGE2D); + Serialise_glTexStorage2D(target, levels, internalformat, width, height); + + m_TextureRecord[m_TextureUnit]->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(GLint, Level, level); + SERIALISE_ELEMENT(GLint, xoff, xoffset); + SERIALISE_ELEMENT(GLint, yoff, yoffset); + SERIALISE_ELEMENT(GLsizei, Width, width); + SERIALISE_ELEMENT(GLsizei, Height, height); + SERIALISE_ELEMENT(GLenum, Format, format); + SERIALISE_ELEMENT(GLenum, Type, type); + SERIALISE_ELEMENT(ResourceId, id, m_TextureRecord[m_TextureUnit]->GetResourceID()); + + size_t subimageSize = GetByteSize(Width, Height, 1, Format, Type, Level, m_TextureAlignment); + + SERIALISE_ELEMENT_BUF(byte *, buf, pixels, subimageSize); + + if(m_State == READING) + { + m_Real.glBindTexture(Target, GetResourceManager()->GetLiveResource(id).name); + m_Real.glTexSubImage2D(Target, Level, xoff, yoff, Width, Height, Format, Type, buf); + + delete[] buf; + } + + return true; +} + +void WrappedOpenGL::glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + m_Real.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + + RDCASSERT(m_TextureRecord[m_TextureUnit]); + { + SCOPED_SERIALISE_CONTEXT(TEXSUBIMAGE2D); + Serialise_glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + + m_TextureRecord[m_TextureUnit]->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glGenerateMipmap(GLenum target) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(ResourceId, id, m_TextureRecord[m_TextureUnit]->GetResourceID()); + + if(m_State == READING) + { + m_Real.glBindTexture(Target, GetResourceManager()->GetLiveResource(id).name); + m_Real.glGenerateMipmap(Target); + } + + return true; +} + +void WrappedOpenGL::glGenerateMipmap(GLenum target) +{ + m_Real.glGenerateMipmap(target); + + RDCASSERT(m_TextureRecord[m_TextureUnit]); + { + SCOPED_SERIALISE_CONTEXT(GENERATE_MIPMAP); + Serialise_glGenerateMipmap(target); + + m_TextureRecord[m_TextureUnit]->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(GLenum, PName, pname); + SERIALISE_ELEMENT(int32_t, Param, param); + + if(m_State == READING) + { + glTexParameteri(Target, PName, Param); + } + + return true; +} + +void WrappedOpenGL::glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + m_Real.glTexParameteri(target, pname, param); + + if(m_State >= WRITING) + { + RDCASSERT(m_TextureRecord[m_TextureUnit]); + + SCOPED_SERIALISE_CONTEXT(TEXPARAMETERI); + Serialise_glTexParameteri(target, pname, param); + + m_TextureRecord[m_TextureUnit]->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glGenSamplers(GLsizei count, GLuint *samplers) +{ + m_Real.glGenSamplers(count, samplers); + + for(GLsizei i=0; i < count; i++) + { + GLResource res = SamplerRes(samplers[i]); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + } +} + +void WrappedOpenGL::glBindSampler(GLuint unit, GLuint sampler) +{ + m_Real.glBindSampler(unit, sampler); + + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } +} + +void WrappedOpenGL::glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + m_Real.glSamplerParameteri(sampler, pname, param); + + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } +} + +bool WrappedOpenGL::Serialise_glPixelStorei(GLenum pname, GLint param) +{ + SERIALISE_ELEMENT(GLenum, PName, pname); + SERIALISE_ELEMENT(GLint, Param, param); + + if(m_State == READING) + { + if(pname == eGL_UNPACK_ALIGNMENT) + m_TextureAlignment = param; + + m_Real.glPixelStorei(PName, Param); + } + + return true; +} + +void WrappedOpenGL::glPixelStorei(GLenum pname, GLint param) +{ + m_Real.glPixelStorei(pname, param); + + if(pname == eGL_UNPACK_ALIGNMENT) + m_TextureAlignment = param; + + RDCASSERT(m_TextureRecord[m_TextureUnit]); + { + SCOPED_SERIALISE_CONTEXT(PIXELSTORE); + Serialise_glPixelStorei(pname, param); + + m_TextureRecord[m_TextureUnit]->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glPixelStoref(GLenum pname, GLfloat param) +{ + glPixelStorei(pname, (GLint)param); +} + +void WrappedOpenGL::glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + m_Real.glTexImage1D(target, level, internalformat, width, border, format, type, pixels); +} + +void WrappedOpenGL::glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels) +{ + m_Real.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + + RDCUNIMPLEMENTED(); +} + +void WrappedOpenGL::glActiveTexture(GLenum texture) +{ + m_Real.glActiveTexture(texture); + + m_TextureUnit = texture-eGL_TEXTURE0; +} + +#pragma endregion + +#pragma region Framebuffers + +void WrappedOpenGL::glGenFramebuffers(GLsizei n, GLuint *framebuffers) +{ + m_Real.glGenFramebuffers(n, framebuffers); + + for(GLsizei i=0; i < n; i++) + { + GLResource res = FramebufferRes(framebuffers[i]); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + } +} + +void WrappedOpenGL::glFramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level) +{ + m_Real.glFramebufferTexture(target, attachment, texture, level); + + if(m_State >= WRITING) + RDCUNIMPLEMENTED(); +} + +void WrappedOpenGL::glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) +{ + m_Real.glDeleteFramebuffers(n, framebuffers); + + if(m_State >= WRITING) + RDCUNIMPLEMENTED(); + + for(GLsizei i=0; i < n; i++) + GetResourceManager()->UnregisterResource(FramebufferRes(framebuffers[i])); +} + +void WrappedOpenGL::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params) +{ + m_Real.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); +} + +#pragma endregion + +#pragma region Shaders / Programs + +bool WrappedOpenGL::Serialise_glCreateShader(GLuint shader, GLenum type) +{ + SERIALISE_ELEMENT(GLenum, Type, type); + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ShaderRes(shader))); + + if(m_State == READING) + { + GLuint real = m_Real.glCreateShader(Type); + + GLResource res = ShaderRes(real); + + ResourceId liveId = GetResourceManager()->RegisterResource(res); + + m_Shaders[liveId].type = Type; + + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + } + + return true; +} + +GLuint WrappedOpenGL::glCreateShader(GLenum type) +{ + GLuint real = m_Real.glCreateShader(type); + + GLResource res = ShaderRes(real); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(CREATE_SHADER); + Serialise_glCreateShader(real, type); + + chunk = scope.Get(); + } + + GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + + return real; +} + +bool WrappedOpenGL::Serialise_glShaderSource(GLuint shader, GLsizei count, const GLchar* const *source, const GLint *length) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ShaderRes(shader))); + SERIALISE_ELEMENT(GLsizei, Count, count); + + vector srcs; + + for(GLsizei i=0; i < Count; i++) + { + string s; + if(source) + s = length ? string(source[i], source[i] + length[i]) : string(source[i]); + + m_pSerialiser->SerialiseString("source", s); + + if(m_State == READING) + srcs.push_back(s); + } + + if(m_State == READING) + { + const char **strings = new const char*[srcs.size()]; + for(size_t i=0; i < srcs.size(); i++) + strings[i] = srcs[i].c_str(); + + ResourceId liveId = GetResourceManager()->GetLiveID(id); + + for(GLsizei i=0; i < Count; i++) + m_Shaders[liveId].sources.push_back(strings[i]); + + m_Real.glShaderSource(GetResourceManager()->GetLiveResource(id).name, Count, strings, NULL); + } + + return true; +} + +void WrappedOpenGL::glShaderSource(GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length) +{ + m_Real.glShaderSource(shader, count, string, length); + + if(m_State >= WRITING) + { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(ShaderRes(shader)); + RDCASSERT(record); + { + SCOPED_SERIALISE_CONTEXT(SHADERSOURCE); + Serialise_glShaderSource(shader, count, string, length); + + record->AddChunk(scope.Get()); + } + } +} + +bool WrappedOpenGL::Serialise_glCompileShader(GLuint shader) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ShaderRes(shader))); + + if(m_State == READING) + { + m_Real.glCompileShader(GetResourceManager()->GetLiveResource(id).name); + } + + return true; +} + +void WrappedOpenGL::glCompileShader(GLuint shader) +{ + m_Real.glCompileShader(shader); + + if(m_State >= WRITING) + { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(ShaderRes(shader)); + RDCASSERT(record); + { + SCOPED_SERIALISE_CONTEXT(COMPILESHADER); + Serialise_glCompileShader(shader); + + record->AddChunk(scope.Get()); + } + } +} + +void WrappedOpenGL::glDeleteShader(GLuint shader) +{ + m_Real.glDeleteShader(shader); + + GetResourceManager()->UnregisterResource(ShaderRes(shader)); +} + +bool WrappedOpenGL::Serialise_glAttachShader(GLuint program, GLuint shader) +{ + SERIALISE_ELEMENT(ResourceId, progid, GetResourceManager()->GetID(ProgramRes(program))); + SERIALISE_ELEMENT(ResourceId, shadid, GetResourceManager()->GetID(ShaderRes(shader))); + + if(m_State == READING) + { + ResourceId liveProgId = GetResourceManager()->GetLiveID(progid); + ResourceId liveShadId = GetResourceManager()->GetLiveID(shadid); + + m_Programs[liveProgId].shaders.push_back(liveShadId); + + m_Real.glAttachShader(GetResourceManager()->GetLiveResource(progid).name, + GetResourceManager()->GetLiveResource(shadid).name); + } + + return true; +} + +void WrappedOpenGL::glAttachShader(GLuint program, GLuint shader) +{ + m_Real.glAttachShader(program, shader); + + if(m_State >= WRITING) + { + GLResourceRecord *progRecord = GetResourceManager()->GetResourceRecord(ProgramRes(program)); + GLResourceRecord *shadRecord = GetResourceManager()->GetResourceRecord(ShaderRes(shader)); + RDCASSERT(progRecord && shadRecord); + { + SCOPED_SERIALISE_CONTEXT(ATTACHSHADER); + Serialise_glAttachShader(program, shader); + + progRecord->AddParent(shadRecord); + progRecord->AddChunk(scope.Get()); + } + } +} + +bool WrappedOpenGL::Serialise_glCreateProgram(GLuint program) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ProgramRes(program))); + + if(m_State == READING) + { + GLuint real = m_Real.glCreateProgram(); + + GLResource res = ProgramRes(real); + + m_ResourceManager->RegisterResource(res); + GetResourceManager()->AddLiveResource(id, res); + } + + return true; +} + +GLuint WrappedOpenGL::glCreateProgram() +{ + GLuint real = m_Real.glCreateProgram(); + + GLResource res = ProgramRes(real); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(CREATE_PROGRAM); + Serialise_glCreateProgram(real); + + chunk = scope.Get(); + } + + GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + + return real; +} + +bool WrappedOpenGL::Serialise_glLinkProgram(GLuint program) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ProgramRes(program))); + + if(m_State == READING) + { + m_Real.glLinkProgram(GetResourceManager()->GetLiveResource(id).name); + } + + return true; +} + +void WrappedOpenGL::glLinkProgram(GLuint program) +{ + m_Real.glLinkProgram(program); + + if(m_State >= WRITING) + { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(ProgramRes(program)); + RDCASSERT(record); + { + SCOPED_SERIALISE_CONTEXT(LINKPROGRAM); + Serialise_glLinkProgram(program); + + record->AddChunk(scope.Get()); + } + } +} + +void WrappedOpenGL::glDeleteProgram(GLuint program) +{ + m_Real.glDeleteProgram(program); + + GetResourceManager()->UnregisterResource(ProgramRes(program)); +} + +bool WrappedOpenGL::Serialise_glUseProgram(GLuint program) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ProgramRes(program))); + + if(m_State <= EXECUTING) + { + m_Real.glUseProgram(GetResourceManager()->GetLiveResource(id).name); + } + + return true; +} + +void WrappedOpenGL::glUseProgram(GLuint program) +{ + m_Real.glUseProgram(program); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(USEPROGRAM); + Serialise_glUseProgram(program); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +#pragma region Uniforms + +bool WrappedOpenGL::Serialise_glUniformMatrix(GLint location, GLsizei count, GLboolean transpose, const void *value, UniformType type) +{ + SERIALISE_ELEMENT(UniformType, Type, type); + SERIALISE_ELEMENT(GLint, Loc, location); + SERIALISE_ELEMENT(GLsizei, Count, count); + SERIALISE_ELEMENT(GLboolean, Transpose, transpose); + + size_t elemsPerMat = 0; + + switch(Type) + { + case MAT4FV: elemsPerMat = 16; break; + default: + RDCERR("Unexpected uniform type to Serialise_glUniformMatrix: %d", Type); + } + + if(m_State >= WRITING) + { + m_pSerialiser->RawWriteBytes(value, sizeof(float)*elemsPerMat*Count); + } + else if(m_State <= EXECUTING) + { + value = m_pSerialiser->RawReadBytes(sizeof(float)*elemsPerMat*Count); + + switch(Type) + { + case MAT4FV: m_Real.glUniformMatrix4fv(Loc, Count, Transpose, (const GLfloat *)value); break; + default: + RDCERR("Unexpected uniform type to Serialise_glUniformMatrix: %d", Type); + } + } + + if(m_pSerialiser->GetDebugText()) + { + switch(Type) + { + case MAT4FV: + { + float *f = (float *)value; + if(Transpose) + { + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[0], f[4], f[8], f[12]); + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[1], f[5], f[9], f[13]); + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[2], f[6], f[10], f[14]); + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[3], f[7], f[11], f[15]); + } + else + { + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[0], f[1], f[2], f[3]); + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[4], f[5], f[6], f[7]); + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[8], f[9], f[10], f[11]); + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[12], f[13], f[14], f[15]); + } + break; + } + default: + RDCERR("Unexpected uniform type to Serialise_glUniformVector: %d", Type); + } + } + + return true; +} + +void WrappedOpenGL::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + m_Real.glUniformMatrix4fv(location, count, transpose, value); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(UNIFORM_MATRIX); + Serialise_glUniformMatrix(location, count, transpose, value, MAT4FV); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glUniformVector(GLint location, GLsizei count, const void *value, UniformType type) +{ + SERIALISE_ELEMENT(UniformType, Type, type); + SERIALISE_ELEMENT(GLint, Loc, location); + SERIALISE_ELEMENT(GLsizei, Count, count); + + size_t elemsPerVec = 0; + + switch(Type) + { + case VEC3FV: elemsPerVec = 3; break; + case VEC4FV: elemsPerVec = 4; break; + default: + RDCERR("Unexpected uniform type to Serialise_glUniformVector: %d", Type); + } + + if(m_State >= WRITING) + { + m_pSerialiser->RawWriteBytes(value, sizeof(float)*elemsPerVec*Count); + } + else if(m_State <= EXECUTING) + { + value = m_pSerialiser->RawReadBytes(sizeof(float)*elemsPerVec*Count); + + switch(Type) + { + case VEC3FV: m_Real.glUniform3fv(Loc, Count, (const GLfloat *)value); break; + case VEC4FV: m_Real.glUniform4fv(Loc, Count, (const GLfloat *)value); break; + default: + RDCERR("Unexpected uniform type to Serialise_glUniformVector: %d", Type); + } + } + + if(m_pSerialiser->GetDebugText()) + { + switch(Type) + { + case VEC3FV: + { + float *f = (float *)value; + m_pSerialiser->DebugPrint("value: {%f %f %f}\n", f[0], f[1], f[2]); + break; + } + case VEC4FV: + { + float *f = (float *)value; + m_pSerialiser->DebugPrint("value: {%f %f %f %f}\n", f[0], f[1], f[2], f[3]); + break; + } + default: + RDCERR("Unexpected uniform type to Serialise_glUniformVector: %d", Type); + } + } + + return true; +} + +void WrappedOpenGL::glUniform3fv(GLint location, GLsizei count, const GLfloat *value) +{ + m_Real.glUniform3fv(location, count, value); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(UNIFORM_VECTOR); + Serialise_glUniformVector(location, count, value, VEC3FV); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glUniform4fv(GLint location, GLsizei count, const GLfloat *value) +{ + m_Real.glUniform4fv(location, count, value); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(UNIFORM_VECTOR); + Serialise_glUniformVector(location, count, value, VEC4FV); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +#pragma endregion + +#pragma endregion + +#pragma region Buffers + +bool WrappedOpenGL::Serialise_glGenBuffers(GLsizei n, GLuint* textures) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(BufferRes(*textures))); + + if(m_State == READING) + { + GLuint real = 0; + m_Real.glGenBuffers(1, &real); + + GLResource res = BufferRes(real); + + ResourceId live = m_ResourceManager->RegisterResource(res); + GetResourceManager()->AddLiveResource(id, res); + + m_Buffers[live].resource = res; + m_Buffers[live].curType = eGL_UNKNOWN_ENUM; + } + + return true; +} + +void WrappedOpenGL::glGenBuffers(GLsizei n, GLuint *buffers) +{ + m_Real.glGenBuffers(n, buffers); + + for(GLsizei i=0; i < n; i++) + { + GLResource res = BufferRes(buffers[i]); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(GEN_BUFFER); + Serialise_glGenBuffers(1, buffers+i); + + chunk = scope.Get(); + } + + GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + } +} + +size_t WrappedOpenGL::BufferIdx(GLenum buf) +{ + switch(buf) + { + case eGL_ARRAY_BUFFER: return 0; + case eGL_ELEMENT_ARRAY_BUFFER: return 1; + case eGL_UNIFORM_BUFFER: return 2; + case eGL_COPY_READ_BUFFER: return 3; + default: + RDCERR("Unexpected enum as buffer target: %hs", ToStr::Get(buf).c_str()); + } + + return 0; +} + +bool WrappedOpenGL::Serialise_glBindBuffer(GLenum target, GLuint buffer) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(ResourceId, Id, GetResourceManager()->GetID(BufferRes(buffer))); + + if(m_State >= WRITING) + { + size_t idx = BufferIdx(target); + + m_BufferRecord[idx]->datatype = Target; + } + else if(m_State < WRITING) + { + GLResource res = GetResourceManager()->GetLiveResource(Id); + m_Real.glBindBuffer(Target, res.name); + + m_Buffers[GetResourceManager()->GetLiveID(Id)].curType = Target; + } + + return true; +} + +void WrappedOpenGL::glBindBuffer(GLenum target, GLuint buffer) +{ + m_Real.glBindBuffer(target, buffer); + + if(m_State == WRITING_CAPFRAME) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(BIND_BUFFER); + Serialise_glBindBuffer(target, buffer); + + chunk = scope.Get(); + } + + m_ContextRecord->AddChunk(chunk); + } + + size_t idx = BufferIdx(target); + + if(buffer == 0) + { + m_BufferRecord[idx] = NULL; + return; + } + + if(m_State >= WRITING) + { + GLResourceRecord *r = m_BufferRecord[idx] = GetResourceManager()->GetResourceRecord(BufferRes(buffer)); + + // it's legal to re-type buffers, generate another BindBuffer chunk to rename + if(r->datatype != target) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(BIND_BUFFER); + Serialise_glBindBuffer(target, buffer); + + chunk = scope.Get(); + } + + r->AddChunk(chunk); + } + } +} + +bool WrappedOpenGL::Serialise_glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) +{ + SERIALISE_ELEMENT(GLenum, Target, target); + SERIALISE_ELEMENT(uint64_t, Bytesize, (uint64_t)size); + SERIALISE_ELEMENT_BUF(byte *, bytes, data, (size_t)Bytesize); + SERIALISE_ELEMENT(GLenum, Usage, usage); + SERIALISE_ELEMENT(ResourceId, id, m_BufferRecord[BufferIdx(target)]->GetResourceID()); + + if(m_State == READING) + { + GLResource res = GetResourceManager()->GetLiveResource(id); + m_Real.glBindBuffer(Target, res.name); + m_Real.glBufferData(Target, (GLsizeiptr)Bytesize, bytes, Usage); + + m_Buffers[GetResourceManager()->GetLiveID(id)].size = Bytesize; + + SAFE_DELETE_ARRAY(bytes); + } + + return true; +} + +void WrappedOpenGL::glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) +{ + m_Real.glBufferData(target, size, data, usage); + + size_t idx = BufferIdx(target); + + if(m_State >= WRITING) + { + RDCASSERT(m_BufferRecord[idx]); + + SCOPED_SERIALISE_CONTEXT(BUFFERDATA); + Serialise_glBufferData(target, size, data, usage); + + m_BufferRecord[idx]->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glBindBufferBase(GLenum target, GLuint index, GLuint buffer) +{ + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } + + m_Real.glBindBufferBase(target, index, buffer); +} + +void *WrappedOpenGL::glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } + + return m_Real.glMapBufferRange(target, offset, length, access); +} + +GLboolean WrappedOpenGL::glUnmapBuffer(GLenum target) +{ + if(m_State >= WRITING) + { + RDCUNIMPLEMENTED(); + } + + return m_Real.glUnmapBuffer(target); +} + +bool WrappedOpenGL::Serialise_glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) +{ + SERIALISE_ELEMENT(GLuint, Index, index); + SERIALISE_ELEMENT(GLint, Size, size); + SERIALISE_ELEMENT(GLenum, Type, type); + SERIALISE_ELEMENT(GLboolean, Norm, normalized); + SERIALISE_ELEMENT(GLsizei, Stride, stride); + SERIALISE_ELEMENT(uint64_t, Offset, (uint64_t)pointer); + SERIALISE_ELEMENT(ResourceId, id, m_VertexArrayRecord ? m_VertexArrayRecord->GetResourceID() : ResourceId()); + + if(m_State == READING) + { + if(id != ResourceId()) + { + GLResource res = GetResourceManager()->GetLiveResource(id); + m_Real.glBindVertexArray(res.name); + } + else + { + m_Real.glBindVertexArray(0); + } + + m_Real.glVertexAttribPointer(Index, Size, Type, Norm, Stride, (const void *)Offset); + } + + return true; +} + +void WrappedOpenGL::glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) +{ + m_Real.glVertexAttribPointer(index, size, type, normalized, stride, pointer); + + GLResourceRecord *r = m_VertexArrayRecord ? m_VertexArrayRecord : m_DeviceRecord; + RDCASSERT(r); + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(VERTEXATTRIBPOINTER); + Serialise_glVertexAttribPointer(index, size, type, normalized, stride, pointer); + + r->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glEnableVertexAttribArray(GLuint index) +{ + SERIALISE_ELEMENT(GLuint, Index, index); + + if(m_State == READING) + { + m_Real.glEnableVertexAttribArray(Index); + } + return true; +} + +void WrappedOpenGL::glEnableVertexAttribArray(GLuint index) +{ + m_Real.glEnableVertexAttribArray(index); + + GLResourceRecord *r = m_VertexArrayRecord ? m_VertexArrayRecord : m_DeviceRecord; + RDCASSERT(r); + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(ENABLEVERTEXATTRIBARRAY); + Serialise_glEnableVertexAttribArray(index); + + r->AddChunk(scope.Get()); + } +} + +bool WrappedOpenGL::Serialise_glGenVertexArrays(GLsizei n, GLuint* arrays) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(VertexArrayRes(*arrays))); + + if(m_State == READING) + { + GLuint real = 0; + m_Real.glGenVertexArrays(1, &real); + + GLResource res = VertexArrayRes(real); + + m_ResourceManager->RegisterResource(res); + GetResourceManager()->AddLiveResource(id, res); + } + + return true; +} + +void WrappedOpenGL::glGenVertexArrays(GLsizei n, GLuint *arrays) +{ + m_Real.glGenVertexArrays(n, arrays); + + for(GLsizei i=0; i < n; i++) + { + GLResource res = VertexArrayRes(arrays[i]); + ResourceId id = GetResourceManager()->RegisterResource(res); + + if(m_State >= WRITING) + { + Chunk *chunk = NULL; + + { + SCOPED_SERIALISE_CONTEXT(GEN_VERTEXARRAY); + Serialise_glGenVertexArrays(1, arrays+i); + + chunk = scope.Get(); + } + + GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + RDCASSERT(record); + + record->AddChunk(chunk); + } + else + { + GetResourceManager()->AddLiveResource(id, res); + } + } +} + +bool WrappedOpenGL::Serialise_glBindVertexArray(GLuint array) +{ + SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(VertexArrayRes(array))); + + if(m_State <= EXECUTING) + { + m_Real.glBindVertexArray(GetResourceManager()->GetLiveResource(id).name); + } + + return true; +} + +void WrappedOpenGL::glBindVertexArray(GLuint array) +{ + m_Real.glBindVertexArray(array); + + if(m_State >= WRITING) + { + if(array == 0) + { + m_VertexArrayRecord = NULL; + } + else + { + m_VertexArrayRecord = GetResourceManager()->GetResourceRecord(VertexArrayRes(array)); + } + } + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(BINDVERTEXARRAY); + Serialise_glBindVertexArray(array); + + m_ContextRecord->AddChunk(scope.Get()); + } +} + +void WrappedOpenGL::glDeleteBuffers(GLsizei n, const GLuint *buffers) +{ + m_Real.glDeleteBuffers(n, buffers); + + for(GLsizei i=0; i < n; i++) + GetResourceManager()->UnregisterResource(BufferRes(buffers[i])); +} + +void WrappedOpenGL::glDeleteVertexArrays(GLsizei n, const GLuint *arrays) +{ + m_Real.glDeleteVertexArrays(n, arrays); + + for(GLsizei i=0; i < n; i++) + GetResourceManager()->UnregisterResource(VertexArrayRes(arrays[i])); +} + +#pragma endregion diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp new file mode 100644 index 0000000000..3f0086da53 --- /dev/null +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -0,0 +1,1499 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" +#include "gl_driver.h" + +#include "common/string_utils.h" + +#include "replay/type_helpers.h" + +#include "maths/vec.h" + +#include "3rdparty/jpeg-compressor/jpge.h" + +const char *GLChunkNames[] = +{ + "WrappedOpenGL::Initialisation", + "glGenTextures", + "glBindTexture", + "glTexStorage2D", + "glTexSubImage2D", + "glPixelStore", + "glTexParameteri", + "glGenerateMipmap", + + "glCreateShader", + "glCreateProgram", + "glCompileShader", + "glShaderSource", + "glAttachShader", + "glLinkProgram", + + // legacy/immediate mode chunks + "glLightfv", + "glMaterialfv", + "glGenLists", + "glNewList", + "glEndList", + "glCallList", + "glShadeModel", + "glBegin", + "glEnd", + "glVertex3f", + "glNormal3f", + "glPushMatrix", + "glPopMatrix", + "glMatrixMode", + "glLoadIdentity", + "glFrustum", + "glTranslatef", + "glRotatef", + // + + "glClear", + "glClearBufferfv", + "glEnable", + "glDisable", + "glDepthFunc", + "glViewport", + "glUseProgram", + "glBindVertexArray", + "glUniformMatrix*", + "glUniformVector*", + "glDrawArrays", + "glDrawArraysInstancedBasedInstance", + + "glGenFramebuffers", + "glFramebufferTexture", + + "glGenBuffers", + "glBindBuffer", + "glBufferData", + "glGenVertexArrays", + "glBindVertexArray", + "glVertexAttribPointer", + "glEnableVertexAttribArray", + "glDeleteVertexArray", + "glDeleteBuffer", + + "glObjectLabel", + "PushMarker", + "SetMarker", + "PopMarker", + + "Capture", + "BeginCapture", + "EndCapture", +}; + +template<> +string ToStrHelper::Get(const WrappedOpenGL::UniformType &el) +{ + switch(el) + { + case WrappedOpenGL::UNIFORM_UNKNOWN: return "unk"; + case WrappedOpenGL::VEC3FV: return "3fv"; + case WrappedOpenGL::VEC4FV: return "4fv"; + case WrappedOpenGL::MAT4FV: return "4fv"; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "WrappedOpenGL::UniformType<%d>", el); + + return tostrBuf; +} + +GLInitParams::GLInitParams() +{ + SerialiseVersion = GL_SERIALISE_VERSION; + colorBits = 32; + depthBits = 32; + stencilBits = 8; + width = 32; + height = 32; +} + +ReplayCreateStatus GLInitParams::Serialise() +{ + SERIALISE_ELEMENT(uint32_t, ver, GL_SERIALISE_VERSION); SerialiseVersion = ver; + + if(ver != GL_SERIALISE_VERSION) + { + RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GL_SERIALISE_VERSION, ver); + return eReplayCreate_APIIncompatibleVersion; + } + + SERIALISE_ELEMENT(uint32_t, col, colorBits); colorBits = col; + SERIALISE_ELEMENT(uint32_t, dpth, depthBits); depthBits = dpth; + SERIALISE_ELEMENT(uint32_t, stenc, stencilBits); stencilBits = stenc; + SERIALISE_ELEMENT(uint32_t, w, width); width = w; + SERIALISE_ELEMENT(uint32_t, h, height); height = h; + + return eReplayCreate_Success; +} + +WrappedOpenGL::WrappedOpenGL(const wchar_t *logfile, const GLHookSet &funcs) + : m_Real(funcs) +{ + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedOpenGL)); + + glExts.push_back("GL_ARB_multitexture"); + +#if !defined(_RELEASE) + CaptureOptions &opts = (CaptureOptions &)RenderDoc::Inst().GetCaptureOptions(); + opts.RefAllResources = true; +#endif + + m_Replay.SetDriver(this); + + // TODO: need to check against implementation to ensure we don't claim to support + // an extension that it doesn't! + merge(glExts, glExtsString, ' '); + + m_FrameCounter = 0; + + m_FrameTimer.Restart(); + + m_TotalTime = m_AvgFrametime = m_MinFrametime = m_MaxFrametime = 0.0; + + m_CurFileSize = 0; + + m_RealDebugFunc = NULL; + m_RealDebugFuncParam = NULL; + + m_DrawcallStack.push_back(&m_ParentDrawcall); + + m_CurEventID = 1; + m_CurDrawcallID = 1; + + RDCEraseEl(m_TextureRecord); + m_TextureAlignment = 0; + m_TextureUnit = 0; + + m_LastIndexSize = eGL_UNKNOWN_ENUM; + m_LastIndexOffset = 0; + m_LastDrawMode = eGL_UNKNOWN_ENUM; + + m_DisplayListRecord = NULL; + +#if defined(RELEASE) + const bool debugSerialiser = false; +#else + const bool debugSerialiser = true; +#endif + + if(RenderDoc::Inst().IsReplayApp()) + { + m_State = READING; + if(logfile) + { + m_pSerialiser = new Serialiser(logfile, Serialiser::READING, debugSerialiser); + } + else + { + byte dummy[4]; + m_pSerialiser = new Serialiser(4, dummy, false); + } + + if(m_Real.glDebugMessageCallback) + { + m_Real.glDebugMessageCallback(&DebugSnoopStatic, this); + m_Real.glEnable(eGL_DEBUG_OUTPUT_SYNCHRONOUS); + } + } + else + { + m_State = WRITING_IDLE; + m_pSerialiser = new Serialiser(NULL, Serialiser::WRITING, debugSerialiser); + } + + m_DeviceRecord = NULL; + + m_ResourceManager = new GLResourceManager(this); + + m_DeviceResourceID = GetResourceManager()->RegisterResource(GLResource(eResSpecial, eSpecialResDevice)); + m_ContextResourceID = GetResourceManager()->RegisterResource(GLResource(eResSpecial, eSpecialResContext)); + + if(!RenderDoc::Inst().IsReplayApp()) + { + m_DeviceRecord = GetResourceManager()->AddResourceRecord(m_DeviceResourceID); + m_DeviceRecord->DataInSerialiser = false; + m_DeviceRecord->Length = 0; + m_DeviceRecord->NumSubResources = 0; + m_DeviceRecord->SpecialResource = true; + m_DeviceRecord->SubResources = NULL; + + m_ContextRecord = GetResourceManager()->AddResourceRecord(m_ContextResourceID); + m_ContextRecord->DataInSerialiser = false; + m_ContextRecord->Length = 0; + m_ContextRecord->NumSubResources = 0; + m_ContextRecord->SpecialResource = true; + m_ContextRecord->SubResources = NULL; + } + else + { + m_DeviceRecord = m_ContextRecord = NULL; + + TrackedResource::SetReplayResourceIDs(); + } + + m_FakeBB_FBO = 0; + m_FakeBB_Color = 0; + m_FakeBB_DepthStencil = 0; + + RDCDEBUG("Debug Text enabled - for development! remove before release!"); + m_pSerialiser->SetDebugText(true); + + m_pSerialiser->SetChunkNameLookup(&GetChunkName); + + ////////////////////////////////////////////////////////////////////////// + // Compile time asserts + + RDCCOMPILE_ASSERT(ARRAY_COUNT(GLChunkNames) == NUM_OPENGL_CHUNKS-FIRST_CHUNK_ID, "Not right number of chunk names"); +} + +void WrappedOpenGL::Initialise(GLInitParams ¶ms) +{ + // deliberately want to go through our own wrappers to set up e.g. m_Textures members + WrappedOpenGL &gl = *this; + + gl.glGenFramebuffers(1, &m_FakeBB_FBO); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, m_FakeBB_FBO); + + gl.glGenTextures(1, &m_FakeBB_Color); + gl.glBindTexture(eGL_TEXTURE_2D, m_FakeBB_Color); + + gl.glObjectLabel(eGL_TEXTURE, m_FakeBB_Color, -1, "Backbuffer Color"); + + GLNOTIMP("backbuffer needs to resize if the size is exceeded"); + + GLenum colfmt = eGL_RGBA8; + + if(params.colorBits == 32) + colfmt = eGL_RGBA8; + else if(params.colorBits == 24) + colfmt = eGL_RGB8; + else + RDCERR("Unexpected # colour bits: %d", params.colorBits); + + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, colfmt, params.width, params.height); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, m_FakeBB_Color, 0); + + gl.glViewport(0, 0, params.width, params.height); + + if(params.depthBits > 0 || params.stencilBits > 0) + { + gl.glGenTextures(1, &m_FakeBB_DepthStencil); + gl.glBindTexture(eGL_TEXTURE_2D, m_FakeBB_DepthStencil); + + GLenum depthfmt = eGL_DEPTH32F_STENCIL8; + bool stencil = false; + + if(params.stencilBits == 8) + { + stencil = true; + + if(params.depthBits == 32) + depthfmt = eGL_DEPTH32F_STENCIL8; + else if(params.depthBits == 24) + depthfmt = eGL_DEPTH24_STENCIL8; + else + RDCERR("Unexpected combination of depth & stencil bits: %d & %d", params.depthBits, params.stencilBits); + } + else if(params.stencilBits == 0) + { + if(params.depthBits == 32) + depthfmt = eGL_DEPTH_COMPONENT32F; + else if(params.depthBits == 24) + depthfmt = eGL_DEPTH_COMPONENT24; + else if(params.depthBits == 16) + depthfmt = eGL_DEPTH_COMPONENT16; + else + RDCERR("Unexpected # depth bits: %d", params.depthBits); + } + else + RDCERR("Unexpected # stencil bits: %d", params.stencilBits); + + if(stencil) + gl.glObjectLabel(eGL_TEXTURE, m_FakeBB_DepthStencil, -1, "Backbuffer Depth-stencil"); + else + gl.glObjectLabel(eGL_TEXTURE, m_FakeBB_DepthStencil, -1, "Backbuffer Depth"); + + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, depthfmt, params.width, params.height); + + if(stencil) + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, m_FakeBB_DepthStencil, 0); + else + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, m_FakeBB_DepthStencil, 0); + } +} + +const char * WrappedOpenGL::GetChunkName(uint32_t idx) +{ + if(idx < FIRST_CHUNK_ID || idx >= NUM_OPENGL_CHUNKS) + return ""; + return GLChunkNames[idx-FIRST_CHUNK_ID]; +} + +WrappedOpenGL::~WrappedOpenGL() +{ + SAFE_DELETE(m_pSerialiser); + + GetResourceManager()->ReleaseCurrentResource(m_DeviceResourceID); + GetResourceManager()->ReleaseCurrentResource(m_ContextResourceID); + + if(m_ContextRecord) + { + RDCASSERT(m_ContextRecord->GetRefCount() == 1); + m_ContextRecord->Delete(GetResourceManager()); + } + + if(m_DeviceRecord) + { + RDCASSERT(m_DeviceRecord->GetRefCount() == 1); + m_DeviceRecord->Delete(GetResourceManager()); + } + + m_ResourceManager->Shutdown(); + + SAFE_DELETE(m_ResourceManager); + + if(RenderDoc::Inst().GetCrashHandler()) + RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); +} + +//////////////////////////////////////////////////////////////// +// Windowing/setup/etc +//////////////////////////////////////////////////////////////// + +void WrappedOpenGL::CreateContext(void *windowHandle, void *contextHandle, void *shareContext, GLInitParams initParams) +{ + // TODO: support multiple GL contexts more explicitly + m_InitParams = initParams; +} + +void WrappedOpenGL::ActivateContext(void *windowHandle, void *contextHandle) +{ + // TODO: support multiple GL contexts more explicitly + Keyboard::AddInputWindow(windowHandle); +} + +void WrappedOpenGL::WindowSize(void *windowHandle, uint32_t w, uint32_t h) +{ + // TODO: support multiple window handles + m_InitParams.width = w; + m_InitParams.height = h; +} + +void WrappedOpenGL::Present(void *windowHandle) +{ + RenderDoc::Inst().SetCurrentDriver(RDC_OpenGL); + + if(m_State == WRITING_IDLE) + RenderDoc::Inst().Tick(); + + m_FrameCounter++; // first present becomes frame #1, this function is at the end of the frame + + if(m_State == WRITING_IDLE) + { + m_FrameTimes.push_back(m_FrameTimer.GetMilliseconds()); + m_TotalTime += m_FrameTimes.back(); + m_FrameTimer.Restart(); + + // update every second + if(m_TotalTime > 1000.0) + { + m_MinFrametime = 10000.0; + m_MaxFrametime = 0.0; + m_AvgFrametime = 0.0; + + m_TotalTime = 0.0; + + for(size_t i=0; i < m_FrameTimes.size(); i++) + { + m_AvgFrametime += m_FrameTimes[i]; + if(m_FrameTimes[i] < m_MinFrametime) + m_MinFrametime = m_FrameTimes[i]; + if(m_FrameTimes[i] > m_MaxFrametime) + m_MaxFrametime = m_FrameTimes[i]; + } + + m_AvgFrametime /= double(m_FrameTimes.size()); + + m_FrameTimes.clear(); + + RDCLOG("Frame: %d. F12/PrtScr to capture. %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)", + m_FrameCounter, m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime); + for(size_t i=0; i < m_FrameRecord.size(); i++) + RDCLOG("Captured Frame %d. Multiple frame capture not supported.\n", m_FrameRecord[i].frameInfo.frameNumber); +#if !defined(RELEASE) + RDCLOG("%llu chunks - %.2f MB", Chunk::NumLiveChunks(), float(Chunk::TotalMem())/1024.0f/1024.0f); +#endif + } + } + + // kill any current capture + if(m_State == WRITING_CAPFRAME) + { + //if(HasSuccessfulCapture()) + { + RDCLOG("Finished capture, Frame %u", m_FrameCounter); + + EndCaptureFrame(); + FinishCapture(); + + const uint32_t maxSize = 1024; + + byte *thpixels = NULL; + uint32_t thwidth = 0; + uint32_t thheight = 0; + + if(m_Real.glGetIntegerv && m_Real.glReadBuffer && m_Real.glBindFramebuffer && m_Real.glBindBuffer && m_Real.glReadPixels) + { + RDCGLenum prevReadBuf = eGL_BACK; + GLint prevBuf = 0; + GLint unpackBufBind = 0; + m_Real.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&prevReadBuf); + m_Real.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &prevBuf); + m_Real.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, &unpackBufBind); + + m_Real.glReadBuffer(eGL_BACK); + m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0); + m_Real.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); + + thwidth = m_InitParams.width; + thheight = m_InitParams.height; + + thpixels = new byte[thwidth*thheight*3]; + + m_Real.glReadPixels(0, 0, thwidth, thheight, eGL_RGB, eGL_UNSIGNED_BYTE, thpixels); + + for(uint32_t y=0; y <= thheight/2; y++) + { + for(uint32_t x=0; x < thwidth; x++) + { + byte save[3]; + save[0] = thpixels[y*(thwidth*3) + x*3 + 0]; + save[1] = thpixels[y*(thwidth*3) + x*3 + 1]; + save[2] = thpixels[y*(thwidth*3) + x*3 + 2]; + + thpixels[y*(thwidth*3) + x*3 + 0] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 0]; + thpixels[y*(thwidth*3) + x*3 + 1] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 1]; + thpixels[y*(thwidth*3) + x*3 + 2] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 2]; + + thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 0] = save[0]; + thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 1] = save[1]; + thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 2] = save[2]; + } + } + + m_Real.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, unpackBufBind); + m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevBuf); + m_Real.glReadBuffer(prevReadBuf); + } + + byte *jpgbuf = NULL; + int len = thwidth*thheight; + + if(len > 0) + { + jpgbuf = new byte[len]; + + jpge::params p; + + p.m_quality = 40; + + bool success = jpge::compress_image_to_jpeg_file_in_memory(jpgbuf, len, thwidth, thheight, 3, thpixels, p); + + if(!success) + { + RDCERR("Failed to compress to jpg"); + SAFE_DELETE_ARRAY(jpgbuf); + thwidth = 0; + thheight = 0; + } + } + + Serialiser *m_pFileSerialiser = RenderDoc::Inst().OpenWriteSerialiser(m_FrameCounter, &m_InitParams, jpgbuf, len, thwidth, thheight); + + { + SCOPED_SERIALISE_CONTEXT(DEVICE_INIT); + + SERIALISE_ELEMENT(ResourceId, immContextId, m_ContextResourceID); + + m_pFileSerialiser->Insert(scope.Get(true)); + } + + RDCDEBUG("Inserting Resource Serialisers"); + + GetResourceManager()->InsertReferencedChunks(m_pFileSerialiser); + + GetResourceManager()->InsertInitialContentsChunks(m_pSerialiser, m_pFileSerialiser); + + RDCDEBUG("Creating Capture Scope"); + + { + SCOPED_SERIALISE_CONTEXT(CAPTURE_SCOPE); + + Serialise_CaptureScope(0); + + m_pFileSerialiser->Insert(scope.Get(true)); + } + + { + RDCDEBUG("Getting Resource Record"); + + GLResourceRecord *record = m_ResourceManager->GetResourceRecord(m_ContextResourceID); + + RDCDEBUG("Accumulating context resource list"); + + map recordlist; + record->Insert(recordlist); + + RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size()); + + for(auto it = recordlist.begin(); it != recordlist.end(); ++it) + m_pFileSerialiser->Insert(it->second); + + RDCDEBUG("Done"); + } + + m_CurFileSize += m_pFileSerialiser->FlushToDisk(); + + RenderDoc::Inst().SuccessfullyWrittenLog(); + + SAFE_DELETE(m_pFileSerialiser); + + m_State = WRITING_IDLE; + + GetResourceManager()->MarkUnwrittenResources(); + + GetResourceManager()->ClearReferencedResources(); + } + } + + if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE && m_FrameRecord.empty()) + { + m_State = WRITING_CAPFRAME; + + FetchFrameRecord record; + record.frameInfo.frameNumber = m_FrameCounter+1; + m_FrameRecord.push_back(record); + + GetResourceManager()->ClearReferencedResources(); + + GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_Write); + GetResourceManager()->PrepareInitialContents(); + + AttemptCapture(); + BeginCaptureFrame(); + + RDCLOG("Starting capture, frame %u", m_FrameCounter); + } +} + +void WrappedOpenGL::Serialise_CaptureScope(uint64_t offset) +{ + SERIALISE_ELEMENT(uint32_t, FrameNumber, m_FrameCounter); + + if(m_State >= WRITING) + { + GetResourceManager()->Serialise_InitialContentsNeeded(m_pSerialiser); + } + else + { + FetchFrameRecord record; + record.frameInfo.fileOffset = offset; + record.frameInfo.firstEvent = 1;//m_pImmediateContext->GetEventID(); + record.frameInfo.frameNumber = FrameNumber; + record.frameInfo.immContextId = GetResourceManager()->GetOriginalID(m_ContextResourceID); + m_FrameRecord.push_back(record); + + GetResourceManager()->CreateInitialContents(m_pSerialiser); + } +} + +void WrappedOpenGL::EndCaptureFrame() +{ + SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER); + + bool HasCallstack = RenderDoc::Inst().GetCaptureOptions().CaptureCallstacks != 0; + m_pSerialiser->Serialise("HasCallstack", HasCallstack); + + if(HasCallstack) + { + Callstack::Stackwalk *call = Callstack::Collect(); + + RDCASSERT(call->NumLevels() < 0xff); + + size_t numLevels = call->NumLevels(); + uint64_t *stack = call->GetAddrs(); + + m_pSerialiser->Serialise("callstack", stack, numLevels); + + delete call; + } + + m_ContextRecord->AddChunk(scope.Get()); +} + +void WrappedOpenGL::AttemptCapture() +{ + m_State = WRITING_CAPFRAME; + + { + RDCDEBUG("Immediate Context %llu Attempting capture", GetContextResourceID()); + + //m_SuccessfulCapture = true; + + m_ContextRecord->LockChunks(); + while(m_ContextRecord->HasChunks()) + { + Chunk *chunk = m_ContextRecord->GetLastChunk(); + + SAFE_DELETE(chunk); + m_ContextRecord->PopChunk(); + } + m_ContextRecord->UnlockChunks(); + } +} + +bool WrappedOpenGL::Serialise_BeginCaptureFrame(bool applyInitialState) +{ + //GLRenderState state(m_pSerialiser); + + if(m_State >= WRITING) + { + //state = *m_CurrentPipelineState; + + //state.SetSerialiser(m_pSerialiser); + + //state.MarkReferenced(this, true); + } + + //state.Serialise(m_State, this); + + if(m_State <= EXECUTING && applyInitialState) + { + m_DoStateVerify = false; + { + //*m_CurrentPipelineState = state; + //state.ApplyState(this); + } + m_DoStateVerify = true; + //VerifyState(); + } + + return true; +} + +void WrappedOpenGL::BeginCaptureFrame() +{ + SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_HEADER); + + Serialise_BeginCaptureFrame(false); + + m_ContextRecord->AddChunk(scope.Get(), 1); +} + +void WrappedOpenGL::FinishCapture() +{ + m_State = WRITING_IDLE; + + //m_SuccessfulCapture = false; +} + +void WrappedOpenGL::DebugSnoop(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message) +{ + RDCLOG("Got a Debug message from %hs, type %hs, ID %d, severity %hs:\n'%hs'", + ToStr::Get(source).c_str(), ToStr::Get(type).c_str(), id, ToStr::Get(severity).c_str(), message); + + if(m_RealDebugFunc) + m_RealDebugFunc(source, type, id, severity, length, message, m_RealDebugFuncParam); +} + +void WrappedOpenGL::glDebugMessageCallback(GLDEBUGPROC callback, const void *userParam) +{ + m_RealDebugFunc = callback; + m_RealDebugFuncParam = userParam; + + m_Real.glDebugMessageCallback(&DebugSnoopStatic, this); +} + +void WrappedOpenGL::ReadLogInitialisation() +{ + uint64_t lastFrame = 0; + uint64_t firstFrame = 0; + + m_pSerialiser->SetDebugText(true); + + m_pSerialiser->Rewind(); + + while(!m_pSerialiser->AtEnd()) + { + m_pSerialiser->SkipToChunk(CAPTURE_SCOPE); + + // found a capture chunk + if(!m_pSerialiser->AtEnd()) + { + lastFrame = m_pSerialiser->GetOffset(); + if(firstFrame == 0) + firstFrame = m_pSerialiser->GetOffset(); + + // skip this chunk + m_pSerialiser->PushContext(NULL, CAPTURE_SCOPE, false); + m_pSerialiser->SkipCurrentChunk(); + m_pSerialiser->PopContext(NULL, CAPTURE_SCOPE); + } + } + + m_pSerialiser->Rewind(); + + int chunkIdx = 0; + + struct chunkinfo + { + chunkinfo() : count(0), total(0.0) {} + int count; + double total; + }; + + map chunkInfos; + + SCOPED_TIMER("chunk initialisation"); + + while(1) + { + PerformanceTimer timer; + + uint64_t offset = m_pSerialiser->GetOffset(); + + GLChunkType context = (GLChunkType)m_pSerialiser->PushContext(NULL, 1, false); + + chunkIdx++; + + ProcessChunk(offset, context); + + m_pSerialiser->PopContext(NULL, context); + + RenderDoc::Inst().SetProgress(FileInitialRead, float(m_pSerialiser->GetOffset())/float(m_pSerialiser->GetSize())); + + if(context == CAPTURE_SCOPE) + { + ContextReplayLog(READING, 0, 0, false); + + if(m_pSerialiser->GetOffset() > lastFrame) + break; + } + + chunkInfos[context].total += timer.GetMilliseconds(); + chunkInfos[context].count++; + + if(m_pSerialiser->AtEnd()) + { + break; + } + } + + for(auto it=chunkInfos.begin(); it != chunkInfos.end(); ++it) + { + RDCDEBUG("%hs: %.3f total time in %d chunks - %.3f average", + GetChunkName(it->first), it->second.total, it->second.count, + it->second.total/double(it->second.count)); + } + + RDCDEBUG("Allocating %llu persistant bytes of memory for the log.", m_pSerialiser->GetSize() - firstFrame); + + m_pSerialiser->SetDebugText(false); + + m_pSerialiser->SetBase(firstFrame); +} + +void WrappedOpenGL::ProcessChunk(uint64_t offset, GLChunkType context) +{ + switch(context) + { + case DEVICE_INIT: + { + SERIALISE_ELEMENT(ResourceId, immContextId, ResourceId()); + + m_ResourceManager->AddLiveResource(immContextId, GLResource(eResSpecial, eSpecialResContext)); + break; + } + case GEN_TEXTURE: + Serialise_glGenTextures(0, NULL); + break; + case BIND_TEXTURE: + Serialise_glBindTexture(eGL_UNKNOWN_ENUM, 0); + break; + case TEXSTORAGE2D: + Serialise_glTexStorage2D(eGL_UNKNOWN_ENUM, 0, eGL_UNKNOWN_ENUM, 0, 0); + break; + case TEXSUBIMAGE2D: + Serialise_glTexSubImage2D(eGL_UNKNOWN_ENUM, 0, 0, 0, 0, 0, eGL_UNKNOWN_ENUM, eGL_UNKNOWN_ENUM, NULL); + break; + case PIXELSTORE: + Serialise_glPixelStorei(eGL_UNKNOWN_ENUM, 0); + break; + case TEXPARAMETERI: + Serialise_glTexParameteri(eGL_UNKNOWN_ENUM, eGL_UNKNOWN_ENUM, 0); + break; + case GENERATE_MIPMAP: + Serialise_glGenerateMipmap(eGL_UNKNOWN_ENUM); + break; + + case CREATE_SHADER: + Serialise_glCreateShader(0, eGL_UNKNOWN_ENUM); + break; + case CREATE_PROGRAM: + Serialise_glCreateProgram(0); + break; + case COMPILESHADER: + Serialise_glCompileShader(0); + break; + case SHADERSOURCE: + Serialise_glShaderSource(0, 0, NULL, NULL); + break; + case ATTACHSHADER: + Serialise_glAttachShader(0, 0); + break; + case LINKPROGRAM: + Serialise_glLinkProgram(0); + break; + + + // legacy/immediate mode chunks + case LIGHTFV: + Serialise_glLightfv(eGL_UNKNOWN_ENUM, eGL_UNKNOWN_ENUM, NULL); + break; + case MATERIALFV: + Serialise_glMaterialfv(eGL_UNKNOWN_ENUM, eGL_UNKNOWN_ENUM, NULL); + break; + case GENLISTS: + Serialise_glGenLists(0); + break; + case NEWLIST: + Serialise_glNewList(0, eGL_UNKNOWN_ENUM); + break; + case ENDLIST: + Serialise_glEndList(); + break; + case CALLLIST: + Serialise_glCallList(0); + break; + case SHADEMODEL: + Serialise_glShadeModel(eGL_UNKNOWN_ENUM); + break; + case BEGIN: + Serialise_glBegin(eGL_UNKNOWN_ENUM); + break; + case END: + Serialise_glEnd(); + break; + case VERTEX3F: + Serialise_glVertex3f(0, 0, 0); + break; + case NORMAL3F: + Serialise_glNormal3f(0, 0, 0); + break; + case PUSHMATRIX: + Serialise_glPushMatrix(); + break; + case POPMATRIX: + Serialise_glPopMatrix(); + break; + case MATRIXMODE: + Serialise_glMatrixMode(eGL_UNKNOWN_ENUM); + break; + case LOADIDENTITY: + Serialise_glLoadIdentity(); + break; + case FRUSTUM: + Serialise_glFrustum(0, 0, 0, 0, 0, 0); + break; + case TRANSLATEF: + Serialise_glTranslatef(0, 0, 0); + break; + case ROTATEF: + Serialise_glRotatef(0, 0, 0, 0); + break; + // + + case CLEAR: + Serialise_glClear(0); + break; + case CLEARBUFFERF: + Serialise_glClearBufferfv(eGL_UNKNOWN_ENUM, 0, NULL); + break; + case DISABLE: + Serialise_glDisable(eGL_UNKNOWN_ENUM); + break; + case ENABLE: + Serialise_glEnable(eGL_UNKNOWN_ENUM); + break; + case DEPTH_FUNC: + Serialise_glDepthFunc(eGL_UNKNOWN_ENUM); + break; + case VIEWPORT: + Serialise_glViewport(0, 0, 0, 0); + break; + case USEPROGRAM: + Serialise_glUseProgram(0); + break; + case BINDVERTEXARRAY: + Serialise_glBindVertexArray(0); + break; + case UNIFORM_MATRIX: + Serialise_glUniformMatrix(0, 0, 0, NULL, UNIFORM_UNKNOWN); + break; + case UNIFORM_VECTOR: + Serialise_glUniformVector(0, 0, NULL, UNIFORM_UNKNOWN); + break; + case DRAWARRAYS_INSTANCEDBASEDINSTANCE: + Serialise_glDrawArraysInstancedBaseInstance(eGL_UNKNOWN_ENUM, 0, 0, 0, 0); + break; + + case GEN_BUFFER: + Serialise_glGenBuffers(0, NULL); + break; + case BIND_BUFFER: + Serialise_glBindBuffer(eGL_UNKNOWN_ENUM, 0); + break; + case BUFFERDATA: + Serialise_glBufferData(eGL_UNKNOWN_ENUM, 0, NULL, eGL_UNKNOWN_ENUM); + break; + case GEN_VERTEXARRAY: + Serialise_glGenVertexArrays(0, NULL); + break; + case BIND_VERTEXARRAY: + Serialise_glBindVertexArray(0); + break; + case VERTEXATTRIBPOINTER: + Serialise_glVertexAttribPointer(0, 0, eGL_UNKNOWN_ENUM, 0, 0, NULL); + break; + case ENABLEVERTEXATTRIBARRAY: + Serialise_glEnableVertexAttribArray(0); + break; + + case DELETE_VERTEXARRAY: + case DELETE_BUFFER: + RDCFATAL("Not impl"); + break; + + case OBJECT_LABEL: + Serialise_glObjectLabel(eGL_UNKNOWN_ENUM, 0, 0, NULL); + break; + + case CAPTURE_SCOPE: + Serialise_CaptureScope(offset); + break; + case CONTEXT_CAPTURE_FOOTER: + { + bool HasCallstack = false; + m_pSerialiser->Serialise("HasCallstack", HasCallstack); + + if(HasCallstack) + { + size_t numLevels = 0; + uint64_t *stack = NULL; + + m_pSerialiser->Serialise("callstack", stack, numLevels); + + m_pSerialiser->SetCallstack(stack, numLevels); + + SAFE_DELETE_ARRAY(stack); + } + + if(m_State == READING) + { + AddEvent(CONTEXT_CAPTURE_FOOTER, "SwapBuffers()"); + + FetchDrawcall draw; + draw.name = L"SwapBuffers()"; + draw.flags |= eDraw_Present; + + AddDrawcall(draw, true); + } + } + break; + default: + // ignore system chunks + if((int)context == (int)INITIAL_CONTENTS) + RDCERR("Initial contents not implemented yet"); + else if((int)context < (int)FIRST_CHUNK_ID) + m_pSerialiser->SkipCurrentChunk(); + else + RDCERR("Unrecognised Chunk type %d", context); + break; + } +} + +void WrappedOpenGL::ContextReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial) +{ + m_State = readType; + + m_DoStateVerify = true; + + GLChunkType header = (GLChunkType)m_pSerialiser->PushContext(NULL, 1, false); + RDCASSERT(header == CONTEXT_CAPTURE_HEADER); + + WrappedOpenGL *context = this; + + Serialise_BeginCaptureFrame(!partial); + + m_pSerialiser->PopContext(NULL, header); + + m_CurEvents.clear(); + + if(m_State == EXECUTING) + { + FetchAPIEvent ev = GetEvent(startEventID); + m_CurEventID = ev.eventID; + m_pSerialiser->SetOffset(ev.fileOffset); + } + else if(m_State == READING) + { + m_CurEventID = 1; + } + + if(m_State == EXECUTING) + { + } + + GetResourceManager()->MarkInFrame(true); + + while(1) + { + if(m_State == EXECUTING && m_CurEventID > endEventID) + { + // we can just break out if we've done all the events desired. + break; + } + + uint64_t offset = m_pSerialiser->GetOffset(); + + GLChunkType context = (GLChunkType)m_pSerialiser->PushContext(NULL, 1, false); + + ContextProcessChunk(offset, context, false); + + RenderDoc::Inst().SetProgress(FileInitialRead, float(offset)/float(m_pSerialiser->GetSize())); + + // for now just abort after capture scope. Really we'd need to support multiple frames + // but for now this will do. + if(context == CONTEXT_CAPTURE_FOOTER) + break; + + m_CurEventID++; + } + + if(m_State == READING) + { + GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake(); + + m_ParentDrawcall.children.clear(); + } + + GetResourceManager()->MarkInFrame(false); + + m_State = READING; + + m_DoStateVerify = false; +} + +void WrappedOpenGL::ContextProcessChunk(uint64_t offset, GLChunkType chunk, bool forceExecute) +{ + /* + if(chunk < FIRST_CONTEXT_CHUNK && !forceExecute) + { + if(m_State == READING) + { + GetResourceManager()->MarkInFrame(false); + + ProcessChunk(offset, chunk); + m_pSerialiser->PopContext(NULL, chunk); + + GetResourceManager()->MarkInFrame(true); + } + else if(m_State == EXECUTING) + { + m_pSerialiser->SkipCurrentChunk(); + m_pSerialiser->PopContext(NULL, chunk); + } + return; + }*/ + + m_CurChunkOffset = offset; + + uint64_t cOffs = m_pSerialiser->GetOffset(); + + WrappedOpenGL *context = this; + + LogState state = context->m_State; + + if(forceExecute) + context->m_State = EXECUTING; + else + context->m_State = m_State; + + m_AddedDrawcall = false; + + ProcessChunk(offset, chunk); + + m_pSerialiser->PopContext(NULL, chunk); + + if(context->m_State == READING && chunk == SET_MARKER) + { + // no push/pop necessary + } + else if(context->m_State == READING && chunk == BEGIN_EVENT) + { + // push down the drawcallstack to the latest drawcall + context->m_DrawcallStack.push_back(&context->m_DrawcallStack.back()->children.back()); + } + else if(context->m_State == READING && chunk == END_EVENT) + { + // refuse to pop off further than the root drawcall (mismatched begin/end events e.g.) + RDCASSERT(context->m_DrawcallStack.size() > 1); + if(context->m_DrawcallStack.size() > 1) + context->m_DrawcallStack.pop_back(); + } + else if(context->m_State == READING) + { + if(!m_AddedDrawcall) + context->AddEvent(chunk, m_pSerialiser->GetDebugStr()); + } + + m_AddedDrawcall = false; + + if(forceExecute) + context->m_State = state; +} + +void WrappedOpenGL::AddDrawcall(FetchDrawcall d, bool hasEvents) +{ + if(d.context == ResourceId()) d.context = GetResourceManager()->GetOriginalID(m_ContextResourceID); + + m_AddedDrawcall = true; + + WrappedOpenGL *context = this; + + FetchDrawcall draw = d; + draw.eventID = m_CurEventID; + draw.drawcallID = m_CurDrawcallID; + + for(int i=0; i < 8; i++) + draw.outputs[i] = ResourceId(); + + draw.depthOut = ResourceId(); + + GLNOTIMP("Hack, not getting current pipeline state framebufer binding"); + draw.outputs[0] = GetResourceManager()->GetID(TextureRes(m_FakeBB_Color)); + draw.depthOut = GetResourceManager()->GetID(TextureRes(m_FakeBB_DepthStencil)); + + m_CurDrawcallID++; + if(hasEvents) + { + vector evs; + evs.reserve(m_CurEvents.size()); + for(size_t i=0; i < m_CurEvents.size(); ) + { + if(m_CurEvents[i].context == draw.context) + { + evs.push_back(m_CurEvents[i]); + m_CurEvents.erase(m_CurEvents.begin()+i); + } + else + { + i++; + } + } + + draw.events = evs; + } + + //AddUsage(draw); + + // should have at least the root drawcall here, push this drawcall + // onto the back's children list. + if(!context->m_DrawcallStack.empty()) + { + DrawcallTreeNode node(draw); + node.children.insert(node.children.begin(), draw.children.elems, draw.children.elems+draw.children.count); + context->m_DrawcallStack.back()->children.push_back(node); + } + else + RDCERR("Somehow lost drawcall stack!"); +} + +void WrappedOpenGL::AddEvent(GLChunkType type, string description, ResourceId ctx) +{ + if(ctx == ResourceId()) ctx = GetResourceManager()->GetOriginalID(m_ContextResourceID); + + FetchAPIEvent apievent; + + apievent.context = ctx; + apievent.fileOffset = m_CurChunkOffset; + apievent.eventID = m_CurEventID; + + apievent.eventDesc = widen(description); + + Callstack::Stackwalk *stack = m_pSerialiser->GetLastCallstack(); + if(stack) + { + create_array(apievent.callstack, stack->NumLevels()); + memcpy(apievent.callstack.elems, stack->GetAddrs(), sizeof(uint64_t)*stack->NumLevels()); + } + + m_CurEvents.push_back(apievent); + + if(m_State == READING) + m_Events.push_back(apievent); +} + +FetchAPIEvent WrappedOpenGL::GetEvent(uint32_t eventID) +{ + for(size_t i=m_Events.size()-1; i > 0; i--) + { + if(m_Events[i].eventID <= eventID) + return m_Events[i]; + } + + return m_Events[0]; +} + +void WrappedOpenGL::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType) +{ + RDCASSERT(frameID < (uint32_t)m_FrameRecord.size()); + + uint64_t offs = m_FrameRecord[frameID].frameInfo.fileOffset; + + m_pSerialiser->SetOffset(offs); + + bool partial = true; + + if(startEventID == 0 && (replayType == eReplay_WithoutDraw || replayType == eReplay_Full)) + { + startEventID = m_FrameRecord[frameID].frameInfo.firstEvent; + partial = false; + } + + GLChunkType header = (GLChunkType)m_pSerialiser->PushContext(NULL, 1, false); + + RDCASSERT(header == CAPTURE_SCOPE); + + m_pSerialiser->SkipCurrentChunk(); + + m_pSerialiser->PopContext(NULL, header); + + if(!partial) + { + GetResourceManager()->ApplyInitialContents(); + GetResourceManager()->ReleaseInFrameResources(); + } + + { + if(replayType == eReplay_Full) + ContextReplayLog(EXECUTING, startEventID, endEventID, partial); + else if(replayType == eReplay_WithoutDraw) + ContextReplayLog(EXECUTING, startEventID, RDCMAX(1U,endEventID)-1, partial); + else if(replayType == eReplay_OnlyDraw) + ContextReplayLog(EXECUTING, endEventID, endEventID, partial); + else + RDCFATAL("Unexpected replay type"); + } +} + +#pragma region Get functions + +GLenum WrappedOpenGL::glGetError() +{ + return m_Real.glGetError(); +} + +void WrappedOpenGL::glGetFloatv(GLenum pname, GLfloat *params) +{ + m_Real.glGetFloatv(pname, params); +} + +void WrappedOpenGL::glGetIntegerv(GLenum pname, GLint *params) +{ + if(pname == GL_NUM_EXTENSIONS) + { + if(params) + *params = (GLint)glExts.size(); + return; + } + + m_Real.glGetIntegerv(pname, params); +} + +void WrappedOpenGL::glGetIntegeri_v(GLenum pname, GLuint index, GLint *data) +{ + m_Real.glGetIntegeri_v(pname, index, data); +} + +void WrappedOpenGL::glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + m_Real.glGetTexLevelParameteriv(target, level, pname, params); +} + +void WrappedOpenGL::glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) +{ + m_Real.glGetTexLevelParameterfv(target, level, pname, params); +} + +void WrappedOpenGL::glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + m_Real.glGetTexParameterfv(target, pname, params); +} + +void WrappedOpenGL::glGetTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + m_Real.glGetTexParameteriv(target, pname, params); +} + +void WrappedOpenGL::glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) +{ + m_Real.glGetInternalformativ(target, internalformat, pname, bufSize, params); +} + +void WrappedOpenGL::glGetInternalformati64v(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params) +{ + m_Real.glGetInternalformati64v(target, internalformat, pname, bufSize, params); +} + +void WrappedOpenGL::glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + m_Real.glGetBufferParameteriv(target, pname, params); +} + +void WrappedOpenGL::glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void *data) +{ + m_Real.glGetBufferSubData(target, offset, size, data); +} + +const GLubyte *WrappedOpenGL::glGetString(GLenum name) +{ + if(name == GL_EXTENSIONS) + { + return (const GLubyte *)glExtsString.c_str(); + } + return m_Real.glGetString(name); +} + +const GLubyte *WrappedOpenGL::glGetStringi(GLenum name, GLuint i) +{ + if(name == GL_EXTENSIONS) + { + if((size_t)i < glExts.size()) + return (const GLubyte *)glExts[i].c_str(); + + return (const GLubyte *)""; + } + return m_Real.glGetStringi(name, i); +} + +void WrappedOpenGL::glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) +{ + m_Real.glGetVertexAttribiv(index, pname, params); +} + +void WrappedOpenGL::glGetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer) +{ + m_Real.glGetVertexAttribPointerv(index, pname, pointer); +} + +void WrappedOpenGL::glGetShaderiv(GLuint shader, GLenum pname, GLint *params) +{ + m_Real.glGetShaderiv(shader, pname, params); +} + +void WrappedOpenGL::glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +{ + m_Real.glGetShaderInfoLog(shader, bufSize, length, infoLog); +} + +void WrappedOpenGL::glGetProgramiv(GLuint program, GLenum pname, GLint *params) +{ + m_Real.glGetProgramiv(program, pname, params); +} + +void WrappedOpenGL::glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +{ + m_Real.glGetProgramInfoLog(program, bufSize, length, infoLog); +} + +void WrappedOpenGL::glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params) +{ + m_Real.glGetProgramInterfaceiv(program, programInterface, pname, params); +} + +void WrappedOpenGL::glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) +{ + m_Real.glGetProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, params); +} + +void WrappedOpenGL::glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) +{ + m_Real.glGetProgramResourceName(program, programInterface, index, bufSize, length, name); +} + +GLint WrappedOpenGL::glGetUniformLocation(GLuint program, const GLchar *name) +{ + return m_Real.glGetUniformLocation(program, name); +} + +void WrappedOpenGL::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + m_Real.glGetActiveUniform(program, index, bufSize, length, size, type, name); +} + +void WrappedOpenGL::glGetUniformfv(GLuint program, GLint location, GLfloat *params) +{ + m_Real.glGetUniformfv(program, location, params); +} + +void WrappedOpenGL::glGetUniformiv(GLuint program, GLint location, GLint *params) +{ + m_Real.glGetUniformiv(program, location, params); +} + +void WrappedOpenGL::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) +{ + m_Real.glReadPixels(x, y, width, height, format, type, pixels); +} + +void WrappedOpenGL::glReadBuffer(GLenum mode) +{ + m_Real.glReadBuffer(mode); +} + +#pragma endregion diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h new file mode 100644 index 0000000000..990ad833d3 --- /dev/null +++ b/renderdoc/driver/gl/gl_driver.h @@ -0,0 +1,380 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "common/common.h" +#include "common/timing.h" + +#include "core/core.h" + +#include "replay/replay_driver.h" + +#include "gl_common.h" +#include "gl_hookset.h" +#include "gl_resources.h" +#include "gl_manager.h" +#include "gl_replay.h" + +#include +using std::list; + +struct GLInitParams : public RDCInitParams +{ + GLInitParams(); + ReplayCreateStatus Serialise(); + + uint32_t colorBits; + uint32_t depthBits; + uint32_t stencilBits; + uint32_t width; + uint32_t height; + + static const uint32_t GL_SERIALISE_VERSION = 0x0000002; + + // version number internal to opengl stream + uint32_t SerialiseVersion; +}; + +struct DrawcallTreeNode +{ + DrawcallTreeNode() {} + explicit DrawcallTreeNode(FetchDrawcall d) : draw(d) {} + FetchDrawcall draw; + vector children; + + DrawcallTreeNode &operator =(FetchDrawcall d) { *this = DrawcallTreeNode(d); return *this; } + + rdctype::array Bake() + { + rdctype::array ret; + if(children.empty()) return ret; + + create_array_uninit(ret, children.size()); + for(size_t i=0; i < children.size(); i++) + { + ret.elems[i] = children[i].draw; + ret.elems[i].children = children[i].Bake(); + } + + return ret; + } +}; + +class WrappedOpenGL +{ + private: + const GLHookSet &m_Real; + + friend class GLReplay; + + GLDEBUGPROC m_RealDebugFunc; + const void *m_RealDebugFuncParam; + + void DebugSnoop(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message); + static void APIENTRY DebugSnoopStatic(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) + { ((WrappedOpenGL *)userParam)->DebugSnoop(source, type, id, severity, length, message); } + + // state + GLResourceRecord *m_TextureRecord[128]; + GLResourceRecord *m_BufferRecord[16]; + GLResourceRecord *m_VertexArrayRecord; + GLint m_TextureUnit; + GLint m_TextureAlignment; + + size_t BufferIdx(GLenum buf); + + // internals + Serialiser *m_pSerialiser; + LogState m_State; + + GLReplay m_Replay; + + GLInitParams m_InitParams; + + ResourceId m_DeviceResourceID; + GLResourceRecord *m_DeviceRecord; + + ResourceId m_ContextResourceID; + GLResourceRecord *m_ContextRecord; + + GLResourceRecord *m_DisplayListRecord; + + GLResourceManager *m_ResourceManager; + + uint32_t m_FrameCounter; + + uint64_t m_CurFileSize; + + PerformanceTimer m_FrameTimer; + vector m_FrameTimes; + double m_TotalTime, m_AvgFrametime, m_MinFrametime, m_MaxFrametime; + + vector m_FrameRecord; + + static const char *GetChunkName(uint32_t idx); + + // replay + + vector m_CurEvents, m_Events; + bool m_AddedDrawcall; + + uint64_t m_CurChunkOffset; + uint32_t m_CurEventID, m_CurDrawcallID; + + DrawcallTreeNode m_ParentDrawcall; + + list m_DrawcallStack; + + GLenum m_LastIndexSize; + GLuint m_LastIndexOffset; + GLenum m_LastDrawMode; + + struct BufferData + { + GLResource resource; + GLenum curType; + uint64_t size; + }; + + map m_Buffers; + + struct TextureData + { + TextureData() : width(0), height(0), depth(0) {} + GLResource resource; + GLenum curType; + GLint width, height, depth; + }; + + map m_Textures; + + struct ShaderData + { + GLenum type; + vector sources; + ShaderReflection reflection; + }; + + struct ProgramData + { + ProgramData() : colOutProg(0) {} + vector shaders; + + GLuint colOutProg; + }; + + map m_Shaders; + map m_Programs; + + GLuint m_FakeBB_FBO; + GLuint m_FakeBB_Color; + GLuint m_FakeBB_DepthStencil; + + bool m_DoStateVerify; + //GLRenderState *m_CurrentPipelineState; + + Serialiser *GetSerialiser() { return m_pSerialiser; } + + void ProcessChunk(uint64_t offset, GLChunkType context); + void ContextReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial); + void ContextProcessChunk(uint64_t offset, GLChunkType chunk, bool forceExecute); + void AddDrawcall(FetchDrawcall d, bool hasEvents); + void AddEvent(GLChunkType type, string description, ResourceId ctx = ResourceId()); + + void Serialise_CaptureScope(uint64_t offset); + bool HasSuccessfulCapture(); + void AttemptCapture(); + bool Serialise_BeginCaptureFrame(bool applyInitialState); + void BeginCaptureFrame(); + void FinishCapture(); + void EndCaptureFrame(); + + vector glExts; + string glExtsString; + + // no copy semantics + WrappedOpenGL(const WrappedOpenGL &); + WrappedOpenGL &operator =(const WrappedOpenGL &); + + public: + WrappedOpenGL(const wchar_t *logfile, const GLHookSet &funcs); + ~WrappedOpenGL(); + + GLResourceManager *GetResourceManager() { return m_ResourceManager; } + + ResourceId GetDeviceResourceID() { return m_DeviceResourceID; } + ResourceId GetContextResourceID() { return m_ContextResourceID; } + + GLReplay *GetReplay() { return &m_Replay; } + + // replay interface + void Initialise(GLInitParams ¶ms); + void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); + void ReadLogInitialisation(); + + vector &GetFrameRecord() { return m_FrameRecord; } + FetchAPIEvent GetEvent(uint32_t eventID); + + void CreateContext(void *windowHandle, void *contextHandle, void *shareContext, GLInitParams initParams); + void ActivateContext(void *windowHandle, void *contextHandle); + void WindowSize(void *windowHandle, uint32_t w, uint32_t h); + void Present(void *windowHandle); + + // legacy/immediate mode + IMPLEMENT_FUNCTION_SERIALISED(void, glLightfv(GLenum light, GLenum pname, const GLfloat *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glMaterialfv(GLenum face, GLenum pname, const GLfloat *params)); + IMPLEMENT_FUNCTION_SERIALISED(GLuint, glGenLists(GLsizei range)); + IMPLEMENT_FUNCTION_SERIALISED(void, glNewList(GLuint list, GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glEndList()); + IMPLEMENT_FUNCTION_SERIALISED(void, glCallList(GLuint list)); + IMPLEMENT_FUNCTION_SERIALISED(void, glShadeModel(GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBegin(GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glEnd()); + IMPLEMENT_FUNCTION_SERIALISED(void, glVertex3f(GLfloat x, GLfloat y, GLfloat z)); + IMPLEMENT_FUNCTION_SERIALISED(void, glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)); + IMPLEMENT_FUNCTION_SERIALISED(void, glPushMatrix()); + IMPLEMENT_FUNCTION_SERIALISED(void, glPopMatrix()); + IMPLEMENT_FUNCTION_SERIALISED(void, glMatrixMode(GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glLoadIdentity()); + IMPLEMENT_FUNCTION_SERIALISED(void, glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)); + IMPLEMENT_FUNCTION_SERIALISED(void, glTranslatef(GLfloat x, GLfloat y, GLfloat z)); + IMPLEMENT_FUNCTION_SERIALISED(void, glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)); + // + + IMPLEMENT_FUNCTION_SERIALISED(void, glBindTexture(GLenum target, GLuint texture)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBlendFunc(GLenum sfactor, GLenum dfactor)); + IMPLEMENT_FUNCTION_SERIALISED(void, glClear(GLbitfield mask)); + IMPLEMENT_FUNCTION_SERIALISED(void, glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)); + IMPLEMENT_FUNCTION_SERIALISED(void, glClearDepth(GLclampd depth)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDepthFunc(GLenum func)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDisable(GLenum cap)); + IMPLEMENT_FUNCTION_SERIALISED(void, glEnable(GLenum cap)); + IMPLEMENT_FUNCTION_SERIALISED(GLenum, glGetError()); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetFloatv(GLenum pname, GLfloat *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetIntegerv(GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetIntegeri_v(GLenum target, GLuint index, GLint *data)); + IMPLEMENT_FUNCTION_SERIALISED(const GLubyte *, glGetStringi(GLenum name, GLuint i)); + IMPLEMENT_FUNCTION_SERIALISED(const GLubyte *, glGetString(GLenum name)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGenTextures(GLsizei n, GLuint* textures)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDeleteTextures(GLsizei n, const GLuint *textures)); + IMPLEMENT_FUNCTION_SERIALISED(void, glHint(GLenum target, GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glPixelStorei(GLenum pname, GLint param)); + IMPLEMENT_FUNCTION_SERIALISED(void, glPixelStoref(GLenum pname, GLfloat param)); + IMPLEMENT_FUNCTION_SERIALISED(void, glPolygonMode(GLenum face, GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)); + IMPLEMENT_FUNCTION_SERIALISED(void, glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels)); + IMPLEMENT_FUNCTION_SERIALISED(void, glTexParameteri(GLenum target, GLenum pname, GLint param)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGenSamplers(GLsizei count, GLuint *samplers)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBindSampler(GLuint unit, GLuint sampler)); + IMPLEMENT_FUNCTION_SERIALISED(void, glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)); + IMPLEMENT_FUNCTION_SERIALISED(void, glViewport(GLint x, GLint y, GLsizei width, GLsizei height)); + IMPLEMENT_FUNCTION_SERIALISED(void, glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)); + IMPLEMENT_FUNCTION_SERIALISED(void, glReadBuffer(GLenum mode)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGenFramebuffers(GLsizei n, GLuint *framebuffers)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBindFramebuffer(GLenum target, GLuint framebuffer)); + IMPLEMENT_FUNCTION_SERIALISED(void, glFramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params)); + + IMPLEMENT_FUNCTION_SERIALISED(void, glGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label)); + IMPLEMENT_FUNCTION_SERIALISED(void, glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label)); + + IMPLEMENT_FUNCTION_SERIALISED(void, glDebugMessageCallback(GLDEBUGPROC callback, const void *userParam)); + IMPLEMENT_FUNCTION_SERIALISED(void, glActiveTexture(GLenum texture)); + IMPLEMENT_FUNCTION_SERIALISED(void, glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)); + IMPLEMENT_FUNCTION_SERIALISED(void, glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGenerateMipmap(GLenum target)); + + IMPLEMENT_FUNCTION_SERIALISED(void, glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetTexParameteriv(GLenum target, GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetInternalformati64v(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params)); + + bool Serialise_glCreateShader(GLuint real, GLenum type); + GLuint glCreateShader(GLenum type); + + bool Serialise_glCreateProgram(GLuint real); + GLuint glCreateProgram(); + + IMPLEMENT_FUNCTION_SERIALISED(void, glDeleteShader(GLuint shader)); + IMPLEMENT_FUNCTION_SERIALISED(void, glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length)); + IMPLEMENT_FUNCTION_SERIALISED(void, glCompileShader(GLuint shader)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetShaderiv(GLuint shader, GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)); + IMPLEMENT_FUNCTION_SERIALISED(void, glAttachShader(GLuint program, GLuint shader)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDeleteProgram(GLuint program)); + IMPLEMENT_FUNCTION_SERIALISED(void, glLinkProgram(GLuint program)); + IMPLEMENT_FUNCTION_SERIALISED(void, glUseProgram(GLuint program)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetProgramiv(GLuint program, GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGenBuffers(GLsizei n, GLuint *buffers)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBindBuffer(GLenum target, GLuint buffer)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBindBufferBase(GLenum target, GLuint index, GLuint buffer)); + IMPLEMENT_FUNCTION_SERIALISED(void *, glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)); + IMPLEMENT_FUNCTION_SERIALISED(GLboolean, glUnmapBuffer(GLenum target)); + + IMPLEMENT_FUNCTION_SERIALISED(void, glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)); + IMPLEMENT_FUNCTION_SERIALISED(void, glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer)); + IMPLEMENT_FUNCTION_SERIALISED(void, glEnableVertexAttribArray(GLuint index)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGenVertexArrays(GLsizei n, GLuint *arrays)); + IMPLEMENT_FUNCTION_SERIALISED(void, glBindVertexArray(GLuint array)); + IMPLEMENT_FUNCTION_SERIALISED(GLint, glGetUniformLocation(GLuint program, const GLchar *name)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetUniformfv(GLuint program, GLint location, GLfloat *params)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetUniformiv(GLuint program, GLint location, GLint *params)); + + enum UniformType + { + UNIFORM_UNKNOWN, + + VEC3FV, + VEC4FV, + + MAT4FV, + }; + + bool Serialise_glUniformMatrix(GLint location, GLsizei count, GLboolean transpose, const void *value, UniformType type); + bool Serialise_glUniformVector(GLint location, GLsizei count, const void *value, UniformType type); + + IMPLEMENT_FUNCTION_SERIALISED(void, glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)); + IMPLEMENT_FUNCTION_SERIALISED(void, glUniform3fv(GLint location, GLsizei count, const GLfloat *value)); + IMPLEMENT_FUNCTION_SERIALISED(void, glUniform4fv(GLint location, GLsizei count, const GLfloat *value)); + + IMPLEMENT_FUNCTION_SERIALISED(void, glDrawArrays(GLenum mode, GLint first, GLsizei count)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDeleteBuffers(GLsizei n, const GLuint *buffers)); + IMPLEMENT_FUNCTION_SERIALISED(void, glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void *data)); + IMPLEMENT_FUNCTION_SERIALISED(void, glDeleteVertexArrays(GLsizei n, const GLuint *arrays)); +}; diff --git a/renderdoc/driver/gl/gl_enum.h b/renderdoc/driver/gl/gl_enum.h new file mode 100644 index 0000000000..1ca5d970e0 --- /dev/null +++ b/renderdoc/driver/gl/gl_enum.h @@ -0,0 +1,4640 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +// egrep -ih '#define[ \t]*[A-Z_0-9]*[ \t]*0x[0-9A-F]{4,}\s*$' glcorearb.h glext.h wglext.h glxext.h +// | awk '{print $2" "$3}' | sed -e '{s%\(.*\) \(.*\)%\te\1 = \2,%g}' | sort -u + +enum RDCGLenum +{ + eGL_UNKNOWN_ENUM = 0x0, + eERROR_INCOMPATIBLE_AFFINITY_MASKS_NV = 0x20D0, + eERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB = 0x2054, + eERROR_INVALID_PIXEL_TYPE_ARB = 0x2043, + eERROR_INVALID_PIXEL_TYPE_EXT = 0x2043, + eERROR_INVALID_PROFILE_ARB = 0x2096, + eERROR_INVALID_VERSION_ARB = 0x2095, + eERROR_MISSING_AFFINITY_MASK_NV = 0x20D1, + eGLX_ACCUM_BUFFER_BIT = 0x00000080, + eGLX_ACCUM_BUFFER_BIT_SGIX = 0x00000080, + eGLX_AUX0_EXT = 0x20E2, + eGLX_AUX1_EXT = 0x20E3, + eGLX_AUX2_EXT = 0x20E4, + eGLX_AUX3_EXT = 0x20E5, + eGLX_AUX4_EXT = 0x20E6, + eGLX_AUX5_EXT = 0x20E7, + eGLX_AUX6_EXT = 0x20E8, + eGLX_AUX7_EXT = 0x20E9, + eGLX_AUX8_EXT = 0x20EA, + eGLX_AUX9_EXT = 0x20EB, + eGLX_AUX_BUFFERS_BIT = 0x00000010, + eGLX_AUX_BUFFERS_BIT_SGIX = 0x00000010, + eGLX_BACK_BUFFER_AGE_EXT = 0x20F4, + eGLX_BACK_EXT = 0x20E0, + eGLX_BACK_LEFT_BUFFER_BIT = 0x00000004, + eGLX_BACK_LEFT_BUFFER_BIT_SGIX = 0x00000004, + eGLX_BACK_LEFT_EXT = 0x20E0, + eGLX_BACK_RIGHT_BUFFER_BIT = 0x00000008, + eGLX_BACK_RIGHT_BUFFER_BIT_SGIX = 0x00000008, + eGLX_BACK_RIGHT_EXT = 0x20E1, + eGLX_BIND_TO_MIPMAP_TEXTURE_EXT = 0x20D2, + eGLX_BIND_TO_TEXTURE_RGBA_EXT = 0x20D1, + eGLX_BIND_TO_TEXTURE_RGB_EXT = 0x20D0, + eGLX_BIND_TO_TEXTURE_TARGETS_EXT = 0x20D3, + eGLX_BLENDED_RGBA_SGIS = 0x8025, + eGLX_BUFFER_CLOBBER_MASK_SGIX = 0x08000000, + eGLX_BUFFER_SWAP_COMPLETE_INTEL_MASK = 0x04000000, + eGLX_COLOR_INDEX_BIT = 0x00000002, + eGLX_COLOR_INDEX_BIT_SGIX = 0x00000002, + eGLX_COLOR_INDEX_TYPE = 0x8015, + eGLX_COLOR_INDEX_TYPE_SGIX = 0x8015, + eGLX_COLOR_SAMPLES_NV = 0x20B3, + eGLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB = 0x2095, + eGLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002, + eGLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001, + eGLX_CONTEXT_DEBUG_BIT_ARB = 0x00000001, + eGLX_CONTEXT_ES2_PROFILE_BIT_EXT = 0x00000004, + eGLX_CONTEXT_ES_PROFILE_BIT_EXT = 0x00000004, + eGLX_CONTEXT_FLAGS_ARB = 0x2094, + eGLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002, + eGLX_CONTEXT_MAJOR_VERSION_ARB = 0x2091, + eGLX_CONTEXT_MINOR_VERSION_ARB = 0x2092, + eGLX_CONTEXT_PROFILE_MASK_ARB = 0x9126, + eGLX_CONTEXT_RESET_ISOLATION_BIT_ARB = 0x00000008, + eGLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB = 0x8256, + eGLX_CONTEXT_ROBUST_ACCESS_BIT_ARB = 0x00000004, + eGLX_COPY_COMPLETE_INTEL = 0x8181, + eGLX_DAMAGED = 0x8020, + eGLX_DAMAGED_SGIX = 0x8020, + eGLX_DEPTH_BUFFER_BIT = 0x00000020, + eGLX_DEPTH_BUFFER_BIT_SGIX = 0x00000020, + eGLX_DEVICE_ID_NV = 0x20CD, + eGLX_DIGITAL_MEDIA_PBUFFER_SGIX = 0x8024, + eGLX_DIRECT_COLOR = 0x8003, + eGLX_DIRECT_COLOR_EXT = 0x8003, + eGLX_DONT_CARE = 0xFFFFFFFF, + eGLX_DRAWABLE_TYPE = 0x8010, + eGLX_DRAWABLE_TYPE_SGIX = 0x8010, + eGLX_EVENT_MASK = 0x801F, + eGLX_EVENT_MASK_SGIX = 0x801F, + eGLX_EXCHANGE_COMPLETE_INTEL = 0x8180, + eGLX_FBCONFIG_ID = 0x8013, + eGLX_FBCONFIG_ID_SGIX = 0x8013, + eGLX_FLIP_COMPLETE_INTEL = 0x8182, + eGLX_FLOAT_COMPONENTS_NV = 0x20B0, + eGLX_FRAMEBUFFER_SRGB_CAPABLE_ARB = 0x20B2, + eGLX_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x20B2, + eGLX_FRONT_EXT = 0x20DE, + eGLX_FRONT_LEFT_BUFFER_BIT = 0x00000001, + eGLX_FRONT_LEFT_BUFFER_BIT_SGIX = 0x00000001, + eGLX_FRONT_LEFT_EXT = 0x20DE, + eGLX_FRONT_RIGHT_BUFFER_BIT = 0x00000002, + eGLX_FRONT_RIGHT_BUFFER_BIT_SGIX = 0x00000002, + eGLX_FRONT_RIGHT_EXT = 0x20DF, + eGLX_GPU_CLOCK_AMD = 0x21A4, + eGLX_GPU_FASTEST_TARGET_GPUS_AMD = 0x21A2, + eGLX_GPU_NUM_PIPES_AMD = 0x21A5, + eGLX_GPU_NUM_RB_AMD = 0x21A7, + eGLX_GPU_NUM_SIMD_AMD = 0x21A6, + eGLX_GPU_NUM_SPI_AMD = 0x21A8, + eGLX_GPU_OPENGL_VERSION_STRING_AMD = 0x1F02, + eGLX_GPU_RAM_AMD = 0x21A3, + eGLX_GPU_RENDERER_STRING_AMD = 0x1F01, + eGLX_GPU_VENDOR_AMD = 0x1F00, + eGLX_GRAY_SCALE = 0x8006, + eGLX_GRAY_SCALE_EXT = 0x8006, + eGLX_HEIGHT = 0x801E, + eGLX_HEIGHT_SGIX = 0x801E, + eGLX_HYPERPIPE_DISPLAY_PIPE_SGIX = 0x00000001, + eGLX_HYPERPIPE_ID_SGIX = 0x8030, + eGLX_HYPERPIPE_PIXEL_AVERAGE_SGIX = 0x00000004, + eGLX_HYPERPIPE_RENDER_PIPE_SGIX = 0x00000002, + eGLX_HYPERPIPE_STEREO_SGIX = 0x00000003, + eGLX_LARGEST_PBUFFER = 0x801C, + eGLX_LARGEST_PBUFFER_SGIX = 0x801C, + eGLX_LATE_SWAPS_TEAR_EXT = 0x20F3, + eGLX_LOSE_CONTEXT_ON_RESET_ARB = 0x8252, + eGLX_MAX_PBUFFER_HEIGHT = 0x8017, + eGLX_MAX_PBUFFER_HEIGHT_SGIX = 0x8017, + eGLX_MAX_PBUFFER_PIXELS = 0x8018, + eGLX_MAX_PBUFFER_PIXELS_SGIX = 0x8018, + eGLX_MAX_PBUFFER_WIDTH = 0x8016, + eGLX_MAX_PBUFFER_WIDTH_SGIX = 0x8016, + eGLX_MAX_SWAP_INTERVAL_EXT = 0x20F2, + eGLX_MIPMAP_TEXTURE_EXT = 0x20D7, + eGLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS = 0x8027, + eGLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS = 0x8026, + eGLX_NONE = 0x8000, + eGLX_NONE_EXT = 0x8000, + eGLX_NON_CONFORMANT_CONFIG = 0x800D, + eGLX_NON_CONFORMANT_VISUAL_EXT = 0x800D, + eGLX_NO_RESET_NOTIFICATION_ARB = 0x8261, + eGLX_NUM_VIDEO_CAPTURE_SLOTS_NV = 0x20CF, + eGLX_NUM_VIDEO_SLOTS_NV = 0x20F0, + eGLX_OPTIMAL_PBUFFER_HEIGHT_SGIX = 0x801A, + eGLX_OPTIMAL_PBUFFER_WIDTH_SGIX = 0x8019, + eGLX_PBUFFER = 0x8023, + eGLX_PBUFFER_BIT = 0x00000004, + eGLX_PBUFFER_BIT_SGIX = 0x00000004, + eGLX_PBUFFER_CLOBBER_MASK = 0x08000000, + eGLX_PBUFFER_HEIGHT = 0x8040, + eGLX_PBUFFER_SGIX = 0x8023, + eGLX_PBUFFER_WIDTH = 0x8041, + eGLX_PIPE_RECT_LIMITS_SGIX = 0x00000002, + eGLX_PIPE_RECT_SGIX = 0x00000001, + eGLX_PIXMAP_BIT = 0x00000002, + eGLX_PIXMAP_BIT_SGIX = 0x00000002, + eGLX_PRESERVED_CONTENTS = 0x801B, + eGLX_PRESERVED_CONTENTS_SGIX = 0x801B, + eGLX_PSEUDO_COLOR = 0x8004, + eGLX_PSEUDO_COLOR_EXT = 0x8004, + eGLX_RENDERER_ACCELERATED_MESA = 0x8186, + eGLX_RENDERER_DEVICE_ID_MESA = 0x8184, + eGLX_RENDERER_ID_MESA = 0x818E, + eGLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA = 0x818B, + eGLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA = 0x818A, + eGLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA = 0x818D, + eGLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA = 0x818C, + eGLX_RENDERER_PREFERRED_PROFILE_MESA = 0x8189, + eGLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA = 0x8188, + eGLX_RENDERER_VENDOR_ID_MESA = 0x8183, + eGLX_RENDERER_VERSION_MESA = 0x8185, + eGLX_RENDERER_VIDEO_MEMORY_MESA = 0x8187, + eGLX_RENDER_TYPE = 0x8011, + eGLX_RENDER_TYPE_SGIX = 0x8011, + eGLX_RGBA_BIT = 0x00000001, + eGLX_RGBA_BIT_SGIX = 0x00000001, + eGLX_RGBA_FLOAT_BIT_ARB = 0x00000004, + eGLX_RGBA_FLOAT_TYPE_ARB = 0x20B9, + eGLX_RGBA_TYPE = 0x8014, + eGLX_RGBA_TYPE_SGIX = 0x8014, + eGLX_RGBA_UNSIGNED_FLOAT_BIT_EXT = 0x00000008, + eGLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT = 0x20B1, + eGLX_SAMPLES_3DFX = 0x8051, + eGLX_SAMPLE_BUFFERS_3DFX = 0x8050, + eGLX_SAMPLE_BUFFERS_BIT_SGIX = 0x00000100, + eGLX_SAVED = 0x8021, + eGLX_SAVED_SGIX = 0x8021, + eGLX_SCREEN = 0x800C, + eGLX_SCREEN_EXT = 0x800C, + eGLX_SHARE_CONTEXT_EXT = 0x800A, + eGLX_SLOW_CONFIG = 0x8001, + eGLX_SLOW_VISUAL_EXT = 0x8001, + eGLX_STATIC_COLOR = 0x8005, + eGLX_STATIC_COLOR_EXT = 0x8005, + eGLX_STATIC_GRAY = 0x8007, + eGLX_STATIC_GRAY_EXT = 0x8007, + eGLX_STENCIL_BUFFER_BIT = 0x00000040, + eGLX_STENCIL_BUFFER_BIT_SGIX = 0x00000040, + eGLX_STEREO_NOTIFY_EXT = 0x00000000, + eGLX_STEREO_NOTIFY_MASK_EXT = 0x00000001, + eGLX_STEREO_TREE_EXT = 0x20F5, + eGLX_SWAP_COPY_OML = 0x8062, + eGLX_SWAP_EXCHANGE_OML = 0x8061, + eGLX_SWAP_INTERVAL_EXT = 0x20F1, + eGLX_SWAP_METHOD_OML = 0x8060, + eGLX_SWAP_UNDEFINED_OML = 0x8063, + eGLX_SYNC_FRAME_SGIX = 0x00000000, + eGLX_SYNC_SWAP_SGIX = 0x00000001, + eGLX_TEXTURE_1D_BIT_EXT = 0x00000001, + eGLX_TEXTURE_1D_EXT = 0x20DB, + eGLX_TEXTURE_2D_BIT_EXT = 0x00000002, + eGLX_TEXTURE_2D_EXT = 0x20DC, + eGLX_TEXTURE_FORMAT_EXT = 0x20D5, + eGLX_TEXTURE_FORMAT_NONE_EXT = 0x20D8, + eGLX_TEXTURE_FORMAT_RGBA_EXT = 0x20DA, + eGLX_TEXTURE_FORMAT_RGB_EXT = 0x20D9, + eGLX_TEXTURE_RECTANGLE_BIT_EXT = 0x00000004, + eGLX_TEXTURE_RECTANGLE_EXT = 0x20DD, + eGLX_TEXTURE_TARGET_EXT = 0x20D6, + eGLX_TRANSPARENT_INDEX = 0x8009, + eGLX_TRANSPARENT_INDEX_EXT = 0x8009, + eGLX_TRANSPARENT_RGB = 0x8008, + eGLX_TRANSPARENT_RGB_EXT = 0x8008, + eGLX_TRUE_COLOR = 0x8002, + eGLX_TRUE_COLOR_EXT = 0x8002, + eGLX_UNIQUE_ID_NV = 0x20CE, + eGLX_VIDEO_OUT_ALPHA_NV = 0x20C4, + eGLX_VIDEO_OUT_COLOR_AND_ALPHA_NV = 0x20C6, + eGLX_VIDEO_OUT_COLOR_AND_DEPTH_NV = 0x20C7, + eGLX_VIDEO_OUT_COLOR_NV = 0x20C3, + eGLX_VIDEO_OUT_DEPTH_NV = 0x20C5, + eGLX_VIDEO_OUT_FIELD_1_NV = 0x20C9, + eGLX_VIDEO_OUT_FIELD_2_NV = 0x20CA, + eGLX_VIDEO_OUT_FRAME_NV = 0x20C8, + eGLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV = 0x20CB, + eGLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV = 0x20CC, + eGLX_VISUAL_ID = 0x800B, + eGLX_VISUAL_ID_EXT = 0x800B, + eGLX_VISUAL_SELECT_GROUP_SGIX = 0x8028, + eGLX_WIDTH = 0x801D, + eGLX_WIDTH_SGIX = 0x801D, + eGLX_WINDOW = 0x8022, + eGLX_WINDOW_BIT = 0x00000001, + eGLX_WINDOW_BIT_SGIX = 0x00000001, + eGLX_WINDOW_SGIX = 0x8022, + eGLX_X_RENDERABLE = 0x8012, + eGLX_X_RENDERABLE_SGIX = 0x8012, + eGLX_Y_INVERTED_EXT = 0x20D4, + eGL_1PASS_EXT = 0x80A1, + eGL_1PASS_SGIS = 0x80A1, + eGL_2PASS_0_EXT = 0x80A2, + eGL_2PASS_0_SGIS = 0x80A2, + eGL_2PASS_1_EXT = 0x80A3, + eGL_2PASS_1_SGIS = 0x80A3, + eGL_2X_BIT_ATI = 0x00000001, + eGL_422_AVERAGE_EXT = 0x80CE, + eGL_422_EXT = 0x80CC, + eGL_422_REV_AVERAGE_EXT = 0x80CF, + eGL_422_REV_EXT = 0x80CD, + eGL_4PASS_0_EXT = 0x80A4, + eGL_4PASS_0_SGIS = 0x80A4, + eGL_4PASS_1_EXT = 0x80A5, + eGL_4PASS_1_SGIS = 0x80A5, + eGL_4PASS_2_EXT = 0x80A6, + eGL_4PASS_2_SGIS = 0x80A6, + eGL_4PASS_3_EXT = 0x80A7, + eGL_4PASS_3_SGIS = 0x80A7, + eGL_4X_BIT_ATI = 0x00000002, + eGL_8X_BIT_ATI = 0x00000004, + eGL_ABGR_EXT = 0x8000, + eGL_ACCUM_ADJACENT_PAIRS_NV = 0x90AD, + eGL_ACTIVE_ATOMIC_COUNTER_BUFFERS = 0x92D9, + eGL_ACTIVE_ATTRIBUTES = 0x8B89, + eGL_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A, + eGL_ACTIVE_PROGRAM = 0x8259, + eGL_ACTIVE_PROGRAM_EXT = 0x8B8D, + eGL_ACTIVE_RESOURCES = 0x92F5, + eGL_ACTIVE_STENCIL_FACE_EXT = 0x8911, + eGL_ACTIVE_SUBROUTINES = 0x8DE5, + eGL_ACTIVE_SUBROUTINE_MAX_LENGTH = 0x8E48, + eGL_ACTIVE_SUBROUTINE_UNIFORMS = 0x8DE6, + eGL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS = 0x8E47, + eGL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH = 0x8E49, + eGL_ACTIVE_TEXTURE = 0x84E0, + eGL_ACTIVE_TEXTURE_ARB = 0x84E0, + eGL_ACTIVE_UNIFORMS = 0x8B86, + eGL_ACTIVE_UNIFORM_BLOCKS = 0x8A36, + eGL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = 0x8A35, + eGL_ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87, + eGL_ACTIVE_VARIABLES = 0x9305, + eGL_ACTIVE_VARYINGS_NV = 0x8C81, + eGL_ACTIVE_VARYING_MAX_LENGTH_NV = 0x8C82, + eGL_ACTIVE_VERTEX_UNITS_ARB = 0x86A5, + eGL_ADD_ATI = 0x8963, + eGL_ADD_SIGNED = 0x8574, + eGL_ADD_SIGNED_ARB = 0x8574, + eGL_ADD_SIGNED_EXT = 0x8574, + eGL_ADJACENT_PAIRS_NV = 0x90AE, + eGL_AFFINE_2D_NV = 0x9092, + eGL_AFFINE_3D_NV = 0x9094, + eGL_ALIASED_LINE_WIDTH_RANGE = 0x846E, + eGL_ALIASED_POINT_SIZE_RANGE = 0x846D, + eGL_ALLOW_DRAW_FRG_HINT_PGI = 0x1A210, + eGL_ALLOW_DRAW_MEM_HINT_PGI = 0x1A211, + eGL_ALLOW_DRAW_OBJ_HINT_PGI = 0x1A20E, + eGL_ALLOW_DRAW_WIN_HINT_PGI = 0x1A20F, + eGL_ALL_BARRIER_BITS = 0xFFFFFFFF, + eGL_ALL_BARRIER_BITS_EXT = 0xFFFFFFFF, + eGL_ALL_COMPLETED_NV = 0x84F2, + eGL_ALL_SHADER_BITS = 0xFFFFFFFF, + eGL_ALPHA = 0x1906, + eGL_ALPHA12_EXT = 0x803D, + eGL_ALPHA16F_ARB = 0x881C, + eGL_ALPHA16I_EXT = 0x8D8A, + eGL_ALPHA16UI_EXT = 0x8D78, + eGL_ALPHA16_EXT = 0x803E, + eGL_ALPHA16_SNORM = 0x9018, + eGL_ALPHA32F_ARB = 0x8816, + eGL_ALPHA32I_EXT = 0x8D84, + eGL_ALPHA32UI_EXT = 0x8D72, + eGL_ALPHA4_EXT = 0x803B, + eGL_ALPHA8I_EXT = 0x8D90, + eGL_ALPHA8UI_EXT = 0x8D7E, + eGL_ALPHA8_EXT = 0x803C, + eGL_ALPHA8_SNORM = 0x9014, + eGL_ALPHA_FLOAT16_APPLE = 0x881C, + eGL_ALPHA_FLOAT16_ATI = 0x881C, + eGL_ALPHA_FLOAT32_APPLE = 0x8816, + eGL_ALPHA_FLOAT32_ATI = 0x8816, + eGL_ALPHA_INTEGER = 0x8D97, + eGL_ALPHA_INTEGER_EXT = 0x8D97, + eGL_ALPHA_MAX_CLAMP_INGR = 0x8567, + eGL_ALPHA_MAX_SGIX = 0x8321, + eGL_ALPHA_MIN_CLAMP_INGR = 0x8563, + eGL_ALPHA_MIN_SGIX = 0x8320, + eGL_ALPHA_SNORM = 0x9010, + eGL_ALREADY_SIGNALED = 0x911A, + eGL_ALWAYS = 0x0207, + eGL_ALWAYS_FAST_HINT_PGI = 0x1A20C, + eGL_ALWAYS_SOFT_HINT_PGI = 0x1A20D, + eGL_AND = 0x1501, + eGL_AND_INVERTED = 0x1504, + eGL_AND_REVERSE = 0x1502, + eGL_ANY_SAMPLES_PASSED = 0x8C2F, + eGL_ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A, + eGL_ARRAY_BUFFER = 0x8892, + eGL_ARRAY_BUFFER_ARB = 0x8892, + eGL_ARRAY_BUFFER_BINDING = 0x8894, + eGL_ARRAY_BUFFER_BINDING_ARB = 0x8894, + eGL_ARRAY_ELEMENT_LOCK_COUNT_EXT = 0x81A9, + eGL_ARRAY_ELEMENT_LOCK_FIRST_EXT = 0x81A8, + eGL_ARRAY_OBJECT_BUFFER_ATI = 0x8766, + eGL_ARRAY_OBJECT_OFFSET_ATI = 0x8767, + eGL_ARRAY_SIZE = 0x92FB, + eGL_ARRAY_STRIDE = 0x92FE, + eGL_ASYNC_DRAW_PIXELS_SGIX = 0x835D, + eGL_ASYNC_HISTOGRAM_SGIX = 0x832C, + eGL_ASYNC_MARKER_SGIX = 0x8329, + eGL_ASYNC_READ_PIXELS_SGIX = 0x835E, + eGL_ASYNC_TEX_IMAGE_SGIX = 0x835C, + eGL_ATOMIC_COUNTER_BARRIER_BIT = 0x00001000, + eGL_ATOMIC_COUNTER_BARRIER_BIT_EXT = 0x00001000, + eGL_ATOMIC_COUNTER_BUFFER = 0x92C0, + eGL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS = 0x92C5, + eGL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES = 0x92C6, + eGL_ATOMIC_COUNTER_BUFFER_BINDING = 0x92C1, + eGL_ATOMIC_COUNTER_BUFFER_DATA_SIZE = 0x92C4, + eGL_ATOMIC_COUNTER_BUFFER_INDEX = 0x9301, + eGL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER = 0x90ED, + eGL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER = 0x92CB, + eGL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER = 0x92CA, + eGL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER = 0x92C8, + eGL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x92C9, + eGL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER = 0x92C7, + eGL_ATOMIC_COUNTER_BUFFER_SIZE = 0x92C3, + eGL_ATOMIC_COUNTER_BUFFER_START = 0x92C2, + eGL_ATTACHED_SHADERS = 0x8B85, + eGL_ATTENUATION_EXT = 0x834D, + eGL_ATTRIB_ARRAY_POINTER_NV = 0x8645, + eGL_ATTRIB_ARRAY_SIZE_NV = 0x8623, + eGL_ATTRIB_ARRAY_STRIDE_NV = 0x8624, + eGL_ATTRIB_ARRAY_TYPE_NV = 0x8625, + eGL_AUTO_GENERATE_MIPMAP = 0x8295, + eGL_AUX_DEPTH_STENCIL_APPLE = 0x8A14, + eGL_AVERAGE_EXT = 0x8335, + eGL_AVERAGE_HP = 0x8160, + eGL_BACK = 0x0405, + eGL_BACK_LEFT = 0x0402, + eGL_BACK_NORMALS_HINT_PGI = 0x1A223, + eGL_BACK_PRIMARY_COLOR_NV = 0x8C77, + eGL_BACK_RIGHT = 0x0403, + eGL_BACK_SECONDARY_COLOR_NV = 0x8C78, + eGL_BEVEL_NV = 0x90A6, + eGL_BGR = 0x80E0, + eGL_BGRA = 0x80E1, + eGL_BGRA_EXT = 0x80E1, + eGL_BGRA_INTEGER = 0x8D9B, + eGL_BGRA_INTEGER_EXT = 0x8D9B, + eGL_BGR_EXT = 0x80E0, + eGL_BGR_INTEGER = 0x8D9A, + eGL_BGR_INTEGER_EXT = 0x8D9A, + eGL_BIAS_BIT_ATI = 0x00000008, + eGL_BIAS_BY_NEGATIVE_ONE_HALF_NV = 0x8541, + eGL_BINORMAL_ARRAY_EXT = 0x843A, + eGL_BINORMAL_ARRAY_POINTER_EXT = 0x8443, + eGL_BINORMAL_ARRAY_STRIDE_EXT = 0x8441, + eGL_BINORMAL_ARRAY_TYPE_EXT = 0x8440, + eGL_BLEND = 0x0BE2, + eGL_BLEND_ADVANCED_COHERENT_NV = 0x9285, + eGL_BLEND_COLOR = 0x8005, + eGL_BLEND_COLOR_EXT = 0x8005, + eGL_BLEND_DST = 0x0BE0, + eGL_BLEND_DST_ALPHA = 0x80CA, + eGL_BLEND_DST_ALPHA_EXT = 0x80CA, + eGL_BLEND_DST_RGB = 0x80C8, + eGL_BLEND_DST_RGB_EXT = 0x80C8, + eGL_BLEND_EQUATION = 0x8009, + eGL_BLEND_EQUATION_ALPHA = 0x883D, + eGL_BLEND_EQUATION_ALPHA_EXT = 0x883D, + eGL_BLEND_EQUATION_EXT = 0x8009, + eGL_BLEND_EQUATION_RGB = 0x8009, + eGL_BLEND_EQUATION_RGB_EXT = 0x8009, + eGL_BLEND_OVERLAP_NV = 0x9281, + eGL_BLEND_PREMULTIPLIED_SRC_NV = 0x9280, + eGL_BLEND_SRC = 0x0BE1, + eGL_BLEND_SRC_ALPHA = 0x80CB, + eGL_BLEND_SRC_ALPHA_EXT = 0x80CB, + eGL_BLEND_SRC_RGB = 0x80C9, + eGL_BLEND_SRC_RGB_EXT = 0x80C9, + eGL_BLOCK_INDEX = 0x92FD, + eGL_BLUE = 0x1905, + eGL_BLUE_BIT_ATI = 0x00000004, + eGL_BLUE_INTEGER = 0x8D96, + eGL_BLUE_INTEGER_EXT = 0x8D96, + eGL_BLUE_MAX_CLAMP_INGR = 0x8566, + eGL_BLUE_MIN_CLAMP_INGR = 0x8562, + eGL_BLUE_NV = 0x1905, + eGL_BOOL = 0x8B56, + eGL_BOOL_ARB = 0x8B56, + eGL_BOOL_VEC2 = 0x8B57, + eGL_BOOL_VEC2_ARB = 0x8B57, + eGL_BOOL_VEC3 = 0x8B58, + eGL_BOOL_VEC3_ARB = 0x8B58, + eGL_BOOL_VEC4 = 0x8B59, + eGL_BOOL_VEC4_ARB = 0x8B59, + eGL_BOUNDING_BOX_NV = 0x908D, + eGL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV = 0x909C, + eGL_BUFFER = 0x82E0, + eGL_BUFFER_ACCESS = 0x88BB, + eGL_BUFFER_ACCESS_ARB = 0x88BB, + eGL_BUFFER_ACCESS_FLAGS = 0x911F, + eGL_BUFFER_BINDING = 0x9302, + eGL_BUFFER_DATA_SIZE = 0x9303, + eGL_BUFFER_FLUSHING_UNMAP_APPLE = 0x8A13, + eGL_BUFFER_GPU_ADDRESS_NV = 0x8F1D, + eGL_BUFFER_IMMUTABLE_STORAGE = 0x821F, + eGL_BUFFER_MAPPED = 0x88BC, + eGL_BUFFER_MAPPED_ARB = 0x88BC, + eGL_BUFFER_MAP_LENGTH = 0x9120, + eGL_BUFFER_MAP_OFFSET = 0x9121, + eGL_BUFFER_MAP_POINTER = 0x88BD, + eGL_BUFFER_MAP_POINTER_ARB = 0x88BD, + eGL_BUFFER_OBJECT_APPLE = 0x85B3, + eGL_BUFFER_OBJECT_EXT = 0x9151, + eGL_BUFFER_SERIALIZED_MODIFY_APPLE = 0x8A12, + eGL_BUFFER_SIZE = 0x8764, + eGL_BUFFER_SIZE_ARB = 0x8764, + eGL_BUFFER_STORAGE_FLAGS = 0x8220, + eGL_BUFFER_UPDATE_BARRIER_BIT = 0x00000200, + eGL_BUFFER_UPDATE_BARRIER_BIT_EXT = 0x00000200, + eGL_BUFFER_USAGE = 0x8765, + eGL_BUFFER_USAGE_ARB = 0x8765, + eGL_BUFFER_VARIABLE = 0x92E5, + eGL_BUMP_ENVMAP_ATI = 0x877B, + eGL_BUMP_NUM_TEX_UNITS_ATI = 0x8777, + eGL_BUMP_ROT_MATRIX_ATI = 0x8775, + eGL_BUMP_ROT_MATRIX_SIZE_ATI = 0x8776, + eGL_BUMP_TARGET_ATI = 0x877C, + eGL_BUMP_TEX_UNITS_ATI = 0x8778, + eGL_BYTE = 0x1400, + eGL_CALLIGRAPHIC_FRAGMENT_SGIX = 0x8183, + eGL_CAVEAT_SUPPORT = 0x82B8, + eGL_CCW = 0x0901, + eGL_CLAMP_FRAGMENT_COLOR = 0x891B, + eGL_CLAMP_FRAGMENT_COLOR_ARB = 0x891B, + eGL_CLAMP_READ_COLOR = 0x891C, + eGL_CLAMP_READ_COLOR_ARB = 0x891C, + eGL_CLAMP_TO_BORDER = 0x812D, + eGL_CLAMP_TO_BORDER_ARB = 0x812D, + eGL_CLAMP_TO_BORDER_SGIS = 0x812D, + eGL_CLAMP_TO_EDGE = 0x812F, + eGL_CLAMP_TO_EDGE_SGIS = 0x812F, + eGL_CLAMP_VERTEX_COLOR = 0x891A, + eGL_CLAMP_VERTEX_COLOR_ARB = 0x891A, + eGL_CLEAR = 0x1500, + eGL_CLEAR_BUFFER = 0x82B4, + eGL_CLEAR_TEXTURE = 0x9365, + eGL_CLIENT_ACTIVE_TEXTURE = 0x84E1, + eGL_CLIENT_ACTIVE_TEXTURE_ARB = 0x84E1, + eGL_CLIENT_MAPPED_BUFFER_BARRIER_BIT = 0x00004000, + eGL_CLIENT_STORAGE_BIT = 0x0200, + eGL_CLIP_DISTANCE0 = 0x3000, + eGL_CLIP_DISTANCE1 = 0x3001, + eGL_CLIP_DISTANCE2 = 0x3002, + eGL_CLIP_DISTANCE3 = 0x3003, + eGL_CLIP_DISTANCE4 = 0x3004, + eGL_CLIP_DISTANCE5 = 0x3005, + eGL_CLIP_DISTANCE6 = 0x3006, + eGL_CLIP_DISTANCE7 = 0x3007, + eGL_CLIP_DISTANCE_NV = 0x8C7A, + eGL_CLIP_FAR_HINT_PGI = 0x1A221, + eGL_CLIP_NEAR_HINT_PGI = 0x1A220, + eGL_CLIP_VOLUME_CLIPPING_HINT_EXT = 0x80F0, + eGL_CMYKA_EXT = 0x800D, + eGL_CMYK_EXT = 0x800C, + eGL_CND0_ATI = 0x896B, + eGL_CND_ATI = 0x896A, + eGL_COLOR = 0x1800, + eGL_COLOR3_BIT_PGI = 0x00010000, + eGL_COLOR4_BIT_PGI = 0x00020000, + eGL_COLORBURN_NV = 0x929A, + eGL_COLORDODGE_NV = 0x9299, + eGL_COLOR_ALPHA_PAIRING_ATI = 0x8975, + eGL_COLOR_ARRAY_ADDRESS_NV = 0x8F23, + eGL_COLOR_ARRAY_BUFFER_BINDING = 0x8898, + eGL_COLOR_ARRAY_BUFFER_BINDING_ARB = 0x8898, + eGL_COLOR_ARRAY_COUNT_EXT = 0x8084, + eGL_COLOR_ARRAY_EXT = 0x8076, + eGL_COLOR_ARRAY_LENGTH_NV = 0x8F2D, + eGL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL = 0x83F7, + eGL_COLOR_ARRAY_POINTER_EXT = 0x8090, + eGL_COLOR_ARRAY_SIZE_EXT = 0x8081, + eGL_COLOR_ARRAY_STRIDE_EXT = 0x8083, + eGL_COLOR_ARRAY_TYPE_EXT = 0x8082, + eGL_COLOR_ATTACHMENT0 = 0x8CE0, + eGL_COLOR_ATTACHMENT0_EXT = 0x8CE0, + eGL_COLOR_ATTACHMENT1 = 0x8CE1, + eGL_COLOR_ATTACHMENT10 = 0x8CEA, + eGL_COLOR_ATTACHMENT10_EXT = 0x8CEA, + eGL_COLOR_ATTACHMENT11 = 0x8CEB, + eGL_COLOR_ATTACHMENT11_EXT = 0x8CEB, + eGL_COLOR_ATTACHMENT12 = 0x8CEC, + eGL_COLOR_ATTACHMENT12_EXT = 0x8CEC, + eGL_COLOR_ATTACHMENT13 = 0x8CED, + eGL_COLOR_ATTACHMENT13_EXT = 0x8CED, + eGL_COLOR_ATTACHMENT14 = 0x8CEE, + eGL_COLOR_ATTACHMENT14_EXT = 0x8CEE, + eGL_COLOR_ATTACHMENT15 = 0x8CEF, + eGL_COLOR_ATTACHMENT15_EXT = 0x8CEF, + eGL_COLOR_ATTACHMENT1_EXT = 0x8CE1, + eGL_COLOR_ATTACHMENT2 = 0x8CE2, + eGL_COLOR_ATTACHMENT2_EXT = 0x8CE2, + eGL_COLOR_ATTACHMENT3 = 0x8CE3, + eGL_COLOR_ATTACHMENT3_EXT = 0x8CE3, + eGL_COLOR_ATTACHMENT4 = 0x8CE4, + eGL_COLOR_ATTACHMENT4_EXT = 0x8CE4, + eGL_COLOR_ATTACHMENT5 = 0x8CE5, + eGL_COLOR_ATTACHMENT5_EXT = 0x8CE5, + eGL_COLOR_ATTACHMENT6 = 0x8CE6, + eGL_COLOR_ATTACHMENT6_EXT = 0x8CE6, + eGL_COLOR_ATTACHMENT7 = 0x8CE7, + eGL_COLOR_ATTACHMENT7_EXT = 0x8CE7, + eGL_COLOR_ATTACHMENT8 = 0x8CE8, + eGL_COLOR_ATTACHMENT8_EXT = 0x8CE8, + eGL_COLOR_ATTACHMENT9 = 0x8CE9, + eGL_COLOR_ATTACHMENT9_EXT = 0x8CE9, + eGL_COLOR_BUFFER_BIT = 0x00004000, + eGL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI = 0x8835, + eGL_COLOR_CLEAR_VALUE = 0x0C22, + eGL_COLOR_COMPONENTS = 0x8283, + eGL_COLOR_ENCODING = 0x8296, + eGL_COLOR_FLOAT_APPLE = 0x8A0F, + eGL_COLOR_INDEX12_EXT = 0x80E6, + eGL_COLOR_INDEX16_EXT = 0x80E7, + eGL_COLOR_INDEX1_EXT = 0x80E2, + eGL_COLOR_INDEX2_EXT = 0x80E3, + eGL_COLOR_INDEX4_EXT = 0x80E4, + eGL_COLOR_INDEX8_EXT = 0x80E5, + eGL_COLOR_LOGIC_OP = 0x0BF2, + eGL_COLOR_MATRIX = 0x80B1, + eGL_COLOR_MATRIX_SGI = 0x80B1, + eGL_COLOR_MATRIX_STACK_DEPTH = 0x80B2, + eGL_COLOR_MATRIX_STACK_DEPTH_SGI = 0x80B2, + eGL_COLOR_RENDERABLE = 0x8286, + eGL_COLOR_SAMPLES_NV = 0x8E20, + eGL_COLOR_SUM = 0x8458, + eGL_COLOR_SUM_ARB = 0x8458, + eGL_COLOR_SUM_CLAMP_NV = 0x854F, + eGL_COLOR_SUM_EXT = 0x8458, + eGL_COLOR_TABLE = 0x80D0, + eGL_COLOR_TABLE_ALPHA_SIZE = 0x80DD, + eGL_COLOR_TABLE_ALPHA_SIZE_SGI = 0x80DD, + eGL_COLOR_TABLE_BIAS = 0x80D7, + eGL_COLOR_TABLE_BIAS_SGI = 0x80D7, + eGL_COLOR_TABLE_BLUE_SIZE = 0x80DC, + eGL_COLOR_TABLE_BLUE_SIZE_SGI = 0x80DC, + eGL_COLOR_TABLE_FORMAT = 0x80D8, + eGL_COLOR_TABLE_FORMAT_SGI = 0x80D8, + eGL_COLOR_TABLE_GREEN_SIZE = 0x80DB, + eGL_COLOR_TABLE_GREEN_SIZE_SGI = 0x80DB, + eGL_COLOR_TABLE_INTENSITY_SIZE = 0x80DF, + eGL_COLOR_TABLE_INTENSITY_SIZE_SGI = 0x80DF, + eGL_COLOR_TABLE_LUMINANCE_SIZE = 0x80DE, + eGL_COLOR_TABLE_LUMINANCE_SIZE_SGI = 0x80DE, + eGL_COLOR_TABLE_RED_SIZE = 0x80DA, + eGL_COLOR_TABLE_RED_SIZE_SGI = 0x80DA, + eGL_COLOR_TABLE_SCALE = 0x80D6, + eGL_COLOR_TABLE_SCALE_SGI = 0x80D6, + eGL_COLOR_TABLE_SGI = 0x80D0, + eGL_COLOR_TABLE_WIDTH = 0x80D9, + eGL_COLOR_TABLE_WIDTH_SGI = 0x80D9, + eGL_COLOR_WRITEMASK = 0x0C23, + eGL_COMBINE = 0x8570, + eGL_COMBINE4_NV = 0x8503, + eGL_COMBINER0_NV = 0x8550, + eGL_COMBINER1_NV = 0x8551, + eGL_COMBINER2_NV = 0x8552, + eGL_COMBINER3_NV = 0x8553, + eGL_COMBINER4_NV = 0x8554, + eGL_COMBINER5_NV = 0x8555, + eGL_COMBINER6_NV = 0x8556, + eGL_COMBINER7_NV = 0x8557, + eGL_COMBINER_AB_DOT_PRODUCT_NV = 0x8545, + eGL_COMBINER_AB_OUTPUT_NV = 0x854A, + eGL_COMBINER_BIAS_NV = 0x8549, + eGL_COMBINER_CD_DOT_PRODUCT_NV = 0x8546, + eGL_COMBINER_CD_OUTPUT_NV = 0x854B, + eGL_COMBINER_COMPONENT_USAGE_NV = 0x8544, + eGL_COMBINER_INPUT_NV = 0x8542, + eGL_COMBINER_MAPPING_NV = 0x8543, + eGL_COMBINER_MUX_SUM_NV = 0x8547, + eGL_COMBINER_SCALE_NV = 0x8548, + eGL_COMBINER_SUM_OUTPUT_NV = 0x854C, + eGL_COMBINE_ALPHA = 0x8572, + eGL_COMBINE_ALPHA_ARB = 0x8572, + eGL_COMBINE_ALPHA_EXT = 0x8572, + eGL_COMBINE_ARB = 0x8570, + eGL_COMBINE_EXT = 0x8570, + eGL_COMBINE_RGB = 0x8571, + eGL_COMBINE_RGB_ARB = 0x8571, + eGL_COMBINE_RGB_EXT = 0x8571, + eGL_COMMAND_BARRIER_BIT = 0x00000040, + eGL_COMMAND_BARRIER_BIT_EXT = 0x00000040, + eGL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT = 0x884E, + eGL_COMPARE_REF_TO_TEXTURE = 0x884E, + eGL_COMPARE_R_TO_TEXTURE = 0x884E, + eGL_COMPARE_R_TO_TEXTURE_ARB = 0x884E, + eGL_COMPATIBLE_SUBROUTINES = 0x8E4B, + eGL_COMPILE_STATUS = 0x8B81, + eGL_COMPRESSED_ALPHA = 0x84E9, + eGL_COMPRESSED_ALPHA_ARB = 0x84E9, + eGL_COMPRESSED_INTENSITY = 0x84EC, + eGL_COMPRESSED_INTENSITY_ARB = 0x84EC, + eGL_COMPRESSED_LUMINANCE = 0x84EA, + eGL_COMPRESSED_LUMINANCE_ALPHA = 0x84EB, + eGL_COMPRESSED_LUMINANCE_ALPHA_ARB = 0x84EB, + eGL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C72, + eGL_COMPRESSED_LUMINANCE_ARB = 0x84EA, + eGL_COMPRESSED_LUMINANCE_LATC1_EXT = 0x8C70, + eGL_COMPRESSED_R11_EAC = 0x9270, + eGL_COMPRESSED_RED = 0x8225, + eGL_COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD, + eGL_COMPRESSED_RED_RGTC1 = 0x8DBB, + eGL_COMPRESSED_RED_RGTC1_EXT = 0x8DBB, + eGL_COMPRESSED_RG = 0x8226, + eGL_COMPRESSED_RG11_EAC = 0x9272, + eGL_COMPRESSED_RGB = 0x84ED, + eGL_COMPRESSED_RGB8_ETC2 = 0x9274, + eGL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276, + eGL_COMPRESSED_RGBA = 0x84EE, + eGL_COMPRESSED_RGBA8_ETC2_EAC = 0x9278, + eGL_COMPRESSED_RGBA_ARB = 0x84EE, + eGL_COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB, + eGL_COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8, + eGL_COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9, + eGL_COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA, + eGL_COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC, + eGL_COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD, + eGL_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0, + eGL_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1, + eGL_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2, + eGL_COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3, + eGL_COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4, + eGL_COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5, + eGL_COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6, + eGL_COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7, + eGL_COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C, + eGL_COMPRESSED_RGBA_BPTC_UNORM_ARB = 0x8E8C, + eGL_COMPRESSED_RGBA_FXT1_3DFX = 0x86B1, + eGL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1, + eGL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2, + eGL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3, + eGL_COMPRESSED_RGB_ARB = 0x84ED, + eGL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E, + eGL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB = 0x8E8E, + eGL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F, + eGL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB = 0x8E8F, + eGL_COMPRESSED_RGB_FXT1_3DFX = 0x86B0, + eGL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0, + eGL_COMPRESSED_RG_RGTC2 = 0x8DBD, + eGL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C73, + eGL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = 0x8C71, + eGL_COMPRESSED_SIGNED_R11_EAC = 0x9271, + eGL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE, + eGL_COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC, + eGL_COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC, + eGL_COMPRESSED_SIGNED_RG11_EAC = 0x9273, + eGL_COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE, + eGL_COMPRESSED_SLUMINANCE = 0x8C4A, + eGL_COMPRESSED_SLUMINANCE_ALPHA = 0x8C4B, + eGL_COMPRESSED_SLUMINANCE_ALPHA_EXT = 0x8C4B, + eGL_COMPRESSED_SLUMINANCE_EXT = 0x8C4A, + eGL_COMPRESSED_SRGB = 0x8C48, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6, + eGL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7, + eGL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279, + eGL_COMPRESSED_SRGB8_ETC2 = 0x9275, + eGL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277, + eGL_COMPRESSED_SRGB_ALPHA = 0x8C49, + eGL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D, + eGL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB = 0x8E8D, + eGL_COMPRESSED_SRGB_ALPHA_EXT = 0x8C49, + eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D, + eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E, + eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F, + eGL_COMPRESSED_SRGB_EXT = 0x8C48, + eGL_COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C, + eGL_COMPRESSED_TEXTURE_FORMATS = 0x86A3, + eGL_COMPRESSED_TEXTURE_FORMATS_ARB = 0x86A3, + eGL_COMPUTE_PROGRAM_NV = 0x90FB, + eGL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV = 0x90FC, + eGL_COMPUTE_SHADER = 0x91B9, + eGL_COMPUTE_SHADER_BIT = 0x00000020, + eGL_COMPUTE_SUBROUTINE = 0x92ED, + eGL_COMPUTE_SUBROUTINE_UNIFORM = 0x92F3, + eGL_COMPUTE_TEXTURE = 0x82A0, + eGL_COMPUTE_WORK_GROUP_SIZE = 0x8267, + eGL_COMP_BIT_ATI = 0x00000002, + eGL_CONDITION_SATISFIED = 0x911C, + eGL_CONJOINT_NV = 0x9284, + eGL_CONSERVE_MEMORY_HINT_PGI = 0x1A1FD, + eGL_CONSTANT = 0x8576, + eGL_CONSTANT_ALPHA = 0x8003, + eGL_CONSTANT_ALPHA_EXT = 0x8003, + eGL_CONSTANT_ARB = 0x8576, + eGL_CONSTANT_BORDER = 0x8151, + eGL_CONSTANT_BORDER_HP = 0x8151, + eGL_CONSTANT_COLOR = 0x8001, + eGL_CONSTANT_COLOR0_NV = 0x852A, + eGL_CONSTANT_COLOR1_NV = 0x852B, + eGL_CONSTANT_COLOR_EXT = 0x8001, + eGL_CONSTANT_EXT = 0x8576, + eGL_CONST_EYE_NV = 0x86E5, + eGL_CONTEXT_COMPATIBILITY_PROFILE_BIT = 0x00000002, + eGL_CONTEXT_CORE_PROFILE_BIT = 0x00000001, + eGL_CONTEXT_FLAGS = 0x821E, + eGL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002, + eGL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001, + eGL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB = 0x00000004, + eGL_CONTEXT_PROFILE_MASK = 0x9126, + eGL_CONTINUOUS_AMD = 0x9007, + eGL_CONTRAST_NV = 0x92A1, + eGL_CONVEX_HULL_NV = 0x908B, + eGL_CONVOLUTION_1D = 0x8010, + eGL_CONVOLUTION_1D_EXT = 0x8010, + eGL_CONVOLUTION_2D = 0x8011, + eGL_CONVOLUTION_2D_EXT = 0x8011, + eGL_CONVOLUTION_BORDER_COLOR = 0x8154, + eGL_CONVOLUTION_BORDER_COLOR_HP = 0x8154, + eGL_CONVOLUTION_BORDER_MODE = 0x8013, + eGL_CONVOLUTION_BORDER_MODE_EXT = 0x8013, + eGL_CONVOLUTION_FILTER_BIAS = 0x8015, + eGL_CONVOLUTION_FILTER_BIAS_EXT = 0x8015, + eGL_CONVOLUTION_FILTER_SCALE = 0x8014, + eGL_CONVOLUTION_FILTER_SCALE_EXT = 0x8014, + eGL_CONVOLUTION_FORMAT = 0x8017, + eGL_CONVOLUTION_FORMAT_EXT = 0x8017, + eGL_CONVOLUTION_HEIGHT = 0x8019, + eGL_CONVOLUTION_HEIGHT_EXT = 0x8019, + eGL_CONVOLUTION_HINT_SGIX = 0x8316, + eGL_CONVOLUTION_WIDTH = 0x8018, + eGL_CONVOLUTION_WIDTH_EXT = 0x8018, + eGL_CON_0_ATI = 0x8941, + eGL_CON_10_ATI = 0x894B, + eGL_CON_11_ATI = 0x894C, + eGL_CON_12_ATI = 0x894D, + eGL_CON_13_ATI = 0x894E, + eGL_CON_14_ATI = 0x894F, + eGL_CON_15_ATI = 0x8950, + eGL_CON_16_ATI = 0x8951, + eGL_CON_17_ATI = 0x8952, + eGL_CON_18_ATI = 0x8953, + eGL_CON_19_ATI = 0x8954, + eGL_CON_1_ATI = 0x8942, + eGL_CON_20_ATI = 0x8955, + eGL_CON_21_ATI = 0x8956, + eGL_CON_22_ATI = 0x8957, + eGL_CON_23_ATI = 0x8958, + eGL_CON_24_ATI = 0x8959, + eGL_CON_25_ATI = 0x895A, + eGL_CON_26_ATI = 0x895B, + eGL_CON_27_ATI = 0x895C, + eGL_CON_28_ATI = 0x895D, + eGL_CON_29_ATI = 0x895E, + eGL_CON_2_ATI = 0x8943, + eGL_CON_30_ATI = 0x895F, + eGL_CON_31_ATI = 0x8960, + eGL_CON_3_ATI = 0x8944, + eGL_CON_4_ATI = 0x8945, + eGL_CON_5_ATI = 0x8946, + eGL_CON_6_ATI = 0x8947, + eGL_CON_7_ATI = 0x8948, + eGL_CON_8_ATI = 0x8949, + eGL_CON_9_ATI = 0x894A, + eGL_COORD_REPLACE = 0x8862, + eGL_COORD_REPLACE_ARB = 0x8862, + eGL_COORD_REPLACE_NV = 0x8862, + eGL_COPY = 0x1503, + eGL_COPY_INVERTED = 0x150C, + eGL_COPY_READ_BUFFER = 0x8F36, + eGL_COPY_READ_BUFFER_BINDING = 0x8F36, + eGL_COPY_WRITE_BUFFER = 0x8F37, + eGL_COPY_WRITE_BUFFER_BINDING = 0x8F37, + eGL_COUNTER_RANGE_AMD = 0x8BC1, + eGL_COUNTER_TYPE_AMD = 0x8BC0, + eGL_COUNT_DOWN_NV = 0x9089, + eGL_COUNT_UP_NV = 0x9088, + eGL_CUBIC_EXT = 0x8334, + eGL_CUBIC_HP = 0x815F, + eGL_CULL_FACE = 0x0B44, + eGL_CULL_FACE_MODE = 0x0B45, + eGL_CULL_FRAGMENT_NV = 0x86E7, + eGL_CULL_MODES_NV = 0x86E0, + eGL_CULL_VERTEX_EXT = 0x81AA, + eGL_CULL_VERTEX_EYE_POSITION_EXT = 0x81AB, + eGL_CULL_VERTEX_OBJECT_POSITION_EXT = 0x81AC, + eGL_CURRENT_ATTRIB_NV = 0x8626, + eGL_CURRENT_BINORMAL_EXT = 0x843C, + eGL_CURRENT_FOG_COORD = 0x8453, + eGL_CURRENT_FOG_COORDINATE = 0x8453, + eGL_CURRENT_FOG_COORDINATE_EXT = 0x8453, + eGL_CURRENT_MATRIX_ARB = 0x8641, + eGL_CURRENT_MATRIX_INDEX_ARB = 0x8845, + eGL_CURRENT_MATRIX_NV = 0x8641, + eGL_CURRENT_MATRIX_STACK_DEPTH_ARB = 0x8640, + eGL_CURRENT_MATRIX_STACK_DEPTH_NV = 0x8640, + eGL_CURRENT_OCCLUSION_QUERY_ID_NV = 0x8865, + eGL_CURRENT_PALETTE_MATRIX_ARB = 0x8843, + eGL_CURRENT_PROGRAM = 0x8B8D, + eGL_CURRENT_QUERY = 0x8865, + eGL_CURRENT_QUERY_ARB = 0x8865, + eGL_CURRENT_RASTER_NORMAL_SGIX = 0x8406, + eGL_CURRENT_RASTER_SECONDARY_COLOR = 0x845F, + eGL_CURRENT_SECONDARY_COLOR = 0x8459, + eGL_CURRENT_SECONDARY_COLOR_EXT = 0x8459, + eGL_CURRENT_TANGENT_EXT = 0x843B, + eGL_CURRENT_TIME_NV = 0x8E28, + eGL_CURRENT_VERTEX_ATTRIB = 0x8626, + eGL_CURRENT_VERTEX_ATTRIB_ARB = 0x8626, + eGL_CURRENT_VERTEX_EXT = 0x87E2, + eGL_CURRENT_VERTEX_WEIGHT_EXT = 0x850B, + eGL_CURRENT_WEIGHT_ARB = 0x86A8, + eGL_CW = 0x0900, + eGL_DARKEN_NV = 0x9297, + eGL_DATA_BUFFER_AMD = 0x9151, + eGL_DEBUG_CALLBACK_FUNCTION = 0x8244, + eGL_DEBUG_CALLBACK_FUNCTION_ARB = 0x8244, + eGL_DEBUG_CALLBACK_USER_PARAM = 0x8245, + eGL_DEBUG_CALLBACK_USER_PARAM_ARB = 0x8245, + eGL_DEBUG_CATEGORY_API_ERROR_AMD = 0x9149, + eGL_DEBUG_CATEGORY_APPLICATION_AMD = 0x914F, + eGL_DEBUG_CATEGORY_DEPRECATION_AMD = 0x914B, + eGL_DEBUG_CATEGORY_OTHER_AMD = 0x9150, + eGL_DEBUG_CATEGORY_PERFORMANCE_AMD = 0x914D, + eGL_DEBUG_CATEGORY_SHADER_COMPILER_AMD = 0x914E, + eGL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD = 0x914C, + eGL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD = 0x914A, + eGL_DEBUG_GROUP_STACK_DEPTH = 0x826D, + eGL_DEBUG_LOGGED_MESSAGES = 0x9145, + eGL_DEBUG_LOGGED_MESSAGES_AMD = 0x9145, + eGL_DEBUG_LOGGED_MESSAGES_ARB = 0x9145, + eGL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 0x8243, + eGL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB = 0x8243, + eGL_DEBUG_OUTPUT = 0x92E0, + eGL_DEBUG_OUTPUT_SYNCHRONOUS = 0x8242, + eGL_DEBUG_OUTPUT_SYNCHRONOUS_ARB = 0x8242, + eGL_DEBUG_SEVERITY_HIGH = 0x9146, + eGL_DEBUG_SEVERITY_HIGH_AMD = 0x9146, + eGL_DEBUG_SEVERITY_HIGH_ARB = 0x9146, + eGL_DEBUG_SEVERITY_LOW = 0x9148, + eGL_DEBUG_SEVERITY_LOW_AMD = 0x9148, + eGL_DEBUG_SEVERITY_LOW_ARB = 0x9148, + eGL_DEBUG_SEVERITY_MEDIUM = 0x9147, + eGL_DEBUG_SEVERITY_MEDIUM_AMD = 0x9147, + eGL_DEBUG_SEVERITY_MEDIUM_ARB = 0x9147, + eGL_DEBUG_SEVERITY_NOTIFICATION = 0x826B, + eGL_DEBUG_SOURCE_API = 0x8246, + eGL_DEBUG_SOURCE_API_ARB = 0x8246, + eGL_DEBUG_SOURCE_APPLICATION = 0x824A, + eGL_DEBUG_SOURCE_APPLICATION_ARB = 0x824A, + eGL_DEBUG_SOURCE_OTHER = 0x824B, + eGL_DEBUG_SOURCE_OTHER_ARB = 0x824B, + eGL_DEBUG_SOURCE_SHADER_COMPILER = 0x8248, + eGL_DEBUG_SOURCE_SHADER_COMPILER_ARB = 0x8248, + eGL_DEBUG_SOURCE_THIRD_PARTY = 0x8249, + eGL_DEBUG_SOURCE_THIRD_PARTY_ARB = 0x8249, + eGL_DEBUG_SOURCE_WINDOW_SYSTEM = 0x8247, + eGL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB = 0x8247, + eGL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 0x824D, + eGL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB = 0x824D, + eGL_DEBUG_TYPE_ERROR = 0x824C, + eGL_DEBUG_TYPE_ERROR_ARB = 0x824C, + eGL_DEBUG_TYPE_MARKER = 0x8268, + eGL_DEBUG_TYPE_OTHER = 0x8251, + eGL_DEBUG_TYPE_OTHER_ARB = 0x8251, + eGL_DEBUG_TYPE_PERFORMANCE = 0x8250, + eGL_DEBUG_TYPE_PERFORMANCE_ARB = 0x8250, + eGL_DEBUG_TYPE_POP_GROUP = 0x826A, + eGL_DEBUG_TYPE_PORTABILITY = 0x824F, + eGL_DEBUG_TYPE_PORTABILITY_ARB = 0x824F, + eGL_DEBUG_TYPE_PUSH_GROUP = 0x8269, + eGL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 0x824E, + eGL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB = 0x824E, + eGL_DECODE_EXT = 0x8A49, + eGL_DECR = 0x1E03, + eGL_DECR_WRAP = 0x8508, + eGL_DECR_WRAP_EXT = 0x8508, + eGL_DEFORMATIONS_MASK_SGIX = 0x8196, + eGL_DELETE_STATUS = 0x8B80, + eGL_DEPENDENT_AR_TEXTURE_2D_NV = 0x86E9, + eGL_DEPENDENT_GB_TEXTURE_2D_NV = 0x86EA, + eGL_DEPENDENT_HILO_TEXTURE_2D_NV = 0x8858, + eGL_DEPENDENT_RGB_TEXTURE_3D_NV = 0x8859, + eGL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV = 0x885A, + eGL_DEPTH = 0x1801, + eGL_DEPTH24_STENCIL8 = 0x88F0, + eGL_DEPTH24_STENCIL8_EXT = 0x88F0, + eGL_DEPTH32F_STENCIL8 = 0x8CAD, + eGL_DEPTH32F_STENCIL8_NV = 0x8DAC, + eGL_DEPTH_ATTACHMENT = 0x8D00, + eGL_DEPTH_ATTACHMENT_EXT = 0x8D00, + eGL_DEPTH_BOUNDS_EXT = 0x8891, + eGL_DEPTH_BOUNDS_TEST_EXT = 0x8890, + eGL_DEPTH_BUFFER_BIT = 0x00000100, + eGL_DEPTH_BUFFER_FLOAT_MODE_NV = 0x8DAF, + eGL_DEPTH_CLAMP = 0x864F, + eGL_DEPTH_CLAMP_FAR_AMD = 0x901F, + eGL_DEPTH_CLAMP_NEAR_AMD = 0x901E, + eGL_DEPTH_CLAMP_NV = 0x864F, + eGL_DEPTH_CLEAR_VALUE = 0x0B73, + eGL_DEPTH_COMPONENT = 0x1902, + eGL_DEPTH_COMPONENT16 = 0x81A5, + eGL_DEPTH_COMPONENT16_ARB = 0x81A5, + eGL_DEPTH_COMPONENT16_SGIX = 0x81A5, + eGL_DEPTH_COMPONENT24 = 0x81A6, + eGL_DEPTH_COMPONENT24_ARB = 0x81A6, + eGL_DEPTH_COMPONENT24_SGIX = 0x81A6, + eGL_DEPTH_COMPONENT32 = 0x81A7, + eGL_DEPTH_COMPONENT32F = 0x8CAC, + eGL_DEPTH_COMPONENT32F_NV = 0x8DAB, + eGL_DEPTH_COMPONENT32_ARB = 0x81A7, + eGL_DEPTH_COMPONENT32_SGIX = 0x81A7, + eGL_DEPTH_COMPONENTS = 0x8284, + eGL_DEPTH_FUNC = 0x0B74, + eGL_DEPTH_RANGE = 0x0B70, + eGL_DEPTH_RENDERABLE = 0x8287, + eGL_DEPTH_STENCIL = 0x84F9, + eGL_DEPTH_STENCIL_ATTACHMENT = 0x821A, + eGL_DEPTH_STENCIL_EXT = 0x84F9, + eGL_DEPTH_STENCIL_NV = 0x84F9, + eGL_DEPTH_STENCIL_TEXTURE_MODE = 0x90EA, + eGL_DEPTH_STENCIL_TO_BGRA_NV = 0x886F, + eGL_DEPTH_STENCIL_TO_RGBA_NV = 0x886E, + eGL_DEPTH_TEST = 0x0B71, + eGL_DEPTH_TEXTURE_MODE = 0x884B, + eGL_DEPTH_TEXTURE_MODE_ARB = 0x884B, + eGL_DEPTH_WRITEMASK = 0x0B72, + eGL_DETAIL_TEXTURE_2D_BINDING_SGIS = 0x8096, + eGL_DETAIL_TEXTURE_2D_SGIS = 0x8095, + eGL_DETAIL_TEXTURE_FUNC_POINTS_SGIS = 0x809C, + eGL_DETAIL_TEXTURE_LEVEL_SGIS = 0x809A, + eGL_DETAIL_TEXTURE_MODE_SGIS = 0x809B, + eGL_DIFFERENCE_NV = 0x929E, + eGL_DISCARD_ATI = 0x8763, + eGL_DISCARD_NV = 0x8530, + eGL_DISCRETE_AMD = 0x9006, + eGL_DISJOINT_NV = 0x9283, + eGL_DISPATCH_INDIRECT_BUFFER = 0x90EE, + eGL_DISPATCH_INDIRECT_BUFFER_BINDING = 0x90EF, + eGL_DISPLAY_LIST = 0x82E7, + eGL_DISTANCE_ATTENUATION_EXT = 0x8129, + eGL_DISTANCE_ATTENUATION_SGIS = 0x8129, + eGL_DITHER = 0x0BD0, + eGL_DONT_CARE = 0x1100, + eGL_DOT2_ADD_ATI = 0x896C, + eGL_DOT3_ATI = 0x8966, + eGL_DOT3_RGB = 0x86AE, + eGL_DOT3_RGBA = 0x86AF, + eGL_DOT3_RGBA_ARB = 0x86AF, + eGL_DOT3_RGBA_EXT = 0x8741, + eGL_DOT3_RGB_ARB = 0x86AE, + eGL_DOT3_RGB_EXT = 0x8740, + eGL_DOT4_ATI = 0x8967, + eGL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV = 0x885D, + eGL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV = 0x86F3, + eGL_DOT_PRODUCT_DEPTH_REPLACE_NV = 0x86ED, + eGL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV = 0x86F1, + eGL_DOT_PRODUCT_NV = 0x86EC, + eGL_DOT_PRODUCT_PASS_THROUGH_NV = 0x885B, + eGL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV = 0x86F2, + eGL_DOT_PRODUCT_TEXTURE_1D_NV = 0x885C, + eGL_DOT_PRODUCT_TEXTURE_2D_NV = 0x86EE, + eGL_DOT_PRODUCT_TEXTURE_3D_NV = 0x86EF, + eGL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV = 0x86F0, + eGL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV = 0x864E, + eGL_DOUBLE = 0x140A, + eGL_DOUBLEBUFFER = 0x0C32, + eGL_DOUBLE_MAT2 = 0x8F46, + eGL_DOUBLE_MAT2_EXT = 0x8F46, + eGL_DOUBLE_MAT2x3 = 0x8F49, + eGL_DOUBLE_MAT2x3_EXT = 0x8F49, + eGL_DOUBLE_MAT2x4 = 0x8F4A, + eGL_DOUBLE_MAT2x4_EXT = 0x8F4A, + eGL_DOUBLE_MAT3 = 0x8F47, + eGL_DOUBLE_MAT3_EXT = 0x8F47, + eGL_DOUBLE_MAT3x2 = 0x8F4B, + eGL_DOUBLE_MAT3x2_EXT = 0x8F4B, + eGL_DOUBLE_MAT3x4 = 0x8F4C, + eGL_DOUBLE_MAT3x4_EXT = 0x8F4C, + eGL_DOUBLE_MAT4 = 0x8F48, + eGL_DOUBLE_MAT4_EXT = 0x8F48, + eGL_DOUBLE_MAT4x2 = 0x8F4D, + eGL_DOUBLE_MAT4x2_EXT = 0x8F4D, + eGL_DOUBLE_MAT4x3 = 0x8F4E, + eGL_DOUBLE_MAT4x3_EXT = 0x8F4E, + eGL_DOUBLE_VEC2 = 0x8FFC, + eGL_DOUBLE_VEC2_EXT = 0x8FFC, + eGL_DOUBLE_VEC3 = 0x8FFD, + eGL_DOUBLE_VEC3_EXT = 0x8FFD, + eGL_DOUBLE_VEC4 = 0x8FFE, + eGL_DOUBLE_VEC4_EXT = 0x8FFE, + eGL_DRAW_BUFFER = 0x0C01, + eGL_DRAW_BUFFER0 = 0x8825, + eGL_DRAW_BUFFER0_ARB = 0x8825, + eGL_DRAW_BUFFER0_ATI = 0x8825, + eGL_DRAW_BUFFER1 = 0x8826, + eGL_DRAW_BUFFER10 = 0x882F, + eGL_DRAW_BUFFER10_ARB = 0x882F, + eGL_DRAW_BUFFER10_ATI = 0x882F, + eGL_DRAW_BUFFER11 = 0x8830, + eGL_DRAW_BUFFER11_ARB = 0x8830, + eGL_DRAW_BUFFER11_ATI = 0x8830, + eGL_DRAW_BUFFER12 = 0x8831, + eGL_DRAW_BUFFER12_ARB = 0x8831, + eGL_DRAW_BUFFER12_ATI = 0x8831, + eGL_DRAW_BUFFER13 = 0x8832, + eGL_DRAW_BUFFER13_ARB = 0x8832, + eGL_DRAW_BUFFER13_ATI = 0x8832, + eGL_DRAW_BUFFER14 = 0x8833, + eGL_DRAW_BUFFER14_ARB = 0x8833, + eGL_DRAW_BUFFER14_ATI = 0x8833, + eGL_DRAW_BUFFER15 = 0x8834, + eGL_DRAW_BUFFER15_ARB = 0x8834, + eGL_DRAW_BUFFER15_ATI = 0x8834, + eGL_DRAW_BUFFER1_ARB = 0x8826, + eGL_DRAW_BUFFER1_ATI = 0x8826, + eGL_DRAW_BUFFER2 = 0x8827, + eGL_DRAW_BUFFER2_ARB = 0x8827, + eGL_DRAW_BUFFER2_ATI = 0x8827, + eGL_DRAW_BUFFER3 = 0x8828, + eGL_DRAW_BUFFER3_ARB = 0x8828, + eGL_DRAW_BUFFER3_ATI = 0x8828, + eGL_DRAW_BUFFER4 = 0x8829, + eGL_DRAW_BUFFER4_ARB = 0x8829, + eGL_DRAW_BUFFER4_ATI = 0x8829, + eGL_DRAW_BUFFER5 = 0x882A, + eGL_DRAW_BUFFER5_ARB = 0x882A, + eGL_DRAW_BUFFER5_ATI = 0x882A, + eGL_DRAW_BUFFER6 = 0x882B, + eGL_DRAW_BUFFER6_ARB = 0x882B, + eGL_DRAW_BUFFER6_ATI = 0x882B, + eGL_DRAW_BUFFER7 = 0x882C, + eGL_DRAW_BUFFER7_ARB = 0x882C, + eGL_DRAW_BUFFER7_ATI = 0x882C, + eGL_DRAW_BUFFER8 = 0x882D, + eGL_DRAW_BUFFER8_ARB = 0x882D, + eGL_DRAW_BUFFER8_ATI = 0x882D, + eGL_DRAW_BUFFER9 = 0x882E, + eGL_DRAW_BUFFER9_ARB = 0x882E, + eGL_DRAW_BUFFER9_ATI = 0x882E, + eGL_DRAW_FRAMEBUFFER = 0x8CA9, + eGL_DRAW_FRAMEBUFFER_BINDING = 0x8CA6, + eGL_DRAW_FRAMEBUFFER_BINDING_EXT = 0x8CA6, + eGL_DRAW_FRAMEBUFFER_EXT = 0x8CA9, + eGL_DRAW_INDIRECT_ADDRESS_NV = 0x8F41, + eGL_DRAW_INDIRECT_BUFFER = 0x8F3F, + eGL_DRAW_INDIRECT_BUFFER_BINDING = 0x8F43, + eGL_DRAW_INDIRECT_LENGTH_NV = 0x8F42, + eGL_DRAW_INDIRECT_UNIFIED_NV = 0x8F40, + eGL_DRAW_PIXELS_APPLE = 0x8A0A, + eGL_DSDT8_MAG8_INTENSITY8_NV = 0x870B, + eGL_DSDT8_MAG8_NV = 0x870A, + eGL_DSDT8_NV = 0x8709, + eGL_DSDT_MAG_INTENSITY_NV = 0x86DC, + eGL_DSDT_MAG_NV = 0x86F6, + eGL_DSDT_MAG_VIB_NV = 0x86F7, + eGL_DSDT_NV = 0x86F5, + eGL_DST_ALPHA = 0x0304, + eGL_DST_ATOP_NV = 0x928F, + eGL_DST_COLOR = 0x0306, + eGL_DST_IN_NV = 0x928B, + eGL_DST_NV = 0x9287, + eGL_DST_OUT_NV = 0x928D, + eGL_DST_OVER_NV = 0x9289, + eGL_DS_BIAS_NV = 0x8716, + eGL_DS_SCALE_NV = 0x8710, + eGL_DT_BIAS_NV = 0x8717, + eGL_DT_SCALE_NV = 0x8711, + eGL_DU8DV8_ATI = 0x877A, + eGL_DUAL_ALPHA12_SGIS = 0x8112, + eGL_DUAL_ALPHA16_SGIS = 0x8113, + eGL_DUAL_ALPHA4_SGIS = 0x8110, + eGL_DUAL_ALPHA8_SGIS = 0x8111, + eGL_DUAL_INTENSITY12_SGIS = 0x811A, + eGL_DUAL_INTENSITY16_SGIS = 0x811B, + eGL_DUAL_INTENSITY4_SGIS = 0x8118, + eGL_DUAL_INTENSITY8_SGIS = 0x8119, + eGL_DUAL_LUMINANCE12_SGIS = 0x8116, + eGL_DUAL_LUMINANCE16_SGIS = 0x8117, + eGL_DUAL_LUMINANCE4_SGIS = 0x8114, + eGL_DUAL_LUMINANCE8_SGIS = 0x8115, + eGL_DUAL_LUMINANCE_ALPHA4_SGIS = 0x811C, + eGL_DUAL_LUMINANCE_ALPHA8_SGIS = 0x811D, + eGL_DUAL_TEXTURE_SELECT_SGIS = 0x8124, + eGL_DUDV_ATI = 0x8779, + eGL_DYNAMIC_ATI = 0x8761, + eGL_DYNAMIC_COPY = 0x88EA, + eGL_DYNAMIC_COPY_ARB = 0x88EA, + eGL_DYNAMIC_DRAW = 0x88E8, + eGL_DYNAMIC_DRAW_ARB = 0x88E8, + eGL_DYNAMIC_READ = 0x88E9, + eGL_DYNAMIC_READ_ARB = 0x88E9, + eGL_DYNAMIC_STORAGE_BIT = 0x0100, + eGL_EDGEFLAG_BIT_PGI = 0x00040000, + eGL_EDGE_FLAG_ARRAY_ADDRESS_NV = 0x8F26, + eGL_EDGE_FLAG_ARRAY_BUFFER_BINDING = 0x889B, + eGL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB = 0x889B, + eGL_EDGE_FLAG_ARRAY_COUNT_EXT = 0x808D, + eGL_EDGE_FLAG_ARRAY_EXT = 0x8079, + eGL_EDGE_FLAG_ARRAY_LENGTH_NV = 0x8F30, + eGL_EDGE_FLAG_ARRAY_POINTER_EXT = 0x8093, + eGL_EDGE_FLAG_ARRAY_STRIDE_EXT = 0x808C, + eGL_EIGHTH_BIT_ATI = 0x00000020, + eGL_ELEMENT_ARRAY_ADDRESS_NV = 0x8F29, + eGL_ELEMENT_ARRAY_APPLE = 0x8A0C, + eGL_ELEMENT_ARRAY_ATI = 0x8768, + eGL_ELEMENT_ARRAY_BARRIER_BIT = 0x00000002, + eGL_ELEMENT_ARRAY_BARRIER_BIT_EXT = 0x00000002, + eGL_ELEMENT_ARRAY_BUFFER = 0x8893, + eGL_ELEMENT_ARRAY_BUFFER_ARB = 0x8893, + eGL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895, + eGL_ELEMENT_ARRAY_BUFFER_BINDING_ARB = 0x8895, + eGL_ELEMENT_ARRAY_LENGTH_NV = 0x8F33, + eGL_ELEMENT_ARRAY_POINTER_APPLE = 0x8A0E, + eGL_ELEMENT_ARRAY_POINTER_ATI = 0x876A, + eGL_ELEMENT_ARRAY_TYPE_APPLE = 0x8A0D, + eGL_ELEMENT_ARRAY_TYPE_ATI = 0x8769, + eGL_ELEMENT_ARRAY_UNIFIED_NV = 0x8F1F, + eGL_EMBOSS_CONSTANT_NV = 0x855E, + eGL_EMBOSS_LIGHT_NV = 0x855D, + eGL_EMBOSS_MAP_NV = 0x855F, + eGL_EQUAL = 0x0202, + eGL_EQUIV = 0x1509, + eGL_EVAL_2D_NV = 0x86C0, + eGL_EVAL_FRACTIONAL_TESSELLATION_NV = 0x86C5, + eGL_EVAL_TRIANGULAR_2D_NV = 0x86C1, + eGL_EVAL_VERTEX_ATTRIB0_NV = 0x86C6, + eGL_EVAL_VERTEX_ATTRIB10_NV = 0x86D0, + eGL_EVAL_VERTEX_ATTRIB11_NV = 0x86D1, + eGL_EVAL_VERTEX_ATTRIB12_NV = 0x86D2, + eGL_EVAL_VERTEX_ATTRIB13_NV = 0x86D3, + eGL_EVAL_VERTEX_ATTRIB14_NV = 0x86D4, + eGL_EVAL_VERTEX_ATTRIB15_NV = 0x86D5, + eGL_EVAL_VERTEX_ATTRIB1_NV = 0x86C7, + eGL_EVAL_VERTEX_ATTRIB2_NV = 0x86C8, + eGL_EVAL_VERTEX_ATTRIB3_NV = 0x86C9, + eGL_EVAL_VERTEX_ATTRIB4_NV = 0x86CA, + eGL_EVAL_VERTEX_ATTRIB5_NV = 0x86CB, + eGL_EVAL_VERTEX_ATTRIB6_NV = 0x86CC, + eGL_EVAL_VERTEX_ATTRIB7_NV = 0x86CD, + eGL_EVAL_VERTEX_ATTRIB8_NV = 0x86CE, + eGL_EVAL_VERTEX_ATTRIB9_NV = 0x86CF, + eGL_EXCLUSION_NV = 0x92A0, + eGL_EXPAND_NEGATE_NV = 0x8539, + eGL_EXPAND_NORMAL_NV = 0x8538, + eGL_EXTENSIONS = 0x1F03, + eGL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD = 0x9160, + eGL_EYE_DISTANCE_TO_LINE_SGIS = 0x81F2, + eGL_EYE_DISTANCE_TO_POINT_SGIS = 0x81F0, + eGL_EYE_LINE_SGIS = 0x81F6, + eGL_EYE_PLANE_ABSOLUTE_NV = 0x855C, + eGL_EYE_POINT_SGIS = 0x81F4, + eGL_EYE_RADIAL_NV = 0x855B, + eGL_E_TIMES_F_NV = 0x8531, + eGL_FACTOR_MAX_AMD = 0x901D, + eGL_FACTOR_MIN_AMD = 0x901C, + eGL_FAILURE_NV = 0x9030, + eGL_FASTEST = 0x1101, + eGL_FENCE_APPLE = 0x8A0B, + eGL_FENCE_CONDITION_NV = 0x84F4, + eGL_FENCE_STATUS_NV = 0x84F3, + eGL_FIELDS_NV = 0x8E27, + eGL_FIELD_LOWER_NV = 0x9023, + eGL_FIELD_UPPER_NV = 0x9022, + eGL_FILE_NAME_NV = 0x9074, + eGL_FILL = 0x1B02, + eGL_FILTER = 0x829A, + eGL_FILTER4_SGIS = 0x8146, + eGL_FIRST_TO_REST_NV = 0x90AF, + eGL_FIRST_VERTEX_CONVENTION = 0x8E4D, + eGL_FIRST_VERTEX_CONVENTION_EXT = 0x8E4D, + eGL_FIXED = 0x140C, + eGL_FIXED_OES = 0x140C, + eGL_FIXED_ONLY = 0x891D, + eGL_FIXED_ONLY_ARB = 0x891D, + eGL_FLOAT = 0x1406, + eGL_FLOAT16_NV = 0x8FF8, + eGL_FLOAT16_VEC2_NV = 0x8FF9, + eGL_FLOAT16_VEC3_NV = 0x8FFA, + eGL_FLOAT16_VEC4_NV = 0x8FFB, + eGL_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD, + eGL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV = 0x8DAD, + eGL_FLOAT_CLEAR_COLOR_VALUE_NV = 0x888D, + eGL_FLOAT_MAT2 = 0x8B5A, + eGL_FLOAT_MAT2_ARB = 0x8B5A, + eGL_FLOAT_MAT2x3 = 0x8B65, + eGL_FLOAT_MAT2x4 = 0x8B66, + eGL_FLOAT_MAT3 = 0x8B5B, + eGL_FLOAT_MAT3_ARB = 0x8B5B, + eGL_FLOAT_MAT3x2 = 0x8B67, + eGL_FLOAT_MAT3x4 = 0x8B68, + eGL_FLOAT_MAT4 = 0x8B5C, + eGL_FLOAT_MAT4_ARB = 0x8B5C, + eGL_FLOAT_MAT4x2 = 0x8B69, + eGL_FLOAT_MAT4x3 = 0x8B6A, + eGL_FLOAT_R16_NV = 0x8884, + eGL_FLOAT_R32_NV = 0x8885, + eGL_FLOAT_RG16_NV = 0x8886, + eGL_FLOAT_RG32_NV = 0x8887, + eGL_FLOAT_RGB16_NV = 0x8888, + eGL_FLOAT_RGB32_NV = 0x8889, + eGL_FLOAT_RGBA16_NV = 0x888A, + eGL_FLOAT_RGBA32_NV = 0x888B, + eGL_FLOAT_RGBA_MODE_NV = 0x888E, + eGL_FLOAT_RGBA_NV = 0x8883, + eGL_FLOAT_RGB_NV = 0x8882, + eGL_FLOAT_RG_NV = 0x8881, + eGL_FLOAT_R_NV = 0x8880, + eGL_FLOAT_VEC2 = 0x8B50, + eGL_FLOAT_VEC2_ARB = 0x8B50, + eGL_FLOAT_VEC3 = 0x8B51, + eGL_FLOAT_VEC3_ARB = 0x8B51, + eGL_FLOAT_VEC4 = 0x8B52, + eGL_FLOAT_VEC4_ARB = 0x8B52, + eGL_FOG_COORD = 0x8451, + eGL_FOG_COORDINATE = 0x8451, + eGL_FOG_COORDINATE_ARRAY = 0x8457, + eGL_FOG_COORDINATE_ARRAY_BUFFER_BINDING = 0x889D, + eGL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB = 0x889D, + eGL_FOG_COORDINATE_ARRAY_EXT = 0x8457, + eGL_FOG_COORDINATE_ARRAY_POINTER = 0x8456, + eGL_FOG_COORDINATE_ARRAY_POINTER_EXT = 0x8456, + eGL_FOG_COORDINATE_ARRAY_STRIDE = 0x8455, + eGL_FOG_COORDINATE_ARRAY_STRIDE_EXT = 0x8455, + eGL_FOG_COORDINATE_ARRAY_TYPE = 0x8454, + eGL_FOG_COORDINATE_ARRAY_TYPE_EXT = 0x8454, + eGL_FOG_COORDINATE_EXT = 0x8451, + eGL_FOG_COORDINATE_SOURCE = 0x8450, + eGL_FOG_COORDINATE_SOURCE_EXT = 0x8450, + eGL_FOG_COORD_ARRAY = 0x8457, + eGL_FOG_COORD_ARRAY_ADDRESS_NV = 0x8F28, + eGL_FOG_COORD_ARRAY_BUFFER_BINDING = 0x889D, + eGL_FOG_COORD_ARRAY_LENGTH_NV = 0x8F32, + eGL_FOG_COORD_ARRAY_POINTER = 0x8456, + eGL_FOG_COORD_ARRAY_STRIDE = 0x8455, + eGL_FOG_COORD_ARRAY_TYPE = 0x8454, + eGL_FOG_COORD_SRC = 0x8450, + eGL_FOG_DISTANCE_MODE_NV = 0x855A, + eGL_FOG_FUNC_POINTS_SGIS = 0x812B, + eGL_FOG_FUNC_SGIS = 0x812A, + eGL_FOG_OFFSET_SGIX = 0x8198, + eGL_FOG_OFFSET_VALUE_SGIX = 0x8199, + eGL_FOG_SPECULAR_TEXTURE_WIN = 0x80EC, + eGL_FONT_ASCENDER_BIT_NV = 0x00200000, + eGL_FONT_DESCENDER_BIT_NV = 0x00400000, + eGL_FONT_HAS_KERNING_BIT_NV = 0x10000000, + eGL_FONT_HEIGHT_BIT_NV = 0x00800000, + eGL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV = 0x02000000, + eGL_FONT_MAX_ADVANCE_WIDTH_BIT_NV = 0x01000000, + eGL_FONT_UNDERLINE_POSITION_BIT_NV = 0x04000000, + eGL_FONT_UNDERLINE_THICKNESS_BIT_NV = 0x08000000, + eGL_FONT_UNITS_PER_EM_BIT_NV = 0x00100000, + eGL_FONT_X_MAX_BOUNDS_BIT_NV = 0x00040000, + eGL_FONT_X_MIN_BOUNDS_BIT_NV = 0x00010000, + eGL_FONT_Y_MAX_BOUNDS_BIT_NV = 0x00080000, + eGL_FONT_Y_MIN_BOUNDS_BIT_NV = 0x00020000, + eGL_FORCE_BLUE_TO_ONE_NV = 0x8860, + eGL_FORMAT_SUBSAMPLE_244_244_OML = 0x8983, + eGL_FORMAT_SUBSAMPLE_24_24_OML = 0x8982, + eGL_FRACTIONAL_EVEN = 0x8E7C, + eGL_FRACTIONAL_ODD = 0x8E7B, + eGL_FRAGMENT_COLOR_EXT = 0x834C, + eGL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX = 0x8402, + eGL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX = 0x8403, + eGL_FRAGMENT_COLOR_MATERIAL_SGIX = 0x8401, + eGL_FRAGMENT_DEPTH = 0x8452, + eGL_FRAGMENT_DEPTH_EXT = 0x8452, + eGL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 0x8E5D, + eGL_FRAGMENT_LIGHT0_SGIX = 0x840C, + eGL_FRAGMENT_LIGHT1_SGIX = 0x840D, + eGL_FRAGMENT_LIGHT2_SGIX = 0x840E, + eGL_FRAGMENT_LIGHT3_SGIX = 0x840F, + eGL_FRAGMENT_LIGHT4_SGIX = 0x8410, + eGL_FRAGMENT_LIGHT5_SGIX = 0x8411, + eGL_FRAGMENT_LIGHT6_SGIX = 0x8412, + eGL_FRAGMENT_LIGHT7_SGIX = 0x8413, + eGL_FRAGMENT_LIGHTING_SGIX = 0x8400, + eGL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX = 0x840A, + eGL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX = 0x8408, + eGL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX = 0x840B, + eGL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX = 0x8409, + eGL_FRAGMENT_MATERIAL_EXT = 0x8349, + eGL_FRAGMENT_NORMAL_EXT = 0x834A, + eGL_FRAGMENT_PROGRAM_ARB = 0x8804, + eGL_FRAGMENT_PROGRAM_BINDING_NV = 0x8873, + eGL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV = 0x8E5D, + eGL_FRAGMENT_PROGRAM_NV = 0x8870, + eGL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV = 0x8DA4, + eGL_FRAGMENT_SHADER = 0x8B30, + eGL_FRAGMENT_SHADER_ARB = 0x8B30, + eGL_FRAGMENT_SHADER_ATI = 0x8920, + eGL_FRAGMENT_SHADER_BIT = 0x00000002, + eGL_FRAGMENT_SHADER_DERIVATIVE_HINT = 0x8B8B, + eGL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB = 0x8B8B, + eGL_FRAGMENT_SUBROUTINE = 0x92EC, + eGL_FRAGMENT_SUBROUTINE_UNIFORM = 0x92F2, + eGL_FRAGMENT_TEXTURE = 0x829F, + eGL_FRAMEBUFFER = 0x8D40, + eGL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 0x8215, + eGL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 0x8214, + eGL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210, + eGL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 0x8211, + eGL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216, + eGL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 0x8213, + eGL_FRAMEBUFFER_ATTACHMENT_LAYERED = 0x8DA7, + eGL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB = 0x8DA7, + eGL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT = 0x8DA7, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT = 0x8CD1, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT = 0x8CD0, + eGL_FRAMEBUFFER_ATTACHMENT_RED_SIZE = 0x8212, + eGL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT = 0x8CD4, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT = 0x8CD3, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 0x8CD4, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT = 0x8CD4, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT = 0x8CD2, + eGL_FRAMEBUFFER_BARRIER_BIT = 0x00000400, + eGL_FRAMEBUFFER_BARRIER_BIT_EXT = 0x00000400, + eGL_FRAMEBUFFER_BINDING = 0x8CA6, + eGL_FRAMEBUFFER_BINDING_EXT = 0x8CA6, + eGL_FRAMEBUFFER_BLEND = 0x828B, + eGL_FRAMEBUFFER_COMPLETE = 0x8CD5, + eGL_FRAMEBUFFER_COMPLETE_EXT = 0x8CD5, + eGL_FRAMEBUFFER_DEFAULT = 0x8218, + eGL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 0x9314, + eGL_FRAMEBUFFER_DEFAULT_HEIGHT = 0x9311, + eGL_FRAMEBUFFER_DEFAULT_LAYERS = 0x9312, + eGL_FRAMEBUFFER_DEFAULT_SAMPLES = 0x9313, + eGL_FRAMEBUFFER_DEFAULT_WIDTH = 0x9310, + eGL_FRAMEBUFFER_EXT = 0x8D40, + eGL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6, + eGL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT = 0x8CD6, + eGL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT = 0x8CD9, + eGL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = 0x8CDB, + eGL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT = 0x8CDB, + eGL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT = 0x8CDA, + eGL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB = 0x8DA9, + eGL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT = 0x8DA9, + eGL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 0x8DA8, + eGL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB = 0x8DA8, + eGL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT = 0x8DA8, + eGL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7, + eGL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT = 0x8CD7, + eGL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56, + eGL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT = 0x8D56, + eGL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER = 0x8CDC, + eGL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT = 0x8CDC, + eGL_FRAMEBUFFER_RENDERABLE = 0x8289, + eGL_FRAMEBUFFER_RENDERABLE_LAYERED = 0x828A, + eGL_FRAMEBUFFER_SRGB = 0x8DB9, + eGL_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x8DBA, + eGL_FRAMEBUFFER_SRGB_EXT = 0x8DB9, + eGL_FRAMEBUFFER_UNDEFINED = 0x8219, + eGL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD, + eGL_FRAMEBUFFER_UNSUPPORTED_EXT = 0x8CDD, + eGL_FRAMEZOOM_FACTOR_SGIX = 0x818C, + eGL_FRAMEZOOM_SGIX = 0x818B, + eGL_FRAME_NV = 0x8E26, + eGL_FRONT = 0x0404, + eGL_FRONT_AND_BACK = 0x0408, + eGL_FRONT_FACE = 0x0B46, + eGL_FRONT_LEFT = 0x0400, + eGL_FRONT_RIGHT = 0x0401, + eGL_FULL_RANGE_EXT = 0x87E1, + eGL_FULL_STIPPLE_HINT_PGI = 0x1A219, + eGL_FULL_SUPPORT = 0x82B7, + eGL_FUNC_ADD = 0x8006, + eGL_FUNC_ADD_EXT = 0x8006, + eGL_FUNC_REVERSE_SUBTRACT = 0x800B, + eGL_FUNC_REVERSE_SUBTRACT_EXT = 0x800B, + eGL_FUNC_SUBTRACT = 0x800A, + eGL_FUNC_SUBTRACT_EXT = 0x800A, + eGL_GENERATE_MIPMAP = 0x8191, + eGL_GENERATE_MIPMAP_HINT = 0x8192, + eGL_GENERATE_MIPMAP_HINT_SGIS = 0x8192, + eGL_GENERATE_MIPMAP_SGIS = 0x8191, + eGL_GENERIC_ATTRIB_NV = 0x8C7D, + eGL_GEOMETRY_DEFORMATION_BIT_SGIX = 0x00000002, + eGL_GEOMETRY_DEFORMATION_SGIX = 0x8194, + eGL_GEOMETRY_INPUT_TYPE = 0x8917, + eGL_GEOMETRY_INPUT_TYPE_ARB = 0x8DDB, + eGL_GEOMETRY_INPUT_TYPE_EXT = 0x8DDB, + eGL_GEOMETRY_OUTPUT_TYPE = 0x8918, + eGL_GEOMETRY_OUTPUT_TYPE_ARB = 0x8DDC, + eGL_GEOMETRY_OUTPUT_TYPE_EXT = 0x8DDC, + eGL_GEOMETRY_PROGRAM_NV = 0x8C26, + eGL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV = 0x8DA3, + eGL_GEOMETRY_SHADER = 0x8DD9, + eGL_GEOMETRY_SHADER_ARB = 0x8DD9, + eGL_GEOMETRY_SHADER_BIT = 0x00000004, + eGL_GEOMETRY_SHADER_EXT = 0x8DD9, + eGL_GEOMETRY_SHADER_INVOCATIONS = 0x887F, + eGL_GEOMETRY_SUBROUTINE = 0x92EB, + eGL_GEOMETRY_SUBROUTINE_UNIFORM = 0x92F1, + eGL_GEOMETRY_TEXTURE = 0x829E, + eGL_GEOMETRY_VERTICES_OUT = 0x8916, + eGL_GEOMETRY_VERTICES_OUT_ARB = 0x8DDA, + eGL_GEOMETRY_VERTICES_OUT_EXT = 0x8DDA, + eGL_GEQUAL = 0x0206, + eGL_GET_TEXTURE_IMAGE_FORMAT = 0x8291, + eGL_GET_TEXTURE_IMAGE_TYPE = 0x8292, + eGL_GLOBAL_ALPHA_FACTOR_SUN = 0x81DA, + eGL_GLOBAL_ALPHA_SUN = 0x81D9, + eGL_GPU_ADDRESS_NV = 0x8F34, + eGL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049, + eGL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX = 0x9047, + eGL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX = 0x904B, + eGL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX = 0x904A, + eGL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048, + eGL_GREATER = 0x0204, + eGL_GREEN = 0x1904, + eGL_GREEN_BIT_ATI = 0x00000002, + eGL_GREEN_INTEGER = 0x8D95, + eGL_GREEN_INTEGER_EXT = 0x8D95, + eGL_GREEN_MAX_CLAMP_INGR = 0x8565, + eGL_GREEN_MIN_CLAMP_INGR = 0x8561, + eGL_GREEN_NV = 0x1904, + eGL_GUILTY_CONTEXT_RESET_ARB = 0x8253, + eGL_HALF_APPLE = 0x140B, + eGL_HALF_BIAS_NEGATE_NV = 0x853B, + eGL_HALF_BIAS_NORMAL_NV = 0x853A, + eGL_HALF_BIT_ATI = 0x00000008, + eGL_HALF_FLOAT = 0x140B, + eGL_HALF_FLOAT_ARB = 0x140B, + eGL_HALF_FLOAT_NV = 0x140B, + eGL_HARDLIGHT_NV = 0x929B, + eGL_HARDMIX_NV = 0x92A9, + eGL_HIGH_FLOAT = 0x8DF2, + eGL_HIGH_INT = 0x8DF5, + eGL_HILO16_NV = 0x86F8, + eGL_HILO8_NV = 0x885E, + eGL_HILO_NV = 0x86F4, + eGL_HISTOGRAM = 0x8024, + eGL_HISTOGRAM_ALPHA_SIZE = 0x802B, + eGL_HISTOGRAM_ALPHA_SIZE_EXT = 0x802B, + eGL_HISTOGRAM_BLUE_SIZE = 0x802A, + eGL_HISTOGRAM_BLUE_SIZE_EXT = 0x802A, + eGL_HISTOGRAM_EXT = 0x8024, + eGL_HISTOGRAM_FORMAT = 0x8027, + eGL_HISTOGRAM_FORMAT_EXT = 0x8027, + eGL_HISTOGRAM_GREEN_SIZE = 0x8029, + eGL_HISTOGRAM_GREEN_SIZE_EXT = 0x8029, + eGL_HISTOGRAM_LUMINANCE_SIZE = 0x802C, + eGL_HISTOGRAM_LUMINANCE_SIZE_EXT = 0x802C, + eGL_HISTOGRAM_RED_SIZE = 0x8028, + eGL_HISTOGRAM_RED_SIZE_EXT = 0x8028, + eGL_HISTOGRAM_SINK = 0x802D, + eGL_HISTOGRAM_SINK_EXT = 0x802D, + eGL_HISTOGRAM_WIDTH = 0x8026, + eGL_HISTOGRAM_WIDTH_EXT = 0x8026, + eGL_HI_BIAS_NV = 0x8714, + eGL_HI_SCALE_NV = 0x870E, + eGL_HSL_COLOR_NV = 0x92AF, + eGL_HSL_HUE_NV = 0x92AD, + eGL_HSL_LUMINOSITY_NV = 0x92B0, + eGL_HSL_SATURATION_NV = 0x92AE, + eGL_IDENTITY_NV = 0x862A, + eGL_IGNORE_BORDER_HP = 0x8150, + eGL_IMAGE_1D = 0x904C, + eGL_IMAGE_1D_ARRAY = 0x9052, + eGL_IMAGE_1D_ARRAY_EXT = 0x9052, + eGL_IMAGE_1D_EXT = 0x904C, + eGL_IMAGE_2D = 0x904D, + eGL_IMAGE_2D_ARRAY = 0x9053, + eGL_IMAGE_2D_ARRAY_EXT = 0x9053, + eGL_IMAGE_2D_EXT = 0x904D, + eGL_IMAGE_2D_MULTISAMPLE = 0x9055, + eGL_IMAGE_2D_MULTISAMPLE_ARRAY = 0x9056, + eGL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT = 0x9056, + eGL_IMAGE_2D_MULTISAMPLE_EXT = 0x9055, + eGL_IMAGE_2D_RECT = 0x904F, + eGL_IMAGE_2D_RECT_EXT = 0x904F, + eGL_IMAGE_3D = 0x904E, + eGL_IMAGE_3D_EXT = 0x904E, + eGL_IMAGE_BINDING_ACCESS = 0x8F3E, + eGL_IMAGE_BINDING_ACCESS_EXT = 0x8F3E, + eGL_IMAGE_BINDING_FORMAT = 0x906E, + eGL_IMAGE_BINDING_FORMAT_EXT = 0x906E, + eGL_IMAGE_BINDING_LAYER = 0x8F3D, + eGL_IMAGE_BINDING_LAYERED = 0x8F3C, + eGL_IMAGE_BINDING_LAYERED_EXT = 0x8F3C, + eGL_IMAGE_BINDING_LAYER_EXT = 0x8F3D, + eGL_IMAGE_BINDING_LEVEL = 0x8F3B, + eGL_IMAGE_BINDING_LEVEL_EXT = 0x8F3B, + eGL_IMAGE_BINDING_NAME = 0x8F3A, + eGL_IMAGE_BINDING_NAME_EXT = 0x8F3A, + eGL_IMAGE_BUFFER = 0x9051, + eGL_IMAGE_BUFFER_EXT = 0x9051, + eGL_IMAGE_CLASS_10_10_10_2 = 0x82C3, + eGL_IMAGE_CLASS_11_11_10 = 0x82C2, + eGL_IMAGE_CLASS_1_X_16 = 0x82BE, + eGL_IMAGE_CLASS_1_X_32 = 0x82BB, + eGL_IMAGE_CLASS_1_X_8 = 0x82C1, + eGL_IMAGE_CLASS_2_X_16 = 0x82BD, + eGL_IMAGE_CLASS_2_X_32 = 0x82BA, + eGL_IMAGE_CLASS_2_X_8 = 0x82C0, + eGL_IMAGE_CLASS_4_X_16 = 0x82BC, + eGL_IMAGE_CLASS_4_X_32 = 0x82B9, + eGL_IMAGE_CLASS_4_X_8 = 0x82BF, + eGL_IMAGE_COMPATIBILITY_CLASS = 0x82A8, + eGL_IMAGE_CUBE = 0x9050, + eGL_IMAGE_CUBE_EXT = 0x9050, + eGL_IMAGE_CUBE_MAP_ARRAY = 0x9054, + eGL_IMAGE_CUBE_MAP_ARRAY_EXT = 0x9054, + eGL_IMAGE_CUBIC_WEIGHT_HP = 0x815E, + eGL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS = 0x90C9, + eGL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE = 0x90C8, + eGL_IMAGE_FORMAT_COMPATIBILITY_TYPE = 0x90C7, + eGL_IMAGE_MAG_FILTER_HP = 0x815C, + eGL_IMAGE_MIN_FILTER_HP = 0x815D, + eGL_IMAGE_PIXEL_FORMAT = 0x82A9, + eGL_IMAGE_PIXEL_TYPE = 0x82AA, + eGL_IMAGE_ROTATE_ANGLE_HP = 0x8159, + eGL_IMAGE_ROTATE_ORIGIN_X_HP = 0x815A, + eGL_IMAGE_ROTATE_ORIGIN_Y_HP = 0x815B, + eGL_IMAGE_SCALE_X_HP = 0x8155, + eGL_IMAGE_SCALE_Y_HP = 0x8156, + eGL_IMAGE_TEXEL_SIZE = 0x82A7, + eGL_IMAGE_TRANSFORM_2D_HP = 0x8161, + eGL_IMAGE_TRANSLATE_X_HP = 0x8157, + eGL_IMAGE_TRANSLATE_Y_HP = 0x8158, + eGL_IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B, + eGL_IMPLEMENTATION_COLOR_READ_FORMAT_OES = 0x8B9B, + eGL_IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A, + eGL_IMPLEMENTATION_COLOR_READ_TYPE_OES = 0x8B9A, + eGL_INCR = 0x1E02, + eGL_INCR_WRAP = 0x8507, + eGL_INCR_WRAP_EXT = 0x8507, + eGL_INDEX = 0x8222, + eGL_INDEX_ARRAY_ADDRESS_NV = 0x8F24, + eGL_INDEX_ARRAY_BUFFER_BINDING = 0x8899, + eGL_INDEX_ARRAY_BUFFER_BINDING_ARB = 0x8899, + eGL_INDEX_ARRAY_COUNT_EXT = 0x8087, + eGL_INDEX_ARRAY_EXT = 0x8077, + eGL_INDEX_ARRAY_LENGTH_NV = 0x8F2E, + eGL_INDEX_ARRAY_POINTER_EXT = 0x8091, + eGL_INDEX_ARRAY_STRIDE_EXT = 0x8086, + eGL_INDEX_ARRAY_TYPE_EXT = 0x8085, + eGL_INDEX_BIT_PGI = 0x00080000, + eGL_INDEX_MATERIAL_EXT = 0x81B8, + eGL_INDEX_MATERIAL_FACE_EXT = 0x81BA, + eGL_INDEX_MATERIAL_PARAMETER_EXT = 0x81B9, + eGL_INDEX_TEST_EXT = 0x81B5, + eGL_INDEX_TEST_FUNC_EXT = 0x81B6, + eGL_INDEX_TEST_REF_EXT = 0x81B7, + eGL_INFO_LOG_LENGTH = 0x8B84, + eGL_INNOCENT_CONTEXT_RESET_ARB = 0x8254, + eGL_INSTRUMENT_BUFFER_POINTER_SGIX = 0x8180, + eGL_INSTRUMENT_MEASUREMENTS_SGIX = 0x8181, + eGL_INT = 0x1404, + eGL_INT16_NV = 0x8FE4, + eGL_INT16_VEC2_NV = 0x8FE5, + eGL_INT16_VEC3_NV = 0x8FE6, + eGL_INT16_VEC4_NV = 0x8FE7, + eGL_INT64_NV = 0x140E, + eGL_INT64_VEC2_NV = 0x8FE9, + eGL_INT64_VEC3_NV = 0x8FEA, + eGL_INT64_VEC4_NV = 0x8FEB, + eGL_INT8_NV = 0x8FE0, + eGL_INT8_VEC2_NV = 0x8FE1, + eGL_INT8_VEC3_NV = 0x8FE2, + eGL_INT8_VEC4_NV = 0x8FE3, + eGL_INTENSITY12_EXT = 0x804C, + eGL_INTENSITY16F_ARB = 0x881D, + eGL_INTENSITY16I_EXT = 0x8D8B, + eGL_INTENSITY16UI_EXT = 0x8D79, + eGL_INTENSITY16_EXT = 0x804D, + eGL_INTENSITY16_SNORM = 0x901B, + eGL_INTENSITY32F_ARB = 0x8817, + eGL_INTENSITY32I_EXT = 0x8D85, + eGL_INTENSITY32UI_EXT = 0x8D73, + eGL_INTENSITY4_EXT = 0x804A, + eGL_INTENSITY8I_EXT = 0x8D91, + eGL_INTENSITY8UI_EXT = 0x8D7F, + eGL_INTENSITY8_EXT = 0x804B, + eGL_INTENSITY8_SNORM = 0x9017, + eGL_INTENSITY_EXT = 0x8049, + eGL_INTENSITY_FLOAT16_APPLE = 0x881D, + eGL_INTENSITY_FLOAT16_ATI = 0x881D, + eGL_INTENSITY_FLOAT32_APPLE = 0x8817, + eGL_INTENSITY_FLOAT32_ATI = 0x8817, + eGL_INTENSITY_SNORM = 0x9013, + eGL_INTERLACE_OML = 0x8980, + eGL_INTERLACE_READ_INGR = 0x8568, + eGL_INTERLACE_READ_OML = 0x8981, + eGL_INTERLACE_SGIX = 0x8094, + eGL_INTERLEAVED_ATTRIBS = 0x8C8C, + eGL_INTERLEAVED_ATTRIBS_EXT = 0x8C8C, + eGL_INTERLEAVED_ATTRIBS_NV = 0x8C8C, + eGL_INTERNALFORMAT_ALPHA_SIZE = 0x8274, + eGL_INTERNALFORMAT_ALPHA_TYPE = 0x827B, + eGL_INTERNALFORMAT_BLUE_SIZE = 0x8273, + eGL_INTERNALFORMAT_BLUE_TYPE = 0x827A, + eGL_INTERNALFORMAT_DEPTH_SIZE = 0x8275, + eGL_INTERNALFORMAT_DEPTH_TYPE = 0x827C, + eGL_INTERNALFORMAT_GREEN_SIZE = 0x8272, + eGL_INTERNALFORMAT_GREEN_TYPE = 0x8279, + eGL_INTERNALFORMAT_PREFERRED = 0x8270, + eGL_INTERNALFORMAT_RED_SIZE = 0x8271, + eGL_INTERNALFORMAT_RED_TYPE = 0x8278, + eGL_INTERNALFORMAT_SHARED_SIZE = 0x8277, + eGL_INTERNALFORMAT_STENCIL_SIZE = 0x8276, + eGL_INTERNALFORMAT_STENCIL_TYPE = 0x827D, + eGL_INTERNALFORMAT_SUPPORTED = 0x826F, + eGL_INTERPOLATE = 0x8575, + eGL_INTERPOLATE_ARB = 0x8575, + eGL_INTERPOLATE_EXT = 0x8575, + eGL_INT_2_10_10_10_REV = 0x8D9F, + eGL_INT_IMAGE_1D = 0x9057, + eGL_INT_IMAGE_1D_ARRAY = 0x905D, + eGL_INT_IMAGE_1D_ARRAY_EXT = 0x905D, + eGL_INT_IMAGE_1D_EXT = 0x9057, + eGL_INT_IMAGE_2D = 0x9058, + eGL_INT_IMAGE_2D_ARRAY = 0x905E, + eGL_INT_IMAGE_2D_ARRAY_EXT = 0x905E, + eGL_INT_IMAGE_2D_EXT = 0x9058, + eGL_INT_IMAGE_2D_MULTISAMPLE = 0x9060, + eGL_INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x9061, + eGL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT = 0x9061, + eGL_INT_IMAGE_2D_MULTISAMPLE_EXT = 0x9060, + eGL_INT_IMAGE_2D_RECT = 0x905A, + eGL_INT_IMAGE_2D_RECT_EXT = 0x905A, + eGL_INT_IMAGE_3D = 0x9059, + eGL_INT_IMAGE_3D_EXT = 0x9059, + eGL_INT_IMAGE_BUFFER = 0x905C, + eGL_INT_IMAGE_BUFFER_EXT = 0x905C, + eGL_INT_IMAGE_CUBE = 0x905B, + eGL_INT_IMAGE_CUBE_EXT = 0x905B, + eGL_INT_IMAGE_CUBE_MAP_ARRAY = 0x905F, + eGL_INT_IMAGE_CUBE_MAP_ARRAY_EXT = 0x905F, + eGL_INT_SAMPLER_1D = 0x8DC9, + eGL_INT_SAMPLER_1D_ARRAY = 0x8DCE, + eGL_INT_SAMPLER_1D_ARRAY_EXT = 0x8DCE, + eGL_INT_SAMPLER_1D_EXT = 0x8DC9, + eGL_INT_SAMPLER_2D = 0x8DCA, + eGL_INT_SAMPLER_2D_ARRAY = 0x8DCF, + eGL_INT_SAMPLER_2D_ARRAY_EXT = 0x8DCF, + eGL_INT_SAMPLER_2D_EXT = 0x8DCA, + eGL_INT_SAMPLER_2D_MULTISAMPLE = 0x9109, + eGL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910C, + eGL_INT_SAMPLER_2D_RECT = 0x8DCD, + eGL_INT_SAMPLER_2D_RECT_EXT = 0x8DCD, + eGL_INT_SAMPLER_3D = 0x8DCB, + eGL_INT_SAMPLER_3D_EXT = 0x8DCB, + eGL_INT_SAMPLER_BUFFER = 0x8DD0, + eGL_INT_SAMPLER_BUFFER_AMD = 0x9002, + eGL_INT_SAMPLER_BUFFER_EXT = 0x8DD0, + eGL_INT_SAMPLER_CUBE = 0x8DCC, + eGL_INT_SAMPLER_CUBE_EXT = 0x8DCC, + eGL_INT_SAMPLER_CUBE_MAP_ARRAY = 0x900E, + eGL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB = 0x900E, + eGL_INT_SAMPLER_RENDERBUFFER_NV = 0x8E57, + eGL_INT_VEC2 = 0x8B53, + eGL_INT_VEC2_ARB = 0x8B53, + eGL_INT_VEC3 = 0x8B54, + eGL_INT_VEC3_ARB = 0x8B54, + eGL_INT_VEC4 = 0x8B55, + eGL_INT_VEC4_ARB = 0x8B55, + eGL_INVALID_ENUM = 0x0500, + eGL_INVALID_FRAMEBUFFER_OPERATION = 0x0506, + eGL_INVALID_FRAMEBUFFER_OPERATION_EXT = 0x0506, + eGL_INVALID_OPERATION = 0x0502, + eGL_INVALID_VALUE = 0x0501, + eGL_INVARIANT_DATATYPE_EXT = 0x87EB, + eGL_INVARIANT_EXT = 0x87C2, + eGL_INVARIANT_VALUE_EXT = 0x87EA, + eGL_INVERSE_NV = 0x862B, + eGL_INVERSE_TRANSPOSE_NV = 0x862D, + eGL_INVERT = 0x150A, + eGL_INVERTED_SCREEN_W_REND = 0x8491, + eGL_INVERT_OVG_NV = 0x92B4, + eGL_INVERT_RGB_NV = 0x92A3, + eGL_IR_INSTRUMENT1_SGIX = 0x817F, + eGL_ISOLINES = 0x8E7A, + eGL_IS_PER_PATCH = 0x92E7, + eGL_IS_ROW_MAJOR = 0x9300, + eGL_IUI_N3F_V2F_EXT = 0x81AF, + eGL_IUI_N3F_V3F_EXT = 0x81B0, + eGL_IUI_V2F_EXT = 0x81AD, + eGL_IUI_V3F_EXT = 0x81AE, + eGL_KEEP = 0x1E00, + eGL_LAST_VERTEX_CONVENTION = 0x8E4E, + eGL_LAST_VERTEX_CONVENTION_EXT = 0x8E4E, + eGL_LAST_VIDEO_CAPTURE_STATUS_NV = 0x9027, + eGL_LAYER_NV = 0x8DAA, + eGL_LAYER_PROVOKING_VERTEX = 0x825E, + eGL_LEFT = 0x0406, + eGL_LEQUAL = 0x0203, + eGL_LERP_ATI = 0x8969, + eGL_LESS = 0x0201, + eGL_LIGHTEN_NV = 0x9298, + eGL_LIGHT_ENV_MODE_SGIX = 0x8407, + eGL_LIGHT_MODEL_COLOR_CONTROL = 0x81F8, + eGL_LIGHT_MODEL_COLOR_CONTROL_EXT = 0x81F8, + eGL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE = 0x85B0, + eGL_LINE = 0x1B01, + eGL_LINEAR = 0x2601, + eGL_LINEARBURN_NV = 0x92A5, + eGL_LINEARDODGE_NV = 0x92A4, + eGL_LINEARLIGHT_NV = 0x92A7, + eGL_LINEAR_CLIPMAP_LINEAR_SGIX = 0x8170, + eGL_LINEAR_CLIPMAP_NEAREST_SGIX = 0x844F, + eGL_LINEAR_DETAIL_ALPHA_SGIS = 0x8098, + eGL_LINEAR_DETAIL_COLOR_SGIS = 0x8099, + eGL_LINEAR_DETAIL_SGIS = 0x8097, + eGL_LINEAR_MIPMAP_LINEAR = 0x2703, + eGL_LINEAR_MIPMAP_NEAREST = 0x2701, + eGL_LINEAR_SHARPEN_ALPHA_SGIS = 0x80AE, + eGL_LINEAR_SHARPEN_COLOR_SGIS = 0x80AF, + eGL_LINEAR_SHARPEN_SGIS = 0x80AD, + eGL_LINES = 0x0001, + eGL_LINES_ADJACENCY = 0x000A, + eGL_LINES_ADJACENCY_ARB = 0x000A, + eGL_LINES_ADJACENCY_EXT = 0x000A, + eGL_LINE_LOOP = 0x0002, + eGL_LINE_SMOOTH = 0x0B20, + eGL_LINE_SMOOTH_HINT = 0x0C52, + eGL_LINE_STRIP = 0x0003, + eGL_LINE_STRIP_ADJACENCY = 0x000B, + eGL_LINE_STRIP_ADJACENCY_ARB = 0x000B, + eGL_LINE_STRIP_ADJACENCY_EXT = 0x000B, + eGL_LINE_WIDTH = 0x0B21, + eGL_LINE_WIDTH_GRANULARITY = 0x0B23, + eGL_LINE_WIDTH_RANGE = 0x0B22, + eGL_LINK_STATUS = 0x8B82, + eGL_LIST_PRIORITY_SGIX = 0x8182, + eGL_LOCAL_CONSTANT_DATATYPE_EXT = 0x87ED, + eGL_LOCAL_CONSTANT_EXT = 0x87C3, + eGL_LOCAL_CONSTANT_VALUE_EXT = 0x87EC, + eGL_LOCAL_EXT = 0x87C4, + eGL_LOCATION = 0x930E, + eGL_LOCATION_COMPONENT = 0x934A, + eGL_LOCATION_INDEX = 0x930F, + eGL_LOGIC_OP_MODE = 0x0BF0, + eGL_LOSE_CONTEXT_ON_RESET_ARB = 0x8252, + eGL_LOWER_LEFT = 0x8CA1, + eGL_LOW_FLOAT = 0x8DF0, + eGL_LOW_INT = 0x8DF3, + eGL_LO_BIAS_NV = 0x8715, + eGL_LO_SCALE_NV = 0x870F, + eGL_LUMINANCE12_ALPHA12_EXT = 0x8047, + eGL_LUMINANCE12_ALPHA4_EXT = 0x8046, + eGL_LUMINANCE12_EXT = 0x8041, + eGL_LUMINANCE16F_ARB = 0x881E, + eGL_LUMINANCE16I_EXT = 0x8D8C, + eGL_LUMINANCE16UI_EXT = 0x8D7A, + eGL_LUMINANCE16_ALPHA16_EXT = 0x8048, + eGL_LUMINANCE16_ALPHA16_SNORM = 0x901A, + eGL_LUMINANCE16_EXT = 0x8042, + eGL_LUMINANCE16_SNORM = 0x9019, + eGL_LUMINANCE32F_ARB = 0x8818, + eGL_LUMINANCE32I_EXT = 0x8D86, + eGL_LUMINANCE32UI_EXT = 0x8D74, + eGL_LUMINANCE4_ALPHA4_EXT = 0x8043, + eGL_LUMINANCE4_EXT = 0x803F, + eGL_LUMINANCE6_ALPHA2_EXT = 0x8044, + eGL_LUMINANCE8I_EXT = 0x8D92, + eGL_LUMINANCE8UI_EXT = 0x8D80, + eGL_LUMINANCE8_ALPHA8_EXT = 0x8045, + eGL_LUMINANCE8_ALPHA8_SNORM = 0x9016, + eGL_LUMINANCE8_EXT = 0x8040, + eGL_LUMINANCE8_SNORM = 0x9015, + eGL_LUMINANCE_ALPHA16F_ARB = 0x881F, + eGL_LUMINANCE_ALPHA16I_EXT = 0x8D8D, + eGL_LUMINANCE_ALPHA16UI_EXT = 0x8D7B, + eGL_LUMINANCE_ALPHA32F_ARB = 0x8819, + eGL_LUMINANCE_ALPHA32I_EXT = 0x8D87, + eGL_LUMINANCE_ALPHA32UI_EXT = 0x8D75, + eGL_LUMINANCE_ALPHA8I_EXT = 0x8D93, + eGL_LUMINANCE_ALPHA8UI_EXT = 0x8D81, + eGL_LUMINANCE_ALPHA_FLOAT16_APPLE = 0x881F, + eGL_LUMINANCE_ALPHA_FLOAT16_ATI = 0x881F, + eGL_LUMINANCE_ALPHA_FLOAT32_APPLE = 0x8819, + eGL_LUMINANCE_ALPHA_FLOAT32_ATI = 0x8819, + eGL_LUMINANCE_ALPHA_INTEGER_EXT = 0x8D9D, + eGL_LUMINANCE_ALPHA_SNORM = 0x9012, + eGL_LUMINANCE_FLOAT16_APPLE = 0x881E, + eGL_LUMINANCE_FLOAT16_ATI = 0x881E, + eGL_LUMINANCE_FLOAT32_APPLE = 0x8818, + eGL_LUMINANCE_FLOAT32_ATI = 0x8818, + eGL_LUMINANCE_INTEGER_EXT = 0x8D9C, + eGL_LUMINANCE_SNORM = 0x9011, + eGL_MAD_ATI = 0x8968, + eGL_MAGNITUDE_BIAS_NV = 0x8718, + eGL_MAGNITUDE_SCALE_NV = 0x8712, + eGL_MAJOR_VERSION = 0x821B, + eGL_MANUAL_GENERATE_MIPMAP = 0x8294, + eGL_MAP1_BINORMAL_EXT = 0x8446, + eGL_MAP1_TANGENT_EXT = 0x8444, + eGL_MAP1_VERTEX_ATTRIB0_4_NV = 0x8660, + eGL_MAP1_VERTEX_ATTRIB10_4_NV = 0x866A, + eGL_MAP1_VERTEX_ATTRIB11_4_NV = 0x866B, + eGL_MAP1_VERTEX_ATTRIB12_4_NV = 0x866C, + eGL_MAP1_VERTEX_ATTRIB13_4_NV = 0x866D, + eGL_MAP1_VERTEX_ATTRIB14_4_NV = 0x866E, + eGL_MAP1_VERTEX_ATTRIB15_4_NV = 0x866F, + eGL_MAP1_VERTEX_ATTRIB1_4_NV = 0x8661, + eGL_MAP1_VERTEX_ATTRIB2_4_NV = 0x8662, + eGL_MAP1_VERTEX_ATTRIB3_4_NV = 0x8663, + eGL_MAP1_VERTEX_ATTRIB4_4_NV = 0x8664, + eGL_MAP1_VERTEX_ATTRIB5_4_NV = 0x8665, + eGL_MAP1_VERTEX_ATTRIB6_4_NV = 0x8666, + eGL_MAP1_VERTEX_ATTRIB7_4_NV = 0x8667, + eGL_MAP1_VERTEX_ATTRIB8_4_NV = 0x8668, + eGL_MAP1_VERTEX_ATTRIB9_4_NV = 0x8669, + eGL_MAP2_BINORMAL_EXT = 0x8447, + eGL_MAP2_TANGENT_EXT = 0x8445, + eGL_MAP2_VERTEX_ATTRIB0_4_NV = 0x8670, + eGL_MAP2_VERTEX_ATTRIB10_4_NV = 0x867A, + eGL_MAP2_VERTEX_ATTRIB11_4_NV = 0x867B, + eGL_MAP2_VERTEX_ATTRIB12_4_NV = 0x867C, + eGL_MAP2_VERTEX_ATTRIB13_4_NV = 0x867D, + eGL_MAP2_VERTEX_ATTRIB14_4_NV = 0x867E, + eGL_MAP2_VERTEX_ATTRIB15_4_NV = 0x867F, + eGL_MAP2_VERTEX_ATTRIB1_4_NV = 0x8671, + eGL_MAP2_VERTEX_ATTRIB2_4_NV = 0x8672, + eGL_MAP2_VERTEX_ATTRIB3_4_NV = 0x8673, + eGL_MAP2_VERTEX_ATTRIB4_4_NV = 0x8674, + eGL_MAP2_VERTEX_ATTRIB5_4_NV = 0x8675, + eGL_MAP2_VERTEX_ATTRIB6_4_NV = 0x8676, + eGL_MAP2_VERTEX_ATTRIB7_4_NV = 0x8677, + eGL_MAP2_VERTEX_ATTRIB8_4_NV = 0x8678, + eGL_MAP2_VERTEX_ATTRIB9_4_NV = 0x8679, + eGL_MAP_ATTRIB_U_ORDER_NV = 0x86C3, + eGL_MAP_ATTRIB_V_ORDER_NV = 0x86C4, + eGL_MAP_COHERENT_BIT = 0x0080, + eGL_MAP_FLUSH_EXPLICIT_BIT = 0x0010, + eGL_MAP_INVALIDATE_BUFFER_BIT = 0x0008, + eGL_MAP_INVALIDATE_RANGE_BIT = 0x0004, + eGL_MAP_PERSISTENT_BIT = 0x0040, + eGL_MAP_READ_BIT = 0x0001, + eGL_MAP_TESSELLATION_NV = 0x86C2, + eGL_MAP_UNSYNCHRONIZED_BIT = 0x0020, + eGL_MAP_WRITE_BIT = 0x0002, + eGL_MATERIAL_SIDE_HINT_PGI = 0x1A22C, + eGL_MATRIX0_ARB = 0x88C0, + eGL_MATRIX0_NV = 0x8630, + eGL_MATRIX10_ARB = 0x88CA, + eGL_MATRIX11_ARB = 0x88CB, + eGL_MATRIX12_ARB = 0x88CC, + eGL_MATRIX13_ARB = 0x88CD, + eGL_MATRIX14_ARB = 0x88CE, + eGL_MATRIX15_ARB = 0x88CF, + eGL_MATRIX16_ARB = 0x88D0, + eGL_MATRIX17_ARB = 0x88D1, + eGL_MATRIX18_ARB = 0x88D2, + eGL_MATRIX19_ARB = 0x88D3, + eGL_MATRIX1_ARB = 0x88C1, + eGL_MATRIX1_NV = 0x8631, + eGL_MATRIX20_ARB = 0x88D4, + eGL_MATRIX21_ARB = 0x88D5, + eGL_MATRIX22_ARB = 0x88D6, + eGL_MATRIX23_ARB = 0x88D7, + eGL_MATRIX24_ARB = 0x88D8, + eGL_MATRIX25_ARB = 0x88D9, + eGL_MATRIX26_ARB = 0x88DA, + eGL_MATRIX27_ARB = 0x88DB, + eGL_MATRIX28_ARB = 0x88DC, + eGL_MATRIX29_ARB = 0x88DD, + eGL_MATRIX2_ARB = 0x88C2, + eGL_MATRIX2_NV = 0x8632, + eGL_MATRIX30_ARB = 0x88DE, + eGL_MATRIX31_ARB = 0x88DF, + eGL_MATRIX3_ARB = 0x88C3, + eGL_MATRIX3_NV = 0x8633, + eGL_MATRIX4_ARB = 0x88C4, + eGL_MATRIX4_NV = 0x8634, + eGL_MATRIX5_ARB = 0x88C5, + eGL_MATRIX5_NV = 0x8635, + eGL_MATRIX6_ARB = 0x88C6, + eGL_MATRIX6_NV = 0x8636, + eGL_MATRIX7_ARB = 0x88C7, + eGL_MATRIX7_NV = 0x8637, + eGL_MATRIX8_ARB = 0x88C8, + eGL_MATRIX9_ARB = 0x88C9, + eGL_MATRIX_EXT = 0x87C0, + eGL_MATRIX_INDEX_ARRAY_ARB = 0x8844, + eGL_MATRIX_INDEX_ARRAY_POINTER_ARB = 0x8849, + eGL_MATRIX_INDEX_ARRAY_SIZE_ARB = 0x8846, + eGL_MATRIX_INDEX_ARRAY_STRIDE_ARB = 0x8848, + eGL_MATRIX_INDEX_ARRAY_TYPE_ARB = 0x8847, + eGL_MATRIX_PALETTE_ARB = 0x8840, + eGL_MATRIX_STRIDE = 0x92FF, + eGL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI = 0x00200000, + eGL_MAT_AMBIENT_BIT_PGI = 0x00100000, + eGL_MAT_COLOR_INDEXES_BIT_PGI = 0x01000000, + eGL_MAT_DIFFUSE_BIT_PGI = 0x00400000, + eGL_MAT_EMISSION_BIT_PGI = 0x00800000, + eGL_MAT_SHININESS_BIT_PGI = 0x02000000, + eGL_MAT_SPECULAR_BIT_PGI = 0x04000000, + eGL_MAX = 0x8008, + eGL_MAX_3D_TEXTURE_SIZE = 0x8073, + eGL_MAX_3D_TEXTURE_SIZE_EXT = 0x8073, + eGL_MAX_4D_TEXTURE_SIZE_SGIS = 0x8138, + eGL_MAX_ACTIVE_LIGHTS_SGIX = 0x8405, + eGL_MAX_ARRAY_TEXTURE_LAYERS = 0x88FF, + eGL_MAX_ARRAY_TEXTURE_LAYERS_EXT = 0x88FF, + eGL_MAX_ASYNC_DRAW_PIXELS_SGIX = 0x8360, + eGL_MAX_ASYNC_HISTOGRAM_SGIX = 0x832D, + eGL_MAX_ASYNC_READ_PIXELS_SGIX = 0x8361, + eGL_MAX_ASYNC_TEX_IMAGE_SGIX = 0x835F, + eGL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS = 0x92DC, + eGL_MAX_ATOMIC_COUNTER_BUFFER_SIZE = 0x92D8, + eGL_MAX_BINDABLE_UNIFORM_SIZE_EXT = 0x8DED, + eGL_MAX_CLIPMAP_DEPTH_SGIX = 0x8177, + eGL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX = 0x8178, + eGL_MAX_CLIP_DISTANCES = 0x0D32, + eGL_MAX_COLOR_ATTACHMENTS = 0x8CDF, + eGL_MAX_COLOR_ATTACHMENTS_EXT = 0x8CDF, + eGL_MAX_COLOR_MATRIX_STACK_DEPTH = 0x80B3, + eGL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI = 0x80B3, + eGL_MAX_COLOR_TEXTURE_SAMPLES = 0x910E, + eGL_MAX_COMBINED_ATOMIC_COUNTERS = 0x92D7, + eGL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS = 0x92D1, + eGL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS = 0x8266, + eGL_MAX_COMBINED_DIMENSIONS = 0x8282, + eGL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x8A33, + eGL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 0x8A32, + eGL_MAX_COMBINED_IMAGE_UNIFORMS = 0x90CF, + eGL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS = 0x8F39, + eGL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT = 0x8F39, + eGL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES = 0x8F39, + eGL_MAX_COMBINED_SHADER_STORAGE_BLOCKS = 0x90DC, + eGL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 0x8E1E, + eGL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E1F, + eGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D, + eGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB = 0x8B4D, + eGL_MAX_COMBINED_UNIFORM_BLOCKS = 0x8A2E, + eGL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x8A31, + eGL_MAX_COMPUTE_ATOMIC_COUNTERS = 0x8265, + eGL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS = 0x8264, + eGL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB = 0x90EB, + eGL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB = 0x91BF, + eGL_MAX_COMPUTE_IMAGE_UNIFORMS = 0x91BD, + eGL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS = 0x90DB, + eGL_MAX_COMPUTE_SHARED_MEMORY_SIZE = 0x8262, + eGL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS = 0x91BC, + eGL_MAX_COMPUTE_UNIFORM_BLOCKS = 0x91BB, + eGL_MAX_COMPUTE_UNIFORM_COMPONENTS = 0x8263, + eGL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB = 0x9344, + eGL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB = 0x9345, + eGL_MAX_COMPUTE_WORK_GROUP_COUNT = 0x91BE, + eGL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS = 0x90EB, + eGL_MAX_COMPUTE_WORK_GROUP_SIZE = 0x91BF, + eGL_MAX_CONVOLUTION_HEIGHT = 0x801B, + eGL_MAX_CONVOLUTION_HEIGHT_EXT = 0x801B, + eGL_MAX_CONVOLUTION_WIDTH = 0x801A, + eGL_MAX_CONVOLUTION_WIDTH_EXT = 0x801A, + eGL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C, + eGL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB = 0x851C, + eGL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT = 0x851C, + eGL_MAX_DEBUG_GROUP_STACK_DEPTH = 0x826C, + eGL_MAX_DEBUG_LOGGED_MESSAGES = 0x9144, + eGL_MAX_DEBUG_LOGGED_MESSAGES_AMD = 0x9144, + eGL_MAX_DEBUG_LOGGED_MESSAGES_ARB = 0x9144, + eGL_MAX_DEBUG_MESSAGE_LENGTH = 0x9143, + eGL_MAX_DEBUG_MESSAGE_LENGTH_AMD = 0x9143, + eGL_MAX_DEBUG_MESSAGE_LENGTH_ARB = 0x9143, + eGL_MAX_DEEP_3D_TEXTURE_DEPTH_NV = 0x90D1, + eGL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV = 0x90D0, + eGL_MAX_DEFORMATION_ORDER_SGIX = 0x8197, + eGL_MAX_DEPTH = 0x8280, + eGL_MAX_DEPTH_TEXTURE_SAMPLES = 0x910F, + eGL_MAX_DRAW_BUFFERS = 0x8824, + eGL_MAX_DRAW_BUFFERS_ARB = 0x8824, + eGL_MAX_DRAW_BUFFERS_ATI = 0x8824, + eGL_MAX_DUAL_SOURCE_DRAW_BUFFERS = 0x88FC, + eGL_MAX_ELEMENTS_INDICES = 0x80E9, + eGL_MAX_ELEMENTS_INDICES_EXT = 0x80E9, + eGL_MAX_ELEMENTS_VERTICES = 0x80E8, + eGL_MAX_ELEMENTS_VERTICES_EXT = 0x80E8, + eGL_MAX_ELEMENT_INDEX = 0x8D6B, + eGL_MAX_EXT = 0x8008, + eGL_MAX_FOG_FUNC_POINTS_SGIS = 0x812C, + eGL_MAX_FRAGMENT_ATOMIC_COUNTERS = 0x92D6, + eGL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS = 0x92D0, + eGL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT = 0x8DE3, + eGL_MAX_FRAGMENT_IMAGE_UNIFORMS = 0x90CE, + eGL_MAX_FRAGMENT_INPUT_COMPONENTS = 0x9125, + eGL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 0x8E5C, + eGL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV = 0x8E5C, + eGL_MAX_FRAGMENT_LIGHTS_SGIX = 0x8404, + eGL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV = 0x8868, + eGL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS = 0x90DA, + eGL_MAX_FRAGMENT_UNIFORM_BLOCKS = 0x8A2D, + eGL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49, + eGL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB = 0x8B49, + eGL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD, + eGL_MAX_FRAMEBUFFER_HEIGHT = 0x9316, + eGL_MAX_FRAMEBUFFER_LAYERS = 0x9317, + eGL_MAX_FRAMEBUFFER_SAMPLES = 0x9318, + eGL_MAX_FRAMEBUFFER_WIDTH = 0x9315, + eGL_MAX_FRAMEZOOM_FACTOR_SGIX = 0x818D, + eGL_MAX_GENERAL_COMBINERS_NV = 0x854D, + eGL_MAX_GEOMETRY_ATOMIC_COUNTERS = 0x92D5, + eGL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 0x92CF, + eGL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT = 0x8DE4, + eGL_MAX_GEOMETRY_IMAGE_UNIFORMS = 0x90CD, + eGL_MAX_GEOMETRY_INPUT_COMPONENTS = 0x9123, + eGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 0x9124, + eGL_MAX_GEOMETRY_OUTPUT_VERTICES = 0x8DE0, + eGL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB = 0x8DE0, + eGL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT = 0x8DE0, + eGL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV = 0x8E5A, + eGL_MAX_GEOMETRY_SHADER_INVOCATIONS = 0x8E5A, + eGL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 0x90D7, + eGL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 0x8C29, + eGL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB = 0x8C29, + eGL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT = 0x8C29, + eGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 0x8DE1, + eGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB = 0x8DE1, + eGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT = 0x8DE1, + eGL_MAX_GEOMETRY_UNIFORM_BLOCKS = 0x8A2C, + eGL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 0x8DDF, + eGL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB = 0x8DDF, + eGL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT = 0x8DDF, + eGL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB = 0x8DDD, + eGL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT = 0x8DDD, + eGL_MAX_HEIGHT = 0x827F, + eGL_MAX_IMAGE_SAMPLES = 0x906D, + eGL_MAX_IMAGE_SAMPLES_EXT = 0x906D, + eGL_MAX_IMAGE_UNITS = 0x8F38, + eGL_MAX_IMAGE_UNITS_EXT = 0x8F38, + eGL_MAX_INTEGER_SAMPLES = 0x9110, + eGL_MAX_LABEL_LENGTH = 0x82E8, + eGL_MAX_LAYERS = 0x8281, + eGL_MAX_MAP_TESSELLATION_NV = 0x86D6, + eGL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB = 0x8841, + eGL_MAX_MULTISAMPLE_COVERAGE_MODES_NV = 0x8E11, + eGL_MAX_NAME_LENGTH = 0x92F6, + eGL_MAX_NUM_ACTIVE_VARIABLES = 0x92F7, + eGL_MAX_NUM_COMPATIBLE_SUBROUTINES = 0x92F8, + eGL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT = 0x87CA, + eGL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT = 0x87CD, + eGL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT = 0x87CE, + eGL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = 0x87CC, + eGL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT = 0x87CB, + eGL_MAX_PALETTE_MATRICES_ARB = 0x8842, + eGL_MAX_PATCH_VERTICES = 0x8E7D, + eGL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT = 0x8337, + eGL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI = 0x87F1, + eGL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB = 0x88B1, + eGL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB = 0x880B, + eGL_MAX_PROGRAM_ATTRIBS_ARB = 0x88AD, + eGL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV = 0x8908, + eGL_MAX_PROGRAM_CALL_DEPTH_NV = 0x88F5, + eGL_MAX_PROGRAM_ENV_PARAMETERS_ARB = 0x88B5, + eGL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV = 0x88F4, + eGL_MAX_PROGRAM_GENERIC_ATTRIBS_NV = 0x8DA5, + eGL_MAX_PROGRAM_GENERIC_RESULTS_NV = 0x8DA6, + eGL_MAX_PROGRAM_IF_DEPTH_NV = 0x88F6, + eGL_MAX_PROGRAM_INSTRUCTIONS_ARB = 0x88A1, + eGL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB = 0x88B4, + eGL_MAX_PROGRAM_LOOP_COUNT_NV = 0x88F8, + eGL_MAX_PROGRAM_LOOP_DEPTH_NV = 0x88F7, + eGL_MAX_PROGRAM_MATRICES_ARB = 0x862F, + eGL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB = 0x862E, + eGL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = 0x88B3, + eGL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = 0x880E, + eGL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB = 0x88AF, + eGL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB = 0x88A3, + eGL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB = 0x88AB, + eGL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB = 0x88A7, + eGL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = 0x8810, + eGL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = 0x880F, + eGL_MAX_PROGRAM_OUTPUT_VERTICES_NV = 0x8C27, + eGL_MAX_PROGRAM_PARAMETERS_ARB = 0x88A9, + eGL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV = 0x8DA0, + eGL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV = 0x8DA1, + eGL_MAX_PROGRAM_PATCH_ATTRIBS_NV = 0x86D8, + eGL_MAX_PROGRAM_RESULT_COMPONENTS_NV = 0x8909, + eGL_MAX_PROGRAM_SUBROUTINE_NUM_NV = 0x8F45, + eGL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV = 0x8F44, + eGL_MAX_PROGRAM_TEMPORARIES_ARB = 0x88A5, + eGL_MAX_PROGRAM_TEXEL_OFFSET = 0x8905, + eGL_MAX_PROGRAM_TEXEL_OFFSET_EXT = 0x8905, + eGL_MAX_PROGRAM_TEXEL_OFFSET_NV = 0x8905, + eGL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB = 0x8F9F, + eGL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET = 0x8E5F, + eGL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB = 0x8E5F, + eGL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV = 0x8E5F, + eGL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB = 0x880D, + eGL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB = 0x880C, + eGL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV = 0x8C28, + eGL_MAX_RATIONAL_EVAL_ORDER_NV = 0x86D7, + eGL_MAX_RECTANGLE_TEXTURE_SIZE = 0x84F8, + eGL_MAX_RECTANGLE_TEXTURE_SIZE_ARB = 0x84F8, + eGL_MAX_RECTANGLE_TEXTURE_SIZE_NV = 0x84F8, + eGL_MAX_RENDERBUFFER_SIZE = 0x84E8, + eGL_MAX_RENDERBUFFER_SIZE_EXT = 0x84E8, + eGL_MAX_SAMPLES = 0x8D57, + eGL_MAX_SAMPLES_EXT = 0x8D57, + eGL_MAX_SAMPLE_MASK_WORDS = 0x8E59, + eGL_MAX_SAMPLE_MASK_WORDS_NV = 0x8E59, + eGL_MAX_SERVER_WAIT_TIMEOUT = 0x9111, + eGL_MAX_SHADER_BUFFER_ADDRESS_NV = 0x8F35, + eGL_MAX_SHADER_STORAGE_BLOCK_SIZE = 0x90DE, + eGL_MAX_SHADER_STORAGE_BUFFER_BINDINGS = 0x90DD, + eGL_MAX_SHININESS_NV = 0x8504, + eGL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD = 0x9199, + eGL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB = 0x9199, + eGL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS = 0x919A, + eGL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB = 0x919A, + eGL_MAX_SPARSE_TEXTURE_SIZE_AMD = 0x9198, + eGL_MAX_SPARSE_TEXTURE_SIZE_ARB = 0x9198, + eGL_MAX_SPOT_EXPONENT_NV = 0x8505, + eGL_MAX_SUBROUTINES = 0x8DE7, + eGL_MAX_SUBROUTINE_UNIFORM_LOCATIONS = 0x8DE8, + eGL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 0x92D3, + eGL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 0x92CD, + eGL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 0x90CB, + eGL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 0x886C, + eGL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 0x8E83, + eGL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 0x90D8, + eGL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 0x8E81, + eGL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 0x8E85, + eGL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 0x8E89, + eGL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 0x8E7F, + eGL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 0x92D4, + eGL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 0x92CE, + eGL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 0x90CC, + eGL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 0x886D, + eGL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 0x8E86, + eGL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 0x90D9, + eGL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 0x8E82, + eGL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 0x8E8A, + eGL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E80, + eGL_MAX_TESS_GEN_LEVEL = 0x8E7E, + eGL_MAX_TESS_PATCH_COMPONENTS = 0x8E84, + eGL_MAX_TEXTURE_BUFFER_SIZE = 0x8C2B, + eGL_MAX_TEXTURE_BUFFER_SIZE_ARB = 0x8C2B, + eGL_MAX_TEXTURE_BUFFER_SIZE_EXT = 0x8C2B, + eGL_MAX_TEXTURE_COORDS = 0x8871, + eGL_MAX_TEXTURE_COORDS_ARB = 0x8871, + eGL_MAX_TEXTURE_COORDS_NV = 0x8871, + eGL_MAX_TEXTURE_IMAGE_UNITS = 0x8872, + eGL_MAX_TEXTURE_IMAGE_UNITS_ARB = 0x8872, + eGL_MAX_TEXTURE_IMAGE_UNITS_NV = 0x8872, + eGL_MAX_TEXTURE_LOD_BIAS = 0x84FD, + eGL_MAX_TEXTURE_LOD_BIAS_EXT = 0x84FD, + eGL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF, + eGL_MAX_TEXTURE_SIZE = 0x0D33, + eGL_MAX_TEXTURE_UNITS = 0x84E2, + eGL_MAX_TEXTURE_UNITS_ARB = 0x84E2, + eGL_MAX_TRACK_MATRICES_NV = 0x862F, + eGL_MAX_TRACK_MATRIX_STACK_DEPTH_NV = 0x862E, + eGL_MAX_TRANSFORM_FEEDBACK_BUFFERS = 0x8E70, + eGL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x8C8A, + eGL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT = 0x8C8A, + eGL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV = 0x8C8A, + eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B, + eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT = 0x8C8B, + eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV = 0x8C8B, + eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 0x8C80, + eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT = 0x8C80, + eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV = 0x8C80, + eGL_MAX_UNIFORM_BLOCK_SIZE = 0x8A30, + eGL_MAX_UNIFORM_BUFFER_BINDINGS = 0x8A2F, + eGL_MAX_UNIFORM_LOCATIONS = 0x826E, + eGL_MAX_VARYING_COMPONENTS = 0x8B4B, + eGL_MAX_VARYING_COMPONENTS_EXT = 0x8B4B, + eGL_MAX_VARYING_FLOATS = 0x8B4B, + eGL_MAX_VARYING_FLOATS_ARB = 0x8B4B, + eGL_MAX_VARYING_VECTORS = 0x8DFC, + eGL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV = 0x8520, + eGL_MAX_VERTEX_ATOMIC_COUNTERS = 0x92D2, + eGL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS = 0x92CC, + eGL_MAX_VERTEX_ATTRIBS = 0x8869, + eGL_MAX_VERTEX_ATTRIBS_ARB = 0x8869, + eGL_MAX_VERTEX_ATTRIB_BINDINGS = 0x82DA, + eGL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET = 0x82D9, + eGL_MAX_VERTEX_ATTRIB_STRIDE = 0x82E5, + eGL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT = 0x8DE2, + eGL_MAX_VERTEX_HINT_PGI = 0x1A22D, + eGL_MAX_VERTEX_IMAGE_UNIFORMS = 0x90CA, + eGL_MAX_VERTEX_OUTPUT_COMPONENTS = 0x9122, + eGL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT = 0x87C5, + eGL_MAX_VERTEX_SHADER_INVARIANTS_EXT = 0x87C7, + eGL_MAX_VERTEX_SHADER_LOCALS_EXT = 0x87C9, + eGL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = 0x87C8, + eGL_MAX_VERTEX_SHADER_STORAGE_BLOCKS = 0x90D6, + eGL_MAX_VERTEX_SHADER_VARIANTS_EXT = 0x87C6, + eGL_MAX_VERTEX_STREAMS = 0x8E71, + eGL_MAX_VERTEX_STREAMS_ATI = 0x876B, + eGL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C, + eGL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB = 0x8B4C, + eGL_MAX_VERTEX_UNIFORM_BLOCKS = 0x8A2B, + eGL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A, + eGL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB = 0x8B4A, + eGL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB, + eGL_MAX_VERTEX_UNITS_ARB = 0x86A4, + eGL_MAX_VERTEX_VARYING_COMPONENTS_ARB = 0x8DDE, + eGL_MAX_VERTEX_VARYING_COMPONENTS_EXT = 0x8DDE, + eGL_MAX_VIEWPORTS = 0x825B, + eGL_MAX_VIEWPORT_DIMS = 0x0D3A, + eGL_MAX_WIDTH = 0x827E, + eGL_MEDIUM_FLOAT = 0x8DF1, + eGL_MEDIUM_INT = 0x8DF4, + eGL_MIN = 0x8007, + eGL_MINMAX = 0x802E, + eGL_MINMAX_EXT = 0x802E, + eGL_MINMAX_FORMAT = 0x802F, + eGL_MINMAX_FORMAT_EXT = 0x802F, + eGL_MINMAX_SINK = 0x8030, + eGL_MINMAX_SINK_EXT = 0x8030, + eGL_MINOR_VERSION = 0x821C, + eGL_MINUS_CLAMPED_NV = 0x92B3, + eGL_MINUS_NV = 0x929F, + eGL_MIN_EXT = 0x8007, + eGL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 0x8E5B, + eGL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV = 0x8E5B, + eGL_MIN_LOD_WARNING_AMD = 0x919C, + eGL_MIN_MAP_BUFFER_ALIGNMENT = 0x90BC, + eGL_MIN_PROGRAM_TEXEL_OFFSET = 0x8904, + eGL_MIN_PROGRAM_TEXEL_OFFSET_EXT = 0x8904, + eGL_MIN_PROGRAM_TEXEL_OFFSET_NV = 0x8904, + eGL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET = 0x8E5E, + eGL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB = 0x8E5E, + eGL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV = 0x8E5E, + eGL_MIN_SAMPLE_SHADING_VALUE = 0x8C37, + eGL_MIN_SAMPLE_SHADING_VALUE_ARB = 0x8C37, + eGL_MIN_SPARSE_LEVEL_AMD = 0x919B, + eGL_MIN_SPARSE_LEVEL_ARB = 0x919B, + eGL_MIPMAP = 0x8293, + eGL_MIRRORED_REPEAT = 0x8370, + eGL_MIRRORED_REPEAT_ARB = 0x8370, + eGL_MIRRORED_REPEAT_IBM = 0x8370, + eGL_MIRROR_CLAMP_ATI = 0x8742, + eGL_MIRROR_CLAMP_EXT = 0x8742, + eGL_MIRROR_CLAMP_TO_BORDER_EXT = 0x8912, + eGL_MIRROR_CLAMP_TO_EDGE = 0x8743, + eGL_MIRROR_CLAMP_TO_EDGE_ATI = 0x8743, + eGL_MIRROR_CLAMP_TO_EDGE_EXT = 0x8743, + eGL_MITER_REVERT_NV = 0x90A7, + eGL_MITER_TRUNCATE_NV = 0x90A8, + eGL_MODELVIEW0_ARB = 0x1700, + eGL_MODELVIEW0_EXT = 0x1700, + eGL_MODELVIEW0_MATRIX_EXT = 0x0BA6, + eGL_MODELVIEW0_STACK_DEPTH_EXT = 0x0BA3, + eGL_MODELVIEW10_ARB = 0x872A, + eGL_MODELVIEW11_ARB = 0x872B, + eGL_MODELVIEW12_ARB = 0x872C, + eGL_MODELVIEW13_ARB = 0x872D, + eGL_MODELVIEW14_ARB = 0x872E, + eGL_MODELVIEW15_ARB = 0x872F, + eGL_MODELVIEW16_ARB = 0x8730, + eGL_MODELVIEW17_ARB = 0x8731, + eGL_MODELVIEW18_ARB = 0x8732, + eGL_MODELVIEW19_ARB = 0x8733, + eGL_MODELVIEW1_ARB = 0x850A, + eGL_MODELVIEW1_EXT = 0x850A, + eGL_MODELVIEW1_MATRIX_EXT = 0x8506, + eGL_MODELVIEW1_STACK_DEPTH_EXT = 0x8502, + eGL_MODELVIEW20_ARB = 0x8734, + eGL_MODELVIEW21_ARB = 0x8735, + eGL_MODELVIEW22_ARB = 0x8736, + eGL_MODELVIEW23_ARB = 0x8737, + eGL_MODELVIEW24_ARB = 0x8738, + eGL_MODELVIEW25_ARB = 0x8739, + eGL_MODELVIEW26_ARB = 0x873A, + eGL_MODELVIEW27_ARB = 0x873B, + eGL_MODELVIEW28_ARB = 0x873C, + eGL_MODELVIEW29_ARB = 0x873D, + eGL_MODELVIEW2_ARB = 0x8722, + eGL_MODELVIEW30_ARB = 0x873E, + eGL_MODELVIEW31_ARB = 0x873F, + eGL_MODELVIEW3_ARB = 0x8723, + eGL_MODELVIEW4_ARB = 0x8724, + eGL_MODELVIEW5_ARB = 0x8725, + eGL_MODELVIEW6_ARB = 0x8726, + eGL_MODELVIEW7_ARB = 0x8727, + eGL_MODELVIEW8_ARB = 0x8728, + eGL_MODELVIEW9_ARB = 0x8729, + eGL_MODELVIEW_PROJECTION_NV = 0x8629, + eGL_MODULATE_ADD_ATI = 0x8744, + eGL_MODULATE_SIGNED_ADD_ATI = 0x8745, + eGL_MODULATE_SUBTRACT_ATI = 0x8746, + eGL_MOVE_TO_CONTINUES_NV = 0x90B6, + eGL_MOVE_TO_RESETS_NV = 0x90B5, + eGL_MOV_ATI = 0x8961, + eGL_MULTIPLY_NV = 0x9294, + eGL_MULTISAMPLE = 0x809D, + eGL_MULTISAMPLE_3DFX = 0x86B2, + eGL_MULTISAMPLE_ARB = 0x809D, + eGL_MULTISAMPLE_BIT = 0x20000000, + eGL_MULTISAMPLE_BIT_3DFX = 0x20000000, + eGL_MULTISAMPLE_BIT_ARB = 0x20000000, + eGL_MULTISAMPLE_BIT_EXT = 0x20000000, + eGL_MULTISAMPLE_COVERAGE_MODES_NV = 0x8E12, + eGL_MULTISAMPLE_EXT = 0x809D, + eGL_MULTISAMPLE_FILTER_HINT_NV = 0x8534, + eGL_MULTISAMPLE_SGIS = 0x809D, + eGL_MUL_ATI = 0x8964, + eGL_MVP_MATRIX_EXT = 0x87E3, + eGL_NAMED_STRING_LENGTH_ARB = 0x8DE9, + eGL_NAMED_STRING_TYPE_ARB = 0x8DEA, + eGL_NAME_LENGTH = 0x92F9, + eGL_NAND = 0x150E, + eGL_NATIVE_GRAPHICS_BEGIN_HINT_PGI = 0x1A203, + eGL_NATIVE_GRAPHICS_END_HINT_PGI = 0x1A204, + eGL_NATIVE_GRAPHICS_HANDLE_PGI = 0x1A202, + eGL_NEAREST = 0x2600, + eGL_NEAREST_CLIPMAP_LINEAR_SGIX = 0x844E, + eGL_NEAREST_CLIPMAP_NEAREST_SGIX = 0x844D, + eGL_NEAREST_MIPMAP_LINEAR = 0x2702, + eGL_NEAREST_MIPMAP_NEAREST = 0x2700, + eGL_NEGATE_BIT_ATI = 0x00000004, + eGL_NEGATIVE_ONE_EXT = 0x87DF, + eGL_NEGATIVE_W_EXT = 0x87DC, + eGL_NEGATIVE_X_EXT = 0x87D9, + eGL_NEGATIVE_Y_EXT = 0x87DA, + eGL_NEGATIVE_Z_EXT = 0x87DB, + eGL_NEVER = 0x0200, + eGL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV = 0x9025, + eGL_NICEST = 0x1102, + eGL_NOOP = 0x1505, + eGL_NOR = 0x1508, + eGL_NORMALIZED_RANGE_EXT = 0x87E0, + eGL_NORMAL_ARRAY_ADDRESS_NV = 0x8F22, + eGL_NORMAL_ARRAY_BUFFER_BINDING = 0x8897, + eGL_NORMAL_ARRAY_BUFFER_BINDING_ARB = 0x8897, + eGL_NORMAL_ARRAY_COUNT_EXT = 0x8080, + eGL_NORMAL_ARRAY_EXT = 0x8075, + eGL_NORMAL_ARRAY_LENGTH_NV = 0x8F2C, + eGL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL = 0x83F6, + eGL_NORMAL_ARRAY_POINTER_EXT = 0x808F, + eGL_NORMAL_ARRAY_STRIDE_EXT = 0x807F, + eGL_NORMAL_ARRAY_TYPE_EXT = 0x807E, + eGL_NORMAL_BIT_PGI = 0x08000000, + eGL_NORMAL_MAP = 0x8511, + eGL_NORMAL_MAP_ARB = 0x8511, + eGL_NORMAL_MAP_EXT = 0x8511, + eGL_NORMAL_MAP_NV = 0x8511, + eGL_NOTEQUAL = 0x0205, + eGL_NO_RESET_NOTIFICATION_ARB = 0x8261, + eGL_NUM_ACTIVE_VARIABLES = 0x9304, + eGL_NUM_COMPATIBLE_SUBROUTINES = 0x8E4A, + eGL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2, + eGL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB = 0x86A2, + eGL_NUM_EXTENSIONS = 0x821D, + eGL_NUM_FILL_STREAMS_NV = 0x8E29, + eGL_NUM_FRAGMENT_CONSTANTS_ATI = 0x896F, + eGL_NUM_FRAGMENT_REGISTERS_ATI = 0x896E, + eGL_NUM_GENERAL_COMBINERS_NV = 0x854E, + eGL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI = 0x8973, + eGL_NUM_INSTRUCTIONS_PER_PASS_ATI = 0x8971, + eGL_NUM_INSTRUCTIONS_TOTAL_ATI = 0x8972, + eGL_NUM_LOOPBACK_COMPONENTS_ATI = 0x8974, + eGL_NUM_PASSES_ATI = 0x8970, + eGL_NUM_PROGRAM_BINARY_FORMATS = 0x87FE, + eGL_NUM_SAMPLE_COUNTS = 0x9380, + eGL_NUM_SHADER_BINARY_FORMATS = 0x8DF9, + eGL_NUM_SHADING_LANGUAGE_VERSIONS = 0x82E9, + eGL_NUM_VIDEO_CAPTURE_STREAMS_NV = 0x9024, + eGL_NUM_VIRTUAL_PAGE_SIZES_ARB = 0x91A8, + eGL_OBJECT_ACTIVE_ATTRIBUTES_ARB = 0x8B89, + eGL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB = 0x8B8A, + eGL_OBJECT_ACTIVE_UNIFORMS_ARB = 0x8B86, + eGL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB = 0x8B87, + eGL_OBJECT_ATTACHED_OBJECTS_ARB = 0x8B85, + eGL_OBJECT_BUFFER_SIZE_ATI = 0x8764, + eGL_OBJECT_BUFFER_USAGE_ATI = 0x8765, + eGL_OBJECT_COMPILE_STATUS_ARB = 0x8B81, + eGL_OBJECT_DELETE_STATUS_ARB = 0x8B80, + eGL_OBJECT_DISTANCE_TO_LINE_SGIS = 0x81F3, + eGL_OBJECT_DISTANCE_TO_POINT_SGIS = 0x81F1, + eGL_OBJECT_INFO_LOG_LENGTH_ARB = 0x8B84, + eGL_OBJECT_LINE_SGIS = 0x81F7, + eGL_OBJECT_LINK_STATUS_ARB = 0x8B82, + eGL_OBJECT_POINT_SGIS = 0x81F5, + eGL_OBJECT_SHADER_SOURCE_LENGTH_ARB = 0x8B88, + eGL_OBJECT_SUBTYPE_ARB = 0x8B4F, + eGL_OBJECT_TYPE = 0x9112, + eGL_OBJECT_TYPE_ARB = 0x8B4E, + eGL_OBJECT_VALIDATE_STATUS_ARB = 0x8B83, + eGL_OCCLUSION_QUERY_EVENT_MASK_AMD = 0x874F, + eGL_OCCLUSION_TEST_HP = 0x8165, + eGL_OCCLUSION_TEST_RESULT_HP = 0x8166, + eGL_OFFSET = 0x92FC, + eGL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV = 0x8856, + eGL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV = 0x8857, + eGL_OFFSET_HILO_TEXTURE_2D_NV = 0x8854, + eGL_OFFSET_HILO_TEXTURE_RECTANGLE_NV = 0x8855, + eGL_OFFSET_PROJECTIVE_TEXTURE_2D_NV = 0x8850, + eGL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV = 0x8851, + eGL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV = 0x8852, + eGL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV = 0x8853, + eGL_OFFSET_TEXTURE_2D_BIAS_NV = 0x86E3, + eGL_OFFSET_TEXTURE_2D_MATRIX_NV = 0x86E1, + eGL_OFFSET_TEXTURE_2D_NV = 0x86E8, + eGL_OFFSET_TEXTURE_2D_SCALE_NV = 0x86E2, + eGL_OFFSET_TEXTURE_BIAS_NV = 0x86E3, + eGL_OFFSET_TEXTURE_MATRIX_NV = 0x86E1, + eGL_OFFSET_TEXTURE_RECTANGLE_NV = 0x864C, + eGL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV = 0x864D, + eGL_OFFSET_TEXTURE_SCALE_NV = 0x86E2, + eGL_ONE_EXT = 0x87DE, + eGL_ONE_MINUS_CONSTANT_ALPHA = 0x8004, + eGL_ONE_MINUS_CONSTANT_ALPHA_EXT = 0x8004, + eGL_ONE_MINUS_CONSTANT_COLOR = 0x8002, + eGL_ONE_MINUS_CONSTANT_COLOR_EXT = 0x8002, + eGL_ONE_MINUS_DST_ALPHA = 0x0305, + eGL_ONE_MINUS_DST_COLOR = 0x0307, + eGL_ONE_MINUS_SRC1_ALPHA = 0x88FB, + eGL_ONE_MINUS_SRC1_COLOR = 0x88FA, + eGL_ONE_MINUS_SRC_ALPHA = 0x0303, + eGL_ONE_MINUS_SRC_COLOR = 0x0301, + eGL_OPERAND0_ALPHA = 0x8598, + eGL_OPERAND0_ALPHA_ARB = 0x8598, + eGL_OPERAND0_ALPHA_EXT = 0x8598, + eGL_OPERAND0_RGB = 0x8590, + eGL_OPERAND0_RGB_ARB = 0x8590, + eGL_OPERAND0_RGB_EXT = 0x8590, + eGL_OPERAND1_ALPHA = 0x8599, + eGL_OPERAND1_ALPHA_ARB = 0x8599, + eGL_OPERAND1_ALPHA_EXT = 0x8599, + eGL_OPERAND1_RGB = 0x8591, + eGL_OPERAND1_RGB_ARB = 0x8591, + eGL_OPERAND1_RGB_EXT = 0x8591, + eGL_OPERAND2_ALPHA = 0x859A, + eGL_OPERAND2_ALPHA_ARB = 0x859A, + eGL_OPERAND2_ALPHA_EXT = 0x859A, + eGL_OPERAND2_RGB = 0x8592, + eGL_OPERAND2_RGB_ARB = 0x8592, + eGL_OPERAND2_RGB_EXT = 0x8592, + eGL_OPERAND3_ALPHA_NV = 0x859B, + eGL_OPERAND3_RGB_NV = 0x8593, + eGL_OP_ADD_EXT = 0x8787, + eGL_OP_CLAMP_EXT = 0x878E, + eGL_OP_CROSS_PRODUCT_EXT = 0x8797, + eGL_OP_DOT3_EXT = 0x8784, + eGL_OP_DOT4_EXT = 0x8785, + eGL_OP_EXP_BASE_2_EXT = 0x8791, + eGL_OP_FLOOR_EXT = 0x878F, + eGL_OP_FRAC_EXT = 0x8789, + eGL_OP_INDEX_EXT = 0x8782, + eGL_OP_LOG_BASE_2_EXT = 0x8792, + eGL_OP_MADD_EXT = 0x8788, + eGL_OP_MAX_EXT = 0x878A, + eGL_OP_MIN_EXT = 0x878B, + eGL_OP_MOV_EXT = 0x8799, + eGL_OP_MULTIPLY_MATRIX_EXT = 0x8798, + eGL_OP_MUL_EXT = 0x8786, + eGL_OP_NEGATE_EXT = 0x8783, + eGL_OP_POWER_EXT = 0x8793, + eGL_OP_RECIP_EXT = 0x8794, + eGL_OP_RECIP_SQRT_EXT = 0x8795, + eGL_OP_ROUND_EXT = 0x8790, + eGL_OP_SET_GE_EXT = 0x878C, + eGL_OP_SET_LT_EXT = 0x878D, + eGL_OP_SUB_EXT = 0x8796, + eGL_OR = 0x1507, + eGL_OR_INVERTED = 0x150D, + eGL_OR_REVERSE = 0x150B, + eGL_OUTPUT_COLOR0_EXT = 0x879B, + eGL_OUTPUT_COLOR1_EXT = 0x879C, + eGL_OUTPUT_FOG_EXT = 0x87BD, + eGL_OUTPUT_TEXTURE_COORD0_EXT = 0x879D, + eGL_OUTPUT_TEXTURE_COORD10_EXT = 0x87A7, + eGL_OUTPUT_TEXTURE_COORD11_EXT = 0x87A8, + eGL_OUTPUT_TEXTURE_COORD12_EXT = 0x87A9, + eGL_OUTPUT_TEXTURE_COORD13_EXT = 0x87AA, + eGL_OUTPUT_TEXTURE_COORD14_EXT = 0x87AB, + eGL_OUTPUT_TEXTURE_COORD15_EXT = 0x87AC, + eGL_OUTPUT_TEXTURE_COORD16_EXT = 0x87AD, + eGL_OUTPUT_TEXTURE_COORD17_EXT = 0x87AE, + eGL_OUTPUT_TEXTURE_COORD18_EXT = 0x87AF, + eGL_OUTPUT_TEXTURE_COORD19_EXT = 0x87B0, + eGL_OUTPUT_TEXTURE_COORD1_EXT = 0x879E, + eGL_OUTPUT_TEXTURE_COORD20_EXT = 0x87B1, + eGL_OUTPUT_TEXTURE_COORD21_EXT = 0x87B2, + eGL_OUTPUT_TEXTURE_COORD22_EXT = 0x87B3, + eGL_OUTPUT_TEXTURE_COORD23_EXT = 0x87B4, + eGL_OUTPUT_TEXTURE_COORD24_EXT = 0x87B5, + eGL_OUTPUT_TEXTURE_COORD25_EXT = 0x87B6, + eGL_OUTPUT_TEXTURE_COORD26_EXT = 0x87B7, + eGL_OUTPUT_TEXTURE_COORD27_EXT = 0x87B8, + eGL_OUTPUT_TEXTURE_COORD28_EXT = 0x87B9, + eGL_OUTPUT_TEXTURE_COORD29_EXT = 0x87BA, + eGL_OUTPUT_TEXTURE_COORD2_EXT = 0x879F, + eGL_OUTPUT_TEXTURE_COORD30_EXT = 0x87BB, + eGL_OUTPUT_TEXTURE_COORD31_EXT = 0x87BC, + eGL_OUTPUT_TEXTURE_COORD3_EXT = 0x87A0, + eGL_OUTPUT_TEXTURE_COORD4_EXT = 0x87A1, + eGL_OUTPUT_TEXTURE_COORD5_EXT = 0x87A2, + eGL_OUTPUT_TEXTURE_COORD6_EXT = 0x87A3, + eGL_OUTPUT_TEXTURE_COORD7_EXT = 0x87A4, + eGL_OUTPUT_TEXTURE_COORD8_EXT = 0x87A5, + eGL_OUTPUT_TEXTURE_COORD9_EXT = 0x87A6, + eGL_OUTPUT_VERTEX_EXT = 0x879A, + eGL_OUT_OF_MEMORY = 0x0505, + eGL_OVERLAY_NV = 0x9296, + eGL_PACK_ALIGNMENT = 0x0D05, + eGL_PACK_CMYK_HINT_EXT = 0x800E, + eGL_PACK_COMPRESSED_BLOCK_DEPTH = 0x912D, + eGL_PACK_COMPRESSED_BLOCK_HEIGHT = 0x912C, + eGL_PACK_COMPRESSED_BLOCK_SIZE = 0x912E, + eGL_PACK_COMPRESSED_BLOCK_WIDTH = 0x912B, + eGL_PACK_IMAGE_DEPTH_SGIS = 0x8131, + eGL_PACK_IMAGE_HEIGHT = 0x806C, + eGL_PACK_IMAGE_HEIGHT_EXT = 0x806C, + eGL_PACK_INVERT_MESA = 0x8758, + eGL_PACK_LSB_FIRST = 0x0D01, + eGL_PACK_RESAMPLE_OML = 0x8984, + eGL_PACK_RESAMPLE_SGIX = 0x842C, + eGL_PACK_ROW_BYTES_APPLE = 0x8A15, + eGL_PACK_ROW_LENGTH = 0x0D02, + eGL_PACK_SKIP_IMAGES = 0x806B, + eGL_PACK_SKIP_IMAGES_EXT = 0x806B, + eGL_PACK_SKIP_PIXELS = 0x0D04, + eGL_PACK_SKIP_ROWS = 0x0D03, + eGL_PACK_SKIP_VOLUMES_SGIS = 0x8130, + eGL_PACK_SUBSAMPLE_RATE_SGIX = 0x85A0, + eGL_PACK_SWAP_BYTES = 0x0D00, + eGL_PALETTE4_R5_G6_B5_OES = 0x8B92, + eGL_PALETTE4_RGB5_A1_OES = 0x8B94, + eGL_PALETTE4_RGB8_OES = 0x8B90, + eGL_PALETTE4_RGBA4_OES = 0x8B93, + eGL_PALETTE4_RGBA8_OES = 0x8B91, + eGL_PALETTE8_R5_G6_B5_OES = 0x8B97, + eGL_PALETTE8_RGB5_A1_OES = 0x8B99, + eGL_PALETTE8_RGB8_OES = 0x8B95, + eGL_PALETTE8_RGBA4_OES = 0x8B98, + eGL_PALETTE8_RGBA8_OES = 0x8B96, + eGL_PARALLEL_ARRAYS_INTEL = 0x83F4, + eGL_PARAMETER_BUFFER_ARB = 0x80EE, + eGL_PARAMETER_BUFFER_BINDING_ARB = 0x80EF, + eGL_PARTIAL_SUCCESS_NV = 0x902E, + eGL_PASS_THROUGH_NV = 0x86E6, + eGL_PATCHES = 0x000E, + eGL_PATCH_DEFAULT_INNER_LEVEL = 0x8E73, + eGL_PATCH_DEFAULT_OUTER_LEVEL = 0x8E74, + eGL_PATCH_VERTICES = 0x8E72, + eGL_PATH_CLIENT_LENGTH_NV = 0x907F, + eGL_PATH_COMMAND_COUNT_NV = 0x909D, + eGL_PATH_COMPUTED_LENGTH_NV = 0x90A0, + eGL_PATH_COORD_COUNT_NV = 0x909E, + eGL_PATH_COVER_DEPTH_FUNC_NV = 0x90BF, + eGL_PATH_DASH_ARRAY_COUNT_NV = 0x909F, + eGL_PATH_DASH_CAPS_NV = 0x907B, + eGL_PATH_DASH_OFFSET_NV = 0x907E, + eGL_PATH_DASH_OFFSET_RESET_NV = 0x90B4, + eGL_PATH_END_CAPS_NV = 0x9076, + eGL_PATH_ERROR_POSITION_NV = 0x90AB, + eGL_PATH_FILL_BOUNDING_BOX_NV = 0x90A1, + eGL_PATH_FILL_COVER_MODE_NV = 0x9082, + eGL_PATH_FILL_MASK_NV = 0x9081, + eGL_PATH_FILL_MODE_NV = 0x9080, + eGL_PATH_FOG_GEN_MODE_NV = 0x90AC, + eGL_PATH_FORMAT_PS_NV = 0x9071, + eGL_PATH_FORMAT_SVG_NV = 0x9070, + eGL_PATH_GEN_COEFF_NV = 0x90B1, + eGL_PATH_GEN_COLOR_FORMAT_NV = 0x90B2, + eGL_PATH_GEN_COMPONENTS_NV = 0x90B3, + eGL_PATH_GEN_MODE_NV = 0x90B0, + eGL_PATH_INITIAL_DASH_CAP_NV = 0x907C, + eGL_PATH_INITIAL_END_CAP_NV = 0x9077, + eGL_PATH_JOIN_STYLE_NV = 0x9079, + eGL_PATH_MITER_LIMIT_NV = 0x907A, + eGL_PATH_OBJECT_BOUNDING_BOX_NV = 0x908A, + eGL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV = 0x90BD, + eGL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV = 0x90BE, + eGL_PATH_STENCIL_FUNC_NV = 0x90B7, + eGL_PATH_STENCIL_REF_NV = 0x90B8, + eGL_PATH_STENCIL_VALUE_MASK_NV = 0x90B9, + eGL_PATH_STROKE_BOUNDING_BOX_NV = 0x90A2, + eGL_PATH_STROKE_COVER_MODE_NV = 0x9083, + eGL_PATH_STROKE_MASK_NV = 0x9084, + eGL_PATH_STROKE_WIDTH_NV = 0x9075, + eGL_PATH_TERMINAL_DASH_CAP_NV = 0x907D, + eGL_PATH_TERMINAL_END_CAP_NV = 0x9078, + eGL_PERCENTAGE_AMD = 0x8BC3, + eGL_PERFMON_RESULT_AMD = 0x8BC6, + eGL_PERFMON_RESULT_AVAILABLE_AMD = 0x8BC4, + eGL_PERFMON_RESULT_SIZE_AMD = 0x8BC5, + eGL_PERFORMANCE_MONITOR_AMD = 0x9152, + eGL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL = 0x94FC, + eGL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL = 0x94FB, + eGL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL = 0x94FA, + eGL_PERFQUERY_COUNTER_DATA_UINT32_INTEL = 0x94F8, + eGL_PERFQUERY_COUNTER_DATA_UINT64_INTEL = 0x94F9, + eGL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL = 0x94FF, + eGL_PERFQUERY_COUNTER_DURATION_NORM_INTEL = 0x94F1, + eGL_PERFQUERY_COUNTER_DURATION_RAW_INTEL = 0x94F2, + eGL_PERFQUERY_COUNTER_EVENT_INTEL = 0x94F0, + eGL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL = 0x94FE, + eGL_PERFQUERY_COUNTER_RAW_INTEL = 0x94F4, + eGL_PERFQUERY_COUNTER_THROUGHPUT_INTEL = 0x94F3, + eGL_PERFQUERY_COUNTER_TIMESTAMP_INTEL = 0x94F5, + eGL_PERFQUERY_DONOT_FLUSH_INTEL = 0x83F9, + eGL_PERFQUERY_FLUSH_INTEL = 0x83FA, + eGL_PERFQUERY_GLOBAL_CONTEXT_INTEL = 0x00000001, + eGL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL = 0x9500, + eGL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL = 0x94FD, + eGL_PERFQUERY_SINGLE_CONTEXT_INTEL = 0x00000000, + eGL_PERFQUERY_WAIT_INTEL = 0x83FB, + eGL_PERTURB_EXT = 0x85AE, + eGL_PER_STAGE_CONSTANTS_NV = 0x8535, + eGL_PHONG_HINT_WIN = 0x80EB, + eGL_PHONG_WIN = 0x80EA, + eGL_PINLIGHT_NV = 0x92A8, + eGL_PIXEL_BUFFER_BARRIER_BIT = 0x00000080, + eGL_PIXEL_BUFFER_BARRIER_BIT_EXT = 0x00000080, + eGL_PIXEL_COUNTER_BITS_NV = 0x8864, + eGL_PIXEL_COUNT_AVAILABLE_NV = 0x8867, + eGL_PIXEL_COUNT_NV = 0x8866, + eGL_PIXEL_CUBIC_WEIGHT_EXT = 0x8333, + eGL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS = 0x8355, + eGL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS = 0x8354, + eGL_PIXEL_GROUP_COLOR_SGIS = 0x8356, + eGL_PIXEL_MAG_FILTER_EXT = 0x8331, + eGL_PIXEL_MIN_FILTER_EXT = 0x8332, + eGL_PIXEL_PACK_BUFFER = 0x88EB, + eGL_PIXEL_PACK_BUFFER_ARB = 0x88EB, + eGL_PIXEL_PACK_BUFFER_BINDING = 0x88ED, + eGL_PIXEL_PACK_BUFFER_BINDING_ARB = 0x88ED, + eGL_PIXEL_PACK_BUFFER_BINDING_EXT = 0x88ED, + eGL_PIXEL_PACK_BUFFER_EXT = 0x88EB, + eGL_PIXEL_SUBSAMPLE_2424_SGIX = 0x85A3, + eGL_PIXEL_SUBSAMPLE_4242_SGIX = 0x85A4, + eGL_PIXEL_SUBSAMPLE_4444_SGIX = 0x85A2, + eGL_PIXEL_TEXTURE_SGIS = 0x8353, + eGL_PIXEL_TEX_GEN_MODE_SGIX = 0x832B, + eGL_PIXEL_TEX_GEN_SGIX = 0x8139, + eGL_PIXEL_TILE_BEST_ALIGNMENT_SGIX = 0x813E, + eGL_PIXEL_TILE_CACHE_INCREMENT_SGIX = 0x813F, + eGL_PIXEL_TILE_CACHE_SIZE_SGIX = 0x8145, + eGL_PIXEL_TILE_GRID_DEPTH_SGIX = 0x8144, + eGL_PIXEL_TILE_GRID_HEIGHT_SGIX = 0x8143, + eGL_PIXEL_TILE_GRID_WIDTH_SGIX = 0x8142, + eGL_PIXEL_TILE_HEIGHT_SGIX = 0x8141, + eGL_PIXEL_TILE_WIDTH_SGIX = 0x8140, + eGL_PIXEL_TRANSFORM_2D_EXT = 0x8330, + eGL_PIXEL_TRANSFORM_2D_MATRIX_EXT = 0x8338, + eGL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT = 0x8336, + eGL_PIXEL_UNPACK_BUFFER = 0x88EC, + eGL_PIXEL_UNPACK_BUFFER_ARB = 0x88EC, + eGL_PIXEL_UNPACK_BUFFER_BINDING = 0x88EF, + eGL_PIXEL_UNPACK_BUFFER_BINDING_ARB = 0x88EF, + eGL_PIXEL_UNPACK_BUFFER_BINDING_EXT = 0x88EF, + eGL_PIXEL_UNPACK_BUFFER_EXT = 0x88EC, + eGL_PLUS_CLAMPED_ALPHA_NV = 0x92B2, + eGL_PLUS_CLAMPED_NV = 0x92B1, + eGL_PLUS_DARKER_NV = 0x9292, + eGL_PLUS_NV = 0x9291, + eGL_PN_TRIANGLES_ATI = 0x87F0, + eGL_PN_TRIANGLES_NORMAL_MODE_ATI = 0x87F3, + eGL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI = 0x87F7, + eGL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI = 0x87F8, + eGL_PN_TRIANGLES_POINT_MODE_ATI = 0x87F2, + eGL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI = 0x87F6, + eGL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI = 0x87F5, + eGL_PN_TRIANGLES_TESSELATION_LEVEL_ATI = 0x87F4, + eGL_POINT = 0x1B00, + eGL_POINTS = 0x0000, + eGL_POINT_DISTANCE_ATTENUATION = 0x8129, + eGL_POINT_DISTANCE_ATTENUATION_ARB = 0x8129, + eGL_POINT_FADE_THRESHOLD_SIZE = 0x8128, + eGL_POINT_FADE_THRESHOLD_SIZE_ARB = 0x8128, + eGL_POINT_FADE_THRESHOLD_SIZE_EXT = 0x8128, + eGL_POINT_FADE_THRESHOLD_SIZE_SGIS = 0x8128, + eGL_POINT_SIZE = 0x0B11, + eGL_POINT_SIZE_GRANULARITY = 0x0B13, + eGL_POINT_SIZE_MAX = 0x8127, + eGL_POINT_SIZE_MAX_ARB = 0x8127, + eGL_POINT_SIZE_MAX_EXT = 0x8127, + eGL_POINT_SIZE_MAX_SGIS = 0x8127, + eGL_POINT_SIZE_MIN = 0x8126, + eGL_POINT_SIZE_MIN_ARB = 0x8126, + eGL_POINT_SIZE_MIN_EXT = 0x8126, + eGL_POINT_SIZE_MIN_SGIS = 0x8126, + eGL_POINT_SIZE_RANGE = 0x0B12, + eGL_POINT_SPRITE = 0x8861, + eGL_POINT_SPRITE_ARB = 0x8861, + eGL_POINT_SPRITE_COORD_ORIGIN = 0x8CA0, + eGL_POINT_SPRITE_NV = 0x8861, + eGL_POINT_SPRITE_R_MODE_NV = 0x8863, + eGL_POLYGON_MODE = 0x0B40, + eGL_POLYGON_OFFSET_BIAS_EXT = 0x8039, + eGL_POLYGON_OFFSET_EXT = 0x8037, + eGL_POLYGON_OFFSET_FACTOR = 0x8038, + eGL_POLYGON_OFFSET_FACTOR_EXT = 0x8038, + eGL_POLYGON_OFFSET_FILL = 0x8037, + eGL_POLYGON_OFFSET_LINE = 0x2A02, + eGL_POLYGON_OFFSET_POINT = 0x2A01, + eGL_POLYGON_OFFSET_UNITS = 0x2A00, + eGL_POLYGON_SMOOTH = 0x0B41, + eGL_POLYGON_SMOOTH_HINT = 0x0C53, + eGL_POST_COLOR_MATRIX_ALPHA_BIAS = 0x80BB, + eGL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI = 0x80BB, + eGL_POST_COLOR_MATRIX_ALPHA_SCALE = 0x80B7, + eGL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI = 0x80B7, + eGL_POST_COLOR_MATRIX_BLUE_BIAS = 0x80BA, + eGL_POST_COLOR_MATRIX_BLUE_BIAS_SGI = 0x80BA, + eGL_POST_COLOR_MATRIX_BLUE_SCALE = 0x80B6, + eGL_POST_COLOR_MATRIX_BLUE_SCALE_SGI = 0x80B6, + eGL_POST_COLOR_MATRIX_COLOR_TABLE = 0x80D2, + eGL_POST_COLOR_MATRIX_COLOR_TABLE_SGI = 0x80D2, + eGL_POST_COLOR_MATRIX_GREEN_BIAS = 0x80B9, + eGL_POST_COLOR_MATRIX_GREEN_BIAS_SGI = 0x80B9, + eGL_POST_COLOR_MATRIX_GREEN_SCALE = 0x80B5, + eGL_POST_COLOR_MATRIX_GREEN_SCALE_SGI = 0x80B5, + eGL_POST_COLOR_MATRIX_RED_BIAS = 0x80B8, + eGL_POST_COLOR_MATRIX_RED_BIAS_SGI = 0x80B8, + eGL_POST_COLOR_MATRIX_RED_SCALE = 0x80B4, + eGL_POST_COLOR_MATRIX_RED_SCALE_SGI = 0x80B4, + eGL_POST_CONVOLUTION_ALPHA_BIAS = 0x8023, + eGL_POST_CONVOLUTION_ALPHA_BIAS_EXT = 0x8023, + eGL_POST_CONVOLUTION_ALPHA_SCALE = 0x801F, + eGL_POST_CONVOLUTION_ALPHA_SCALE_EXT = 0x801F, + eGL_POST_CONVOLUTION_BLUE_BIAS = 0x8022, + eGL_POST_CONVOLUTION_BLUE_BIAS_EXT = 0x8022, + eGL_POST_CONVOLUTION_BLUE_SCALE = 0x801E, + eGL_POST_CONVOLUTION_BLUE_SCALE_EXT = 0x801E, + eGL_POST_CONVOLUTION_COLOR_TABLE = 0x80D1, + eGL_POST_CONVOLUTION_COLOR_TABLE_SGI = 0x80D1, + eGL_POST_CONVOLUTION_GREEN_BIAS = 0x8021, + eGL_POST_CONVOLUTION_GREEN_BIAS_EXT = 0x8021, + eGL_POST_CONVOLUTION_GREEN_SCALE = 0x801D, + eGL_POST_CONVOLUTION_GREEN_SCALE_EXT = 0x801D, + eGL_POST_CONVOLUTION_RED_BIAS = 0x8020, + eGL_POST_CONVOLUTION_RED_BIAS_EXT = 0x8020, + eGL_POST_CONVOLUTION_RED_SCALE = 0x801C, + eGL_POST_CONVOLUTION_RED_SCALE_EXT = 0x801C, + eGL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP = 0x8162, + eGL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX = 0x817B, + eGL_POST_TEXTURE_FILTER_BIAS_SGIX = 0x8179, + eGL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX = 0x817C, + eGL_POST_TEXTURE_FILTER_SCALE_SGIX = 0x817A, + eGL_PREFER_DOUBLEBUFFER_HINT_PGI = 0x1A1F8, + eGL_PRESENT_DURATION_NV = 0x8E2B, + eGL_PRESENT_TIME_NV = 0x8E2A, + eGL_PRESERVE_ATI = 0x8762, + eGL_PREVIOUS = 0x8578, + eGL_PREVIOUS_ARB = 0x8578, + eGL_PREVIOUS_EXT = 0x8578, + eGL_PREVIOUS_TEXTURE_INPUT_NV = 0x86E4, + eGL_PRIMARY_COLOR = 0x8577, + eGL_PRIMARY_COLOR_ARB = 0x8577, + eGL_PRIMARY_COLOR_EXT = 0x8577, + eGL_PRIMARY_COLOR_NV = 0x852C, + eGL_PRIMITIVES_GENERATED = 0x8C87, + eGL_PRIMITIVES_GENERATED_EXT = 0x8C87, + eGL_PRIMITIVES_GENERATED_NV = 0x8C87, + eGL_PRIMITIVE_ID_NV = 0x8C7C, + eGL_PRIMITIVE_RESTART = 0x8F9D, + eGL_PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69, + eGL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 0x8221, + eGL_PRIMITIVE_RESTART_INDEX = 0x8F9E, + eGL_PRIMITIVE_RESTART_INDEX_NV = 0x8559, + eGL_PRIMITIVE_RESTART_NV = 0x8558, + eGL_PROGRAM = 0x82E2, + eGL_PROGRAM_ADDRESS_REGISTERS_ARB = 0x88B0, + eGL_PROGRAM_ALU_INSTRUCTIONS_ARB = 0x8805, + eGL_PROGRAM_ATTRIBS_ARB = 0x88AC, + eGL_PROGRAM_ATTRIB_COMPONENTS_NV = 0x8906, + eGL_PROGRAM_BINARY_FORMATS = 0x87FF, + eGL_PROGRAM_BINARY_LENGTH = 0x8741, + eGL_PROGRAM_BINARY_RETRIEVABLE_HINT = 0x8257, + eGL_PROGRAM_BINDING_ARB = 0x8677, + eGL_PROGRAM_ERROR_POSITION_ARB = 0x864B, + eGL_PROGRAM_ERROR_POSITION_NV = 0x864B, + eGL_PROGRAM_ERROR_STRING_ARB = 0x8874, + eGL_PROGRAM_ERROR_STRING_NV = 0x8874, + eGL_PROGRAM_FORMAT_ARB = 0x8876, + eGL_PROGRAM_FORMAT_ASCII_ARB = 0x8875, + eGL_PROGRAM_INPUT = 0x92E3, + eGL_PROGRAM_INSTRUCTIONS_ARB = 0x88A0, + eGL_PROGRAM_LENGTH_ARB = 0x8627, + eGL_PROGRAM_LENGTH_NV = 0x8627, + eGL_PROGRAM_MATRIX_EXT = 0x8E2D, + eGL_PROGRAM_MATRIX_STACK_DEPTH_EXT = 0x8E2F, + eGL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = 0x88B2, + eGL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = 0x8808, + eGL_PROGRAM_NATIVE_ATTRIBS_ARB = 0x88AE, + eGL_PROGRAM_NATIVE_INSTRUCTIONS_ARB = 0x88A2, + eGL_PROGRAM_NATIVE_PARAMETERS_ARB = 0x88AA, + eGL_PROGRAM_NATIVE_TEMPORARIES_ARB = 0x88A6, + eGL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = 0x880A, + eGL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = 0x8809, + eGL_PROGRAM_OBJECT_ARB = 0x8B40, + eGL_PROGRAM_OBJECT_EXT = 0x8B40, + eGL_PROGRAM_OUTPUT = 0x92E4, + eGL_PROGRAM_PARAMETERS_ARB = 0x88A8, + eGL_PROGRAM_PARAMETER_NV = 0x8644, + eGL_PROGRAM_PIPELINE = 0x82E4, + eGL_PROGRAM_PIPELINE_BINDING = 0x825A, + eGL_PROGRAM_PIPELINE_OBJECT_EXT = 0x8A4F, + eGL_PROGRAM_POINT_SIZE = 0x8642, + eGL_PROGRAM_POINT_SIZE_ARB = 0x8642, + eGL_PROGRAM_POINT_SIZE_EXT = 0x8642, + eGL_PROGRAM_RESIDENT_NV = 0x8647, + eGL_PROGRAM_RESULT_COMPONENTS_NV = 0x8907, + eGL_PROGRAM_SEPARABLE = 0x8258, + eGL_PROGRAM_STRING_ARB = 0x8628, + eGL_PROGRAM_STRING_NV = 0x8628, + eGL_PROGRAM_TARGET_NV = 0x8646, + eGL_PROGRAM_TEMPORARIES_ARB = 0x88A4, + eGL_PROGRAM_TEX_INDIRECTIONS_ARB = 0x8807, + eGL_PROGRAM_TEX_INSTRUCTIONS_ARB = 0x8806, + eGL_PROGRAM_UNDER_NATIVE_LIMITS_ARB = 0x88B6, + eGL_PROVOKING_VERTEX = 0x8E4F, + eGL_PROVOKING_VERTEX_EXT = 0x8E4F, + eGL_PROXY_COLOR_TABLE = 0x80D3, + eGL_PROXY_COLOR_TABLE_SGI = 0x80D3, + eGL_PROXY_HISTOGRAM = 0x8025, + eGL_PROXY_HISTOGRAM_EXT = 0x8025, + eGL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE = 0x80D5, + eGL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI = 0x80D5, + eGL_PROXY_POST_CONVOLUTION_COLOR_TABLE = 0x80D4, + eGL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI = 0x80D4, + eGL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP = 0x8163, + eGL_PROXY_TEXTURE_1D = 0x8063, + eGL_PROXY_TEXTURE_1D_ARRAY = 0x8C19, + eGL_PROXY_TEXTURE_1D_ARRAY_EXT = 0x8C19, + eGL_PROXY_TEXTURE_1D_EXT = 0x8063, + eGL_PROXY_TEXTURE_1D_STACK_MESAX = 0x875B, + eGL_PROXY_TEXTURE_2D = 0x8064, + eGL_PROXY_TEXTURE_2D_ARRAY = 0x8C1B, + eGL_PROXY_TEXTURE_2D_ARRAY_EXT = 0x8C1B, + eGL_PROXY_TEXTURE_2D_EXT = 0x8064, + eGL_PROXY_TEXTURE_2D_MULTISAMPLE = 0x9101, + eGL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x9103, + eGL_PROXY_TEXTURE_2D_STACK_MESAX = 0x875C, + eGL_PROXY_TEXTURE_3D = 0x8070, + eGL_PROXY_TEXTURE_3D_EXT = 0x8070, + eGL_PROXY_TEXTURE_4D_SGIS = 0x8135, + eGL_PROXY_TEXTURE_COLOR_TABLE_SGI = 0x80BD, + eGL_PROXY_TEXTURE_CUBE_MAP = 0x851B, + eGL_PROXY_TEXTURE_CUBE_MAP_ARB = 0x851B, + eGL_PROXY_TEXTURE_CUBE_MAP_ARRAY = 0x900B, + eGL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB = 0x900B, + eGL_PROXY_TEXTURE_CUBE_MAP_EXT = 0x851B, + eGL_PROXY_TEXTURE_RECTANGLE = 0x84F7, + eGL_PROXY_TEXTURE_RECTANGLE_ARB = 0x84F7, + eGL_PROXY_TEXTURE_RECTANGLE_NV = 0x84F7, + eGL_PURGEABLE_APPLE = 0x8A1D, + eGL_QUADS = 0x0007, + eGL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION = 0x8E4C, + eGL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT = 0x8E4C, + eGL_QUAD_ALPHA4_SGIS = 0x811E, + eGL_QUAD_ALPHA8_SGIS = 0x811F, + eGL_QUAD_INTENSITY4_SGIS = 0x8122, + eGL_QUAD_INTENSITY8_SGIS = 0x8123, + eGL_QUAD_LUMINANCE4_SGIS = 0x8120, + eGL_QUAD_LUMINANCE8_SGIS = 0x8121, + eGL_QUAD_MESH_SUN = 0x8614, + eGL_QUAD_TEXTURE_SELECT_SGIS = 0x8125, + eGL_QUARTER_BIT_ATI = 0x00000010, + eGL_QUERY = 0x82E3, + eGL_QUERY_ALL_EVENT_BITS_AMD = 0xFFFFFFFF, + eGL_QUERY_BUFFER = 0x9192, + eGL_QUERY_BUFFER_AMD = 0x9192, + eGL_QUERY_BUFFER_BARRIER_BIT = 0x00008000, + eGL_QUERY_BUFFER_BINDING = 0x9193, + eGL_QUERY_BUFFER_BINDING_AMD = 0x9193, + eGL_QUERY_BY_REGION_NO_WAIT = 0x8E16, + eGL_QUERY_BY_REGION_NO_WAIT_NV = 0x8E16, + eGL_QUERY_BY_REGION_WAIT = 0x8E15, + eGL_QUERY_BY_REGION_WAIT_NV = 0x8E15, + eGL_QUERY_COUNTER_BITS = 0x8864, + eGL_QUERY_COUNTER_BITS_ARB = 0x8864, + eGL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD = 0x00000008, + eGL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD = 0x00000002, + eGL_QUERY_DEPTH_PASS_EVENT_BIT_AMD = 0x00000001, + eGL_QUERY_NO_WAIT = 0x8E14, + eGL_QUERY_NO_WAIT_NV = 0x8E14, + eGL_QUERY_OBJECT_AMD = 0x9153, + eGL_QUERY_OBJECT_EXT = 0x9153, + eGL_QUERY_RESULT = 0x8866, + eGL_QUERY_RESULT_ARB = 0x8866, + eGL_QUERY_RESULT_AVAILABLE = 0x8867, + eGL_QUERY_RESULT_AVAILABLE_ARB = 0x8867, + eGL_QUERY_RESULT_NO_WAIT = 0x9194, + eGL_QUERY_RESULT_NO_WAIT_AMD = 0x9194, + eGL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD = 0x00000004, + eGL_QUERY_WAIT = 0x8E13, + eGL_QUERY_WAIT_NV = 0x8E13, + eGL_R11F_G11F_B10F = 0x8C3A, + eGL_R11F_G11F_B10F_EXT = 0x8C3A, + eGL_R16 = 0x822A, + eGL_R16F = 0x822D, + eGL_R16I = 0x8233, + eGL_R16UI = 0x8234, + eGL_R16_SNORM = 0x8F98, + eGL_R1UI_C3F_V3F_SUN = 0x85C6, + eGL_R1UI_C4F_N3F_V3F_SUN = 0x85C8, + eGL_R1UI_C4UB_V3F_SUN = 0x85C5, + eGL_R1UI_N3F_V3F_SUN = 0x85C7, + eGL_R1UI_T2F_C4F_N3F_V3F_SUN = 0x85CB, + eGL_R1UI_T2F_N3F_V3F_SUN = 0x85CA, + eGL_R1UI_T2F_V3F_SUN = 0x85C9, + eGL_R1UI_V3F_SUN = 0x85C4, + eGL_R32F = 0x822E, + eGL_R32I = 0x8235, + eGL_R32UI = 0x8236, + eGL_R3_G3_B2 = 0x2A10, + eGL_R8 = 0x8229, + eGL_R8I = 0x8231, + eGL_R8UI = 0x8232, + eGL_R8_SNORM = 0x8F94, + eGL_RASTERIZER_DISCARD = 0x8C89, + eGL_RASTERIZER_DISCARD_EXT = 0x8C89, + eGL_RASTERIZER_DISCARD_NV = 0x8C89, + eGL_RASTER_POSITION_UNCLIPPED_IBM = 0x19262, + eGL_READ_BUFFER = 0x0C02, + eGL_READ_FRAMEBUFFER = 0x8CA8, + eGL_READ_FRAMEBUFFER_BINDING = 0x8CAA, + eGL_READ_FRAMEBUFFER_BINDING_EXT = 0x8CAA, + eGL_READ_FRAMEBUFFER_EXT = 0x8CA8, + eGL_READ_ONLY = 0x88B8, + eGL_READ_ONLY_ARB = 0x88B8, + eGL_READ_PIXELS = 0x828C, + eGL_READ_PIXELS_FORMAT = 0x828D, + eGL_READ_PIXELS_TYPE = 0x828E, + eGL_READ_PIXEL_DATA_RANGE_LENGTH_NV = 0x887B, + eGL_READ_PIXEL_DATA_RANGE_NV = 0x8879, + eGL_READ_PIXEL_DATA_RANGE_POINTER_NV = 0x887D, + eGL_READ_WRITE = 0x88BA, + eGL_READ_WRITE_ARB = 0x88BA, + eGL_RECLAIM_MEMORY_HINT_PGI = 0x1A1FE, + eGL_RED = 0x1903, + eGL_REDUCE = 0x8016, + eGL_REDUCE_EXT = 0x8016, + eGL_RED_BIT_ATI = 0x00000001, + eGL_RED_INTEGER = 0x8D94, + eGL_RED_INTEGER_EXT = 0x8D94, + eGL_RED_MAX_CLAMP_INGR = 0x8564, + eGL_RED_MIN_CLAMP_INGR = 0x8560, + eGL_RED_NV = 0x1903, + eGL_RED_SNORM = 0x8F90, + eGL_REFERENCED_BY_COMPUTE_SHADER = 0x930B, + eGL_REFERENCED_BY_FRAGMENT_SHADER = 0x930A, + eGL_REFERENCED_BY_GEOMETRY_SHADER = 0x9309, + eGL_REFERENCED_BY_TESS_CONTROL_SHADER = 0x9307, + eGL_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x9308, + eGL_REFERENCED_BY_VERTEX_SHADER = 0x9306, + eGL_REFERENCE_PLANE_EQUATION_SGIX = 0x817E, + eGL_REFERENCE_PLANE_SGIX = 0x817D, + eGL_REFLECTION_MAP = 0x8512, + eGL_REFLECTION_MAP_ARB = 0x8512, + eGL_REFLECTION_MAP_EXT = 0x8512, + eGL_REFLECTION_MAP_NV = 0x8512, + eGL_REGISTER_COMBINERS_NV = 0x8522, + eGL_REG_0_ATI = 0x8921, + eGL_REG_10_ATI = 0x892B, + eGL_REG_11_ATI = 0x892C, + eGL_REG_12_ATI = 0x892D, + eGL_REG_13_ATI = 0x892E, + eGL_REG_14_ATI = 0x892F, + eGL_REG_15_ATI = 0x8930, + eGL_REG_16_ATI = 0x8931, + eGL_REG_17_ATI = 0x8932, + eGL_REG_18_ATI = 0x8933, + eGL_REG_19_ATI = 0x8934, + eGL_REG_1_ATI = 0x8922, + eGL_REG_20_ATI = 0x8935, + eGL_REG_21_ATI = 0x8936, + eGL_REG_22_ATI = 0x8937, + eGL_REG_23_ATI = 0x8938, + eGL_REG_24_ATI = 0x8939, + eGL_REG_25_ATI = 0x893A, + eGL_REG_26_ATI = 0x893B, + eGL_REG_27_ATI = 0x893C, + eGL_REG_28_ATI = 0x893D, + eGL_REG_29_ATI = 0x893E, + eGL_REG_2_ATI = 0x8923, + eGL_REG_30_ATI = 0x893F, + eGL_REG_31_ATI = 0x8940, + eGL_REG_3_ATI = 0x8924, + eGL_REG_4_ATI = 0x8925, + eGL_REG_5_ATI = 0x8926, + eGL_REG_6_ATI = 0x8927, + eGL_REG_7_ATI = 0x8928, + eGL_REG_8_ATI = 0x8929, + eGL_REG_9_ATI = 0x892A, + eGL_RELEASED_APPLE = 0x8A19, + eGL_RENDERBUFFER = 0x8D41, + eGL_RENDERBUFFER_ALPHA_SIZE = 0x8D53, + eGL_RENDERBUFFER_ALPHA_SIZE_EXT = 0x8D53, + eGL_RENDERBUFFER_BINDING = 0x8CA7, + eGL_RENDERBUFFER_BINDING_EXT = 0x8CA7, + eGL_RENDERBUFFER_BLUE_SIZE = 0x8D52, + eGL_RENDERBUFFER_BLUE_SIZE_EXT = 0x8D52, + eGL_RENDERBUFFER_COLOR_SAMPLES_NV = 0x8E10, + eGL_RENDERBUFFER_COVERAGE_SAMPLES_NV = 0x8CAB, + eGL_RENDERBUFFER_DEPTH_SIZE = 0x8D54, + eGL_RENDERBUFFER_DEPTH_SIZE_EXT = 0x8D54, + eGL_RENDERBUFFER_EXT = 0x8D41, + eGL_RENDERBUFFER_FREE_MEMORY_ATI = 0x87FD, + eGL_RENDERBUFFER_GREEN_SIZE = 0x8D51, + eGL_RENDERBUFFER_GREEN_SIZE_EXT = 0x8D51, + eGL_RENDERBUFFER_HEIGHT = 0x8D43, + eGL_RENDERBUFFER_HEIGHT_EXT = 0x8D43, + eGL_RENDERBUFFER_INTERNAL_FORMAT = 0x8D44, + eGL_RENDERBUFFER_INTERNAL_FORMAT_EXT = 0x8D44, + eGL_RENDERBUFFER_RED_SIZE = 0x8D50, + eGL_RENDERBUFFER_RED_SIZE_EXT = 0x8D50, + eGL_RENDERBUFFER_SAMPLES = 0x8CAB, + eGL_RENDERBUFFER_SAMPLES_EXT = 0x8CAB, + eGL_RENDERBUFFER_STENCIL_SIZE = 0x8D55, + eGL_RENDERBUFFER_STENCIL_SIZE_EXT = 0x8D55, + eGL_RENDERBUFFER_WIDTH = 0x8D42, + eGL_RENDERBUFFER_WIDTH_EXT = 0x8D42, + eGL_RENDERER = 0x1F01, + eGL_REPEAT = 0x2901, + eGL_REPLACE = 0x1E01, + eGL_REPLACEMENT_CODE_ARRAY_POINTER_SUN = 0x85C3, + eGL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN = 0x85C2, + eGL_REPLACEMENT_CODE_ARRAY_SUN = 0x85C0, + eGL_REPLACEMENT_CODE_ARRAY_TYPE_SUN = 0x85C1, + eGL_REPLACEMENT_CODE_SUN = 0x81D8, + eGL_REPLACE_EXT = 0x8062, + eGL_REPLACE_MIDDLE_SUN = 0x0002, + eGL_REPLACE_OLDEST_SUN = 0x0003, + eGL_REPLACE_VALUE_AMD = 0x874B, + eGL_REPLICATE_BORDER = 0x8153, + eGL_REPLICATE_BORDER_HP = 0x8153, + eGL_RESAMPLE_AVERAGE_OML = 0x8988, + eGL_RESAMPLE_DECIMATE_OML = 0x8989, + eGL_RESAMPLE_DECIMATE_SGIX = 0x8430, + eGL_RESAMPLE_REPLICATE_OML = 0x8986, + eGL_RESAMPLE_REPLICATE_SGIX = 0x842E, + eGL_RESAMPLE_ZERO_FILL_OML = 0x8987, + eGL_RESAMPLE_ZERO_FILL_SGIX = 0x842F, + eGL_RESCALE_NORMAL = 0x803A, + eGL_RESCALE_NORMAL_EXT = 0x803A, + eGL_RESET_NOTIFICATION_STRATEGY_ARB = 0x8256, + eGL_RESTART_SUN = 0x0001, + eGL_RETAINED_APPLE = 0x8A1B, + eGL_RG = 0x8227, + eGL_RG16 = 0x822C, + eGL_RG16F = 0x822F, + eGL_RG16I = 0x8239, + eGL_RG16UI = 0x823A, + eGL_RG16_SNORM = 0x8F99, + eGL_RG32F = 0x8230, + eGL_RG32I = 0x823B, + eGL_RG32UI = 0x823C, + eGL_RG8 = 0x822B, + eGL_RG8I = 0x8237, + eGL_RG8UI = 0x8238, + eGL_RG8_SNORM = 0x8F95, + eGL_RGB = 0x1907, + eGL_RGB10 = 0x8052, + eGL_RGB10_A2 = 0x8059, + eGL_RGB10_A2UI = 0x906F, + eGL_RGB10_A2_EXT = 0x8059, + eGL_RGB10_EXT = 0x8052, + eGL_RGB12 = 0x8053, + eGL_RGB12_EXT = 0x8053, + eGL_RGB16 = 0x8054, + eGL_RGB16F = 0x881B, + eGL_RGB16F_ARB = 0x881B, + eGL_RGB16I = 0x8D89, + eGL_RGB16I_EXT = 0x8D89, + eGL_RGB16UI = 0x8D77, + eGL_RGB16UI_EXT = 0x8D77, + eGL_RGB16_EXT = 0x8054, + eGL_RGB16_SNORM = 0x8F9A, + eGL_RGB2_EXT = 0x804E, + eGL_RGB32F = 0x8815, + eGL_RGB32F_ARB = 0x8815, + eGL_RGB32I = 0x8D83, + eGL_RGB32I_EXT = 0x8D83, + eGL_RGB32UI = 0x8D71, + eGL_RGB32UI_EXT = 0x8D71, + eGL_RGB4 = 0x804F, + eGL_RGB4_EXT = 0x804F, + eGL_RGB4_S3TC = 0x83A1, + eGL_RGB5 = 0x8050, + eGL_RGB565 = 0x8D62, + eGL_RGB5_A1 = 0x8057, + eGL_RGB5_A1_EXT = 0x8057, + eGL_RGB5_EXT = 0x8050, + eGL_RGB8 = 0x8051, + eGL_RGB8I = 0x8D8F, + eGL_RGB8I_EXT = 0x8D8F, + eGL_RGB8UI = 0x8D7D, + eGL_RGB8UI_EXT = 0x8D7D, + eGL_RGB8_EXT = 0x8051, + eGL_RGB8_SNORM = 0x8F96, + eGL_RGB9_E5 = 0x8C3D, + eGL_RGB9_E5_EXT = 0x8C3D, + eGL_RGBA = 0x1908, + eGL_RGBA12 = 0x805A, + eGL_RGBA12_EXT = 0x805A, + eGL_RGBA16 = 0x805B, + eGL_RGBA16F = 0x881A, + eGL_RGBA16F_ARB = 0x881A, + eGL_RGBA16I = 0x8D88, + eGL_RGBA16I_EXT = 0x8D88, + eGL_RGBA16UI = 0x8D76, + eGL_RGBA16UI_EXT = 0x8D76, + eGL_RGBA16_EXT = 0x805B, + eGL_RGBA16_SNORM = 0x8F9B, + eGL_RGBA2 = 0x8055, + eGL_RGBA2_EXT = 0x8055, + eGL_RGBA32F = 0x8814, + eGL_RGBA32F_ARB = 0x8814, + eGL_RGBA32I = 0x8D82, + eGL_RGBA32I_EXT = 0x8D82, + eGL_RGBA32UI = 0x8D70, + eGL_RGBA32UI_EXT = 0x8D70, + eGL_RGBA4 = 0x8056, + eGL_RGBA4_DXT5_S3TC = 0x83A5, + eGL_RGBA4_EXT = 0x8056, + eGL_RGBA4_S3TC = 0x83A3, + eGL_RGBA8 = 0x8058, + eGL_RGBA8I = 0x8D8E, + eGL_RGBA8I_EXT = 0x8D8E, + eGL_RGBA8UI = 0x8D7C, + eGL_RGBA8UI_EXT = 0x8D7C, + eGL_RGBA8_EXT = 0x8058, + eGL_RGBA8_SNORM = 0x8F97, + eGL_RGBA_DXT5_S3TC = 0x83A4, + eGL_RGBA_FLOAT16_APPLE = 0x881A, + eGL_RGBA_FLOAT16_ATI = 0x881A, + eGL_RGBA_FLOAT32_APPLE = 0x8814, + eGL_RGBA_FLOAT32_ATI = 0x8814, + eGL_RGBA_FLOAT_MODE_ARB = 0x8820, + eGL_RGBA_FLOAT_MODE_ATI = 0x8820, + eGL_RGBA_INTEGER = 0x8D99, + eGL_RGBA_INTEGER_EXT = 0x8D99, + eGL_RGBA_INTEGER_MODE_EXT = 0x8D9E, + eGL_RGBA_S3TC = 0x83A2, + eGL_RGBA_SIGNED_COMPONENTS_EXT = 0x8C3C, + eGL_RGBA_SNORM = 0x8F93, + eGL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV = 0x86D9, + eGL_RGB_422_APPLE = 0x8A1F, + eGL_RGB_FLOAT16_APPLE = 0x881B, + eGL_RGB_FLOAT16_ATI = 0x881B, + eGL_RGB_FLOAT32_APPLE = 0x8815, + eGL_RGB_FLOAT32_ATI = 0x8815, + eGL_RGB_INTEGER = 0x8D98, + eGL_RGB_INTEGER_EXT = 0x8D98, + eGL_RGB_RAW_422_APPLE = 0x8A51, + eGL_RGB_S3TC = 0x83A0, + eGL_RGB_SCALE = 0x8573, + eGL_RGB_SCALE_ARB = 0x8573, + eGL_RGB_SCALE_EXT = 0x8573, + eGL_RGB_SNORM = 0x8F92, + eGL_RG_INTEGER = 0x8228, + eGL_RG_SNORM = 0x8F91, + eGL_RIGHT = 0x0407, + eGL_ROUND_NV = 0x90A4, + eGL_SAMPLER = 0x82E6, + eGL_SAMPLER_1D = 0x8B5D, + eGL_SAMPLER_1D_ARB = 0x8B5D, + eGL_SAMPLER_1D_ARRAY = 0x8DC0, + eGL_SAMPLER_1D_ARRAY_EXT = 0x8DC0, + eGL_SAMPLER_1D_ARRAY_SHADOW = 0x8DC3, + eGL_SAMPLER_1D_ARRAY_SHADOW_EXT = 0x8DC3, + eGL_SAMPLER_1D_SHADOW = 0x8B61, + eGL_SAMPLER_1D_SHADOW_ARB = 0x8B61, + eGL_SAMPLER_2D = 0x8B5E, + eGL_SAMPLER_2D_ARB = 0x8B5E, + eGL_SAMPLER_2D_ARRAY = 0x8DC1, + eGL_SAMPLER_2D_ARRAY_EXT = 0x8DC1, + eGL_SAMPLER_2D_ARRAY_SHADOW = 0x8DC4, + eGL_SAMPLER_2D_ARRAY_SHADOW_EXT = 0x8DC4, + eGL_SAMPLER_2D_MULTISAMPLE = 0x9108, + eGL_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910B, + eGL_SAMPLER_2D_RECT = 0x8B63, + eGL_SAMPLER_2D_RECT_ARB = 0x8B63, + eGL_SAMPLER_2D_RECT_SHADOW = 0x8B64, + eGL_SAMPLER_2D_RECT_SHADOW_ARB = 0x8B64, + eGL_SAMPLER_2D_SHADOW = 0x8B62, + eGL_SAMPLER_2D_SHADOW_ARB = 0x8B62, + eGL_SAMPLER_3D = 0x8B5F, + eGL_SAMPLER_3D_ARB = 0x8B5F, + eGL_SAMPLER_BINDING = 0x8919, + eGL_SAMPLER_BUFFER = 0x8DC2, + eGL_SAMPLER_BUFFER_AMD = 0x9001, + eGL_SAMPLER_BUFFER_EXT = 0x8DC2, + eGL_SAMPLER_CUBE = 0x8B60, + eGL_SAMPLER_CUBE_ARB = 0x8B60, + eGL_SAMPLER_CUBE_MAP_ARRAY = 0x900C, + eGL_SAMPLER_CUBE_MAP_ARRAY_ARB = 0x900C, + eGL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 0x900D, + eGL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB = 0x900D, + eGL_SAMPLER_CUBE_SHADOW = 0x8DC5, + eGL_SAMPLER_CUBE_SHADOW_EXT = 0x8DC5, + eGL_SAMPLER_OBJECT_AMD = 0x9155, + eGL_SAMPLER_RENDERBUFFER_NV = 0x8E56, + eGL_SAMPLES = 0x80A9, + eGL_SAMPLES_3DFX = 0x86B4, + eGL_SAMPLES_ARB = 0x80A9, + eGL_SAMPLES_EXT = 0x80A9, + eGL_SAMPLES_PASSED = 0x8914, + eGL_SAMPLES_PASSED_ARB = 0x8914, + eGL_SAMPLES_SGIS = 0x80A9, + eGL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E, + eGL_SAMPLE_ALPHA_TO_COVERAGE_ARB = 0x809E, + eGL_SAMPLE_ALPHA_TO_MASK_EXT = 0x809E, + eGL_SAMPLE_ALPHA_TO_MASK_SGIS = 0x809E, + eGL_SAMPLE_ALPHA_TO_ONE = 0x809F, + eGL_SAMPLE_ALPHA_TO_ONE_ARB = 0x809F, + eGL_SAMPLE_ALPHA_TO_ONE_EXT = 0x809F, + eGL_SAMPLE_ALPHA_TO_ONE_SGIS = 0x809F, + eGL_SAMPLE_BUFFERS = 0x80A8, + eGL_SAMPLE_BUFFERS_3DFX = 0x86B3, + eGL_SAMPLE_BUFFERS_ARB = 0x80A8, + eGL_SAMPLE_BUFFERS_EXT = 0x80A8, + eGL_SAMPLE_BUFFERS_SGIS = 0x80A8, + eGL_SAMPLE_COVERAGE = 0x80A0, + eGL_SAMPLE_COVERAGE_ARB = 0x80A0, + eGL_SAMPLE_COVERAGE_INVERT = 0x80AB, + eGL_SAMPLE_COVERAGE_INVERT_ARB = 0x80AB, + eGL_SAMPLE_COVERAGE_VALUE = 0x80AA, + eGL_SAMPLE_COVERAGE_VALUE_ARB = 0x80AA, + eGL_SAMPLE_MASK = 0x8E51, + eGL_SAMPLE_MASK_EXT = 0x80A0, + eGL_SAMPLE_MASK_INVERT_EXT = 0x80AB, + eGL_SAMPLE_MASK_INVERT_SGIS = 0x80AB, + eGL_SAMPLE_MASK_NV = 0x8E51, + eGL_SAMPLE_MASK_SGIS = 0x80A0, + eGL_SAMPLE_MASK_VALUE = 0x8E52, + eGL_SAMPLE_MASK_VALUE_EXT = 0x80AA, + eGL_SAMPLE_MASK_VALUE_NV = 0x8E52, + eGL_SAMPLE_MASK_VALUE_SGIS = 0x80AA, + eGL_SAMPLE_PATTERN_EXT = 0x80AC, + eGL_SAMPLE_PATTERN_SGIS = 0x80AC, + eGL_SAMPLE_POSITION = 0x8E50, + eGL_SAMPLE_POSITION_NV = 0x8E50, + eGL_SAMPLE_SHADING = 0x8C36, + eGL_SAMPLE_SHADING_ARB = 0x8C36, + eGL_SATURATE_BIT_ATI = 0x00000040, + eGL_SCALAR_EXT = 0x87BE, + eGL_SCALEBIAS_HINT_SGIX = 0x8322, + eGL_SCALED_RESOLVE_FASTEST_EXT = 0x90BA, + eGL_SCALED_RESOLVE_NICEST_EXT = 0x90BB, + eGL_SCALE_BY_FOUR_NV = 0x853F, + eGL_SCALE_BY_ONE_HALF_NV = 0x8540, + eGL_SCALE_BY_TWO_NV = 0x853E, + eGL_SCISSOR_BOX = 0x0C10, + eGL_SCISSOR_TEST = 0x0C11, + eGL_SCREEN_COORDINATES_REND = 0x8490, + eGL_SCREEN_NV = 0x9295, + eGL_SECONDARY_COLOR_ARRAY = 0x845E, + eGL_SECONDARY_COLOR_ARRAY_ADDRESS_NV = 0x8F27, + eGL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING = 0x889C, + eGL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB = 0x889C, + eGL_SECONDARY_COLOR_ARRAY_EXT = 0x845E, + eGL_SECONDARY_COLOR_ARRAY_LENGTH_NV = 0x8F31, + eGL_SECONDARY_COLOR_ARRAY_POINTER = 0x845D, + eGL_SECONDARY_COLOR_ARRAY_POINTER_EXT = 0x845D, + eGL_SECONDARY_COLOR_ARRAY_SIZE = 0x845A, + eGL_SECONDARY_COLOR_ARRAY_SIZE_EXT = 0x845A, + eGL_SECONDARY_COLOR_ARRAY_STRIDE = 0x845C, + eGL_SECONDARY_COLOR_ARRAY_STRIDE_EXT = 0x845C, + eGL_SECONDARY_COLOR_ARRAY_TYPE = 0x845B, + eGL_SECONDARY_COLOR_ARRAY_TYPE_EXT = 0x845B, + eGL_SECONDARY_COLOR_NV = 0x852D, + eGL_SECONDARY_INTERPOLATOR_ATI = 0x896D, + eGL_SEPARABLE_2D = 0x8012, + eGL_SEPARABLE_2D_EXT = 0x8012, + eGL_SEPARATE_ATTRIBS = 0x8C8D, + eGL_SEPARATE_ATTRIBS_EXT = 0x8C8D, + eGL_SEPARATE_ATTRIBS_NV = 0x8C8D, + eGL_SEPARATE_SPECULAR_COLOR = 0x81FA, + eGL_SEPARATE_SPECULAR_COLOR_EXT = 0x81FA, + eGL_SET = 0x150F, + eGL_SET_AMD = 0x874A, + eGL_SHADER = 0x82E1, + eGL_SHADER_BINARY_FORMATS = 0x8DF8, + eGL_SHADER_COMPILER = 0x8DFA, + eGL_SHADER_CONSISTENT_NV = 0x86DD, + eGL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV = 0x00000010, + eGL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 0x00000020, + eGL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT = 0x00000020, + eGL_SHADER_IMAGE_ATOMIC = 0x82A6, + eGL_SHADER_IMAGE_LOAD = 0x82A4, + eGL_SHADER_IMAGE_STORE = 0x82A5, + eGL_SHADER_INCLUDE_ARB = 0x8DAE, + eGL_SHADER_OBJECT_ARB = 0x8B48, + eGL_SHADER_OBJECT_EXT = 0x8B48, + eGL_SHADER_OPERATION_NV = 0x86DF, + eGL_SHADER_SOURCE_LENGTH = 0x8B88, + eGL_SHADER_STORAGE_BARRIER_BIT = 0x00002000, + eGL_SHADER_STORAGE_BLOCK = 0x92E6, + eGL_SHADER_STORAGE_BUFFER = 0x90D2, + eGL_SHADER_STORAGE_BUFFER_BINDING = 0x90D3, + eGL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT = 0x90DF, + eGL_SHADER_STORAGE_BUFFER_SIZE = 0x90D5, + eGL_SHADER_STORAGE_BUFFER_START = 0x90D4, + eGL_SHADER_TYPE = 0x8B4F, + eGL_SHADING_LANGUAGE_VERSION = 0x8B8C, + eGL_SHADING_LANGUAGE_VERSION_ARB = 0x8B8C, + eGL_SHADOW_AMBIENT_SGIX = 0x80BF, + eGL_SHADOW_ATTENUATION_EXT = 0x834E, + eGL_SHARED_TEXTURE_PALETTE_EXT = 0x81FB, + eGL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS = 0x80B0, + eGL_SHORT = 0x1402, + eGL_SIGNALED = 0x9119, + eGL_SIGNED_ALPHA8_NV = 0x8706, + eGL_SIGNED_ALPHA_NV = 0x8705, + eGL_SIGNED_HILO16_NV = 0x86FA, + eGL_SIGNED_HILO8_NV = 0x885F, + eGL_SIGNED_HILO_NV = 0x86F9, + eGL_SIGNED_IDENTITY_NV = 0x853C, + eGL_SIGNED_INTENSITY8_NV = 0x8708, + eGL_SIGNED_INTENSITY_NV = 0x8707, + eGL_SIGNED_LUMINANCE8_ALPHA8_NV = 0x8704, + eGL_SIGNED_LUMINANCE8_NV = 0x8702, + eGL_SIGNED_LUMINANCE_ALPHA_NV = 0x8703, + eGL_SIGNED_LUMINANCE_NV = 0x8701, + eGL_SIGNED_NEGATE_NV = 0x853D, + eGL_SIGNED_NORMALIZED = 0x8F9C, + eGL_SIGNED_RGB8_NV = 0x86FF, + eGL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV = 0x870D, + eGL_SIGNED_RGBA8_NV = 0x86FC, + eGL_SIGNED_RGBA_NV = 0x86FB, + eGL_SIGNED_RGB_NV = 0x86FE, + eGL_SIGNED_RGB_UNSIGNED_ALPHA_NV = 0x870C, + eGL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST = 0x82AC, + eGL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE = 0x82AE, + eGL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST = 0x82AD, + eGL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE = 0x82AF, + eGL_SINGLE_COLOR = 0x81F9, + eGL_SINGLE_COLOR_EXT = 0x81F9, + eGL_SKIP_DECODE_EXT = 0x8A4A, + eGL_SKIP_MISSING_GLYPH_NV = 0x90A9, + eGL_SLICE_ACCUM_SUN = 0x85CC, + eGL_SLUMINANCE = 0x8C46, + eGL_SLUMINANCE8 = 0x8C47, + eGL_SLUMINANCE8_ALPHA8 = 0x8C45, + eGL_SLUMINANCE8_ALPHA8_EXT = 0x8C45, + eGL_SLUMINANCE8_EXT = 0x8C47, + eGL_SLUMINANCE_ALPHA = 0x8C44, + eGL_SLUMINANCE_ALPHA_EXT = 0x8C44, + eGL_SLUMINANCE_EXT = 0x8C46, + eGL_SMOOTH_LINE_WIDTH_GRANULARITY = 0x0B23, + eGL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22, + eGL_SMOOTH_POINT_SIZE_GRANULARITY = 0x0B13, + eGL_SMOOTH_POINT_SIZE_RANGE = 0x0B12, + eGL_SM_COUNT_NV = 0x933B, + eGL_SOFTLIGHT_NV = 0x929C, + eGL_SOURCE0_ALPHA = 0x8588, + eGL_SOURCE0_ALPHA_ARB = 0x8588, + eGL_SOURCE0_ALPHA_EXT = 0x8588, + eGL_SOURCE0_RGB = 0x8580, + eGL_SOURCE0_RGB_ARB = 0x8580, + eGL_SOURCE0_RGB_EXT = 0x8580, + eGL_SOURCE1_ALPHA = 0x8589, + eGL_SOURCE1_ALPHA_ARB = 0x8589, + eGL_SOURCE1_ALPHA_EXT = 0x8589, + eGL_SOURCE1_RGB = 0x8581, + eGL_SOURCE1_RGB_ARB = 0x8581, + eGL_SOURCE1_RGB_EXT = 0x8581, + eGL_SOURCE2_ALPHA = 0x858A, + eGL_SOURCE2_ALPHA_ARB = 0x858A, + eGL_SOURCE2_ALPHA_EXT = 0x858A, + eGL_SOURCE2_RGB = 0x8582, + eGL_SOURCE2_RGB_ARB = 0x8582, + eGL_SOURCE2_RGB_EXT = 0x8582, + eGL_SOURCE3_ALPHA_NV = 0x858B, + eGL_SOURCE3_RGB_NV = 0x8583, + eGL_SPARE0_NV = 0x852E, + eGL_SPARE0_PLUS_SECONDARY_COLOR_NV = 0x8532, + eGL_SPARE1_NV = 0x852F, + eGL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB = 0x91A9, + eGL_SPRITE_AXIAL_SGIX = 0x814C, + eGL_SPRITE_AXIS_SGIX = 0x814A, + eGL_SPRITE_EYE_ALIGNED_SGIX = 0x814E, + eGL_SPRITE_MODE_SGIX = 0x8149, + eGL_SPRITE_OBJECT_ALIGNED_SGIX = 0x814D, + eGL_SPRITE_SGIX = 0x8148, + eGL_SPRITE_TRANSLATION_SGIX = 0x814B, + eGL_SQUARE_NV = 0x90A3, + eGL_SRC0_ALPHA = 0x8588, + eGL_SRC0_RGB = 0x8580, + eGL_SRC1_ALPHA = 0x8589, + eGL_SRC1_COLOR = 0x88F9, + eGL_SRC1_RGB = 0x8581, + eGL_SRC2_ALPHA = 0x858A, + eGL_SRC2_RGB = 0x8582, + eGL_SRC_ALPHA = 0x0302, + eGL_SRC_ALPHA_SATURATE = 0x0308, + eGL_SRC_ATOP_NV = 0x928E, + eGL_SRC_COLOR = 0x0300, + eGL_SRC_IN_NV = 0x928A, + eGL_SRC_NV = 0x9286, + eGL_SRC_OUT_NV = 0x928C, + eGL_SRC_OVER_NV = 0x9288, + eGL_SRGB = 0x8C40, + eGL_SRGB8 = 0x8C41, + eGL_SRGB8_ALPHA8 = 0x8C43, + eGL_SRGB8_ALPHA8_EXT = 0x8C43, + eGL_SRGB8_EXT = 0x8C41, + eGL_SRGB_ALPHA = 0x8C42, + eGL_SRGB_ALPHA_EXT = 0x8C42, + eGL_SRGB_DECODE_ARB = 0x8299, + eGL_SRGB_EXT = 0x8C40, + eGL_SRGB_READ = 0x8297, + eGL_SRGB_WRITE = 0x8298, + eGL_STACK_OVERFLOW = 0x0503, + eGL_STACK_UNDERFLOW = 0x0504, + eGL_STANDARD_FONT_NAME_NV = 0x9072, + eGL_STATIC_ATI = 0x8760, + eGL_STATIC_COPY = 0x88E6, + eGL_STATIC_COPY_ARB = 0x88E6, + eGL_STATIC_DRAW = 0x88E4, + eGL_STATIC_DRAW_ARB = 0x88E4, + eGL_STATIC_READ = 0x88E5, + eGL_STATIC_READ_ARB = 0x88E5, + eGL_STENCIL = 0x1802, + eGL_STENCIL_ATTACHMENT = 0x8D20, + eGL_STENCIL_ATTACHMENT_EXT = 0x8D20, + eGL_STENCIL_BACK_FAIL = 0x8801, + eGL_STENCIL_BACK_FAIL_ATI = 0x8801, + eGL_STENCIL_BACK_FUNC = 0x8800, + eGL_STENCIL_BACK_FUNC_ATI = 0x8800, + eGL_STENCIL_BACK_OP_VALUE_AMD = 0x874D, + eGL_STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802, + eGL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI = 0x8802, + eGL_STENCIL_BACK_PASS_DEPTH_PASS = 0x8803, + eGL_STENCIL_BACK_PASS_DEPTH_PASS_ATI = 0x8803, + eGL_STENCIL_BACK_REF = 0x8CA3, + eGL_STENCIL_BACK_VALUE_MASK = 0x8CA4, + eGL_STENCIL_BACK_WRITEMASK = 0x8CA5, + eGL_STENCIL_BUFFER_BIT = 0x00000400, + eGL_STENCIL_CLEAR_TAG_VALUE_EXT = 0x88F3, + eGL_STENCIL_CLEAR_VALUE = 0x0B91, + eGL_STENCIL_COMPONENTS = 0x8285, + eGL_STENCIL_FAIL = 0x0B94, + eGL_STENCIL_FUNC = 0x0B92, + eGL_STENCIL_INDEX = 0x1901, + eGL_STENCIL_INDEX1 = 0x8D46, + eGL_STENCIL_INDEX16 = 0x8D49, + eGL_STENCIL_INDEX16_EXT = 0x8D49, + eGL_STENCIL_INDEX1_EXT = 0x8D46, + eGL_STENCIL_INDEX4 = 0x8D47, + eGL_STENCIL_INDEX4_EXT = 0x8D47, + eGL_STENCIL_INDEX8 = 0x8D48, + eGL_STENCIL_INDEX8_EXT = 0x8D48, + eGL_STENCIL_OP_VALUE_AMD = 0x874C, + eGL_STENCIL_PASS_DEPTH_FAIL = 0x0B95, + eGL_STENCIL_PASS_DEPTH_PASS = 0x0B96, + eGL_STENCIL_REF = 0x0B97, + eGL_STENCIL_RENDERABLE = 0x8288, + eGL_STENCIL_TAG_BITS_EXT = 0x88F2, + eGL_STENCIL_TEST = 0x0B90, + eGL_STENCIL_TEST_TWO_SIDE_EXT = 0x8910, + eGL_STENCIL_VALUE_MASK = 0x0B93, + eGL_STENCIL_WRITEMASK = 0x0B98, + eGL_STEREO = 0x0C33, + eGL_STORAGE_CACHED_APPLE = 0x85BE, + eGL_STORAGE_CLIENT_APPLE = 0x85B4, + eGL_STORAGE_PRIVATE_APPLE = 0x85BD, + eGL_STORAGE_SHARED_APPLE = 0x85BF, + eGL_STREAM_COPY = 0x88E2, + eGL_STREAM_COPY_ARB = 0x88E2, + eGL_STREAM_DRAW = 0x88E0, + eGL_STREAM_DRAW_ARB = 0x88E0, + eGL_STREAM_RASTERIZATION_AMD = 0x91A0, + eGL_STREAM_READ = 0x88E1, + eGL_STREAM_READ_ARB = 0x88E1, + eGL_STRICT_DEPTHFUNC_HINT_PGI = 0x1A216, + eGL_STRICT_LIGHTING_HINT_PGI = 0x1A217, + eGL_STRICT_SCISSOR_HINT_PGI = 0x1A218, + eGL_SUBPIXEL_BITS = 0x0D50, + eGL_SUBSAMPLE_DISTANCE_AMD = 0x883F, + eGL_SUBTRACT = 0x84E7, + eGL_SUBTRACT_ARB = 0x84E7, + eGL_SUB_ATI = 0x8965, + eGL_SUCCESS_NV = 0x902F, + eGL_SURFACE_MAPPED_NV = 0x8700, + eGL_SURFACE_REGISTERED_NV = 0x86FD, + eGL_SURFACE_STATE_NV = 0x86EB, + eGL_SWIZZLE_STQ_ATI = 0x8977, + eGL_SWIZZLE_STQ_DQ_ATI = 0x8979, + eGL_SWIZZLE_STRQ_ATI = 0x897A, + eGL_SWIZZLE_STRQ_DQ_ATI = 0x897B, + eGL_SWIZZLE_STR_ATI = 0x8976, + eGL_SWIZZLE_STR_DR_ATI = 0x8978, + eGL_SYNC_CL_EVENT_ARB = 0x8240, + eGL_SYNC_CL_EVENT_COMPLETE_ARB = 0x8241, + eGL_SYNC_CONDITION = 0x9113, + eGL_SYNC_FENCE = 0x9116, + eGL_SYNC_FLAGS = 0x9115, + eGL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001, + eGL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117, + eGL_SYNC_STATUS = 0x9114, + eGL_SYNC_X11_FENCE_EXT = 0x90E1, + eGL_SYSTEM_FONT_NAME_NV = 0x9073, + eGL_T2F_IUI_N3F_V2F_EXT = 0x81B3, + eGL_T2F_IUI_N3F_V3F_EXT = 0x81B4, + eGL_T2F_IUI_V2F_EXT = 0x81B1, + eGL_T2F_IUI_V3F_EXT = 0x81B2, + eGL_TABLE_TOO_LARGE = 0x8031, + eGL_TABLE_TOO_LARGE_EXT = 0x8031, + eGL_TANGENT_ARRAY_EXT = 0x8439, + eGL_TANGENT_ARRAY_POINTER_EXT = 0x8442, + eGL_TANGENT_ARRAY_STRIDE_EXT = 0x843F, + eGL_TANGENT_ARRAY_TYPE_EXT = 0x843E, + eGL_TESSELLATION_FACTOR_AMD = 0x9005, + eGL_TESSELLATION_MODE_AMD = 0x9004, + eGL_TESS_CONTROL_OUTPUT_VERTICES = 0x8E75, + eGL_TESS_CONTROL_PROGRAM_NV = 0x891E, + eGL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV = 0x8C74, + eGL_TESS_CONTROL_SHADER = 0x8E88, + eGL_TESS_CONTROL_SHADER_BIT = 0x00000008, + eGL_TESS_CONTROL_SUBROUTINE = 0x92E9, + eGL_TESS_CONTROL_SUBROUTINE_UNIFORM = 0x92EF, + eGL_TESS_CONTROL_TEXTURE = 0x829C, + eGL_TESS_EVALUATION_PROGRAM_NV = 0x891F, + eGL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV = 0x8C75, + eGL_TESS_EVALUATION_SHADER = 0x8E87, + eGL_TESS_EVALUATION_SHADER_BIT = 0x00000010, + eGL_TESS_EVALUATION_SUBROUTINE = 0x92EA, + eGL_TESS_EVALUATION_SUBROUTINE_UNIFORM = 0x92F0, + eGL_TESS_EVALUATION_TEXTURE = 0x829D, + eGL_TESS_GEN_MODE = 0x8E76, + eGL_TESS_GEN_POINT_MODE = 0x8E79, + eGL_TESS_GEN_SPACING = 0x8E77, + eGL_TESS_GEN_VERTEX_ORDER = 0x8E78, + eGL_TEXCOORD1_BIT_PGI = 0x10000000, + eGL_TEXCOORD2_BIT_PGI = 0x20000000, + eGL_TEXCOORD3_BIT_PGI = 0x40000000, + eGL_TEXCOORD4_BIT_PGI = 0x80000000, + eGL_TEXTURE = 0x1702, + eGL_TEXTURE0 = 0x84C0, + eGL_TEXTURE0_ARB = 0x84C0, + eGL_TEXTURE1 = 0x84C1, + eGL_TEXTURE10 = 0x84CA, + eGL_TEXTURE10_ARB = 0x84CA, + eGL_TEXTURE11 = 0x84CB, + eGL_TEXTURE11_ARB = 0x84CB, + eGL_TEXTURE12 = 0x84CC, + eGL_TEXTURE12_ARB = 0x84CC, + eGL_TEXTURE13 = 0x84CD, + eGL_TEXTURE13_ARB = 0x84CD, + eGL_TEXTURE14 = 0x84CE, + eGL_TEXTURE14_ARB = 0x84CE, + eGL_TEXTURE15 = 0x84CF, + eGL_TEXTURE15_ARB = 0x84CF, + eGL_TEXTURE16 = 0x84D0, + eGL_TEXTURE16_ARB = 0x84D0, + eGL_TEXTURE17 = 0x84D1, + eGL_TEXTURE17_ARB = 0x84D1, + eGL_TEXTURE18 = 0x84D2, + eGL_TEXTURE18_ARB = 0x84D2, + eGL_TEXTURE19 = 0x84D3, + eGL_TEXTURE19_ARB = 0x84D3, + eGL_TEXTURE1_ARB = 0x84C1, + eGL_TEXTURE2 = 0x84C2, + eGL_TEXTURE20 = 0x84D4, + eGL_TEXTURE20_ARB = 0x84D4, + eGL_TEXTURE21 = 0x84D5, + eGL_TEXTURE21_ARB = 0x84D5, + eGL_TEXTURE22 = 0x84D6, + eGL_TEXTURE22_ARB = 0x84D6, + eGL_TEXTURE23 = 0x84D7, + eGL_TEXTURE23_ARB = 0x84D7, + eGL_TEXTURE24 = 0x84D8, + eGL_TEXTURE24_ARB = 0x84D8, + eGL_TEXTURE25 = 0x84D9, + eGL_TEXTURE25_ARB = 0x84D9, + eGL_TEXTURE26 = 0x84DA, + eGL_TEXTURE26_ARB = 0x84DA, + eGL_TEXTURE27 = 0x84DB, + eGL_TEXTURE27_ARB = 0x84DB, + eGL_TEXTURE28 = 0x84DC, + eGL_TEXTURE28_ARB = 0x84DC, + eGL_TEXTURE29 = 0x84DD, + eGL_TEXTURE29_ARB = 0x84DD, + eGL_TEXTURE2_ARB = 0x84C2, + eGL_TEXTURE3 = 0x84C3, + eGL_TEXTURE30 = 0x84DE, + eGL_TEXTURE30_ARB = 0x84DE, + eGL_TEXTURE31 = 0x84DF, + eGL_TEXTURE31_ARB = 0x84DF, + eGL_TEXTURE3_ARB = 0x84C3, + eGL_TEXTURE4 = 0x84C4, + eGL_TEXTURE4_ARB = 0x84C4, + eGL_TEXTURE5 = 0x84C5, + eGL_TEXTURE5_ARB = 0x84C5, + eGL_TEXTURE6 = 0x84C6, + eGL_TEXTURE6_ARB = 0x84C6, + eGL_TEXTURE7 = 0x84C7, + eGL_TEXTURE7_ARB = 0x84C7, + eGL_TEXTURE8 = 0x84C8, + eGL_TEXTURE8_ARB = 0x84C8, + eGL_TEXTURE9 = 0x84C9, + eGL_TEXTURE9_ARB = 0x84C9, + eGL_TEXTURE_1D = 0x0DE0, + eGL_TEXTURE_1D_ARRAY = 0x8C18, + eGL_TEXTURE_1D_ARRAY_EXT = 0x8C18, + eGL_TEXTURE_1D_BINDING_EXT = 0x8068, + eGL_TEXTURE_1D_STACK_BINDING_MESAX = 0x875D, + eGL_TEXTURE_1D_STACK_MESAX = 0x8759, + eGL_TEXTURE_2D = 0x0DE1, + eGL_TEXTURE_2D_ARRAY = 0x8C1A, + eGL_TEXTURE_2D_ARRAY_EXT = 0x8C1A, + eGL_TEXTURE_2D_BINDING_EXT = 0x8069, + eGL_TEXTURE_2D_MULTISAMPLE = 0x9100, + eGL_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x9102, + eGL_TEXTURE_2D_STACK_BINDING_MESAX = 0x875E, + eGL_TEXTURE_2D_STACK_MESAX = 0x875A, + eGL_TEXTURE_3D = 0x806F, + eGL_TEXTURE_3D_BINDING_EXT = 0x806A, + eGL_TEXTURE_3D_EXT = 0x806F, + eGL_TEXTURE_4DSIZE_SGIS = 0x8136, + eGL_TEXTURE_4D_BINDING_SGIS = 0x814F, + eGL_TEXTURE_4D_SGIS = 0x8134, + eGL_TEXTURE_ALPHA_SIZE = 0x805F, + eGL_TEXTURE_ALPHA_SIZE_EXT = 0x805F, + eGL_TEXTURE_ALPHA_TYPE = 0x8C13, + eGL_TEXTURE_ALPHA_TYPE_ARB = 0x8C13, + eGL_TEXTURE_APPLICATION_MODE_EXT = 0x834F, + eGL_TEXTURE_BASE_LEVEL = 0x813C, + eGL_TEXTURE_BASE_LEVEL_SGIS = 0x813C, + eGL_TEXTURE_BINDING_1D = 0x8068, + eGL_TEXTURE_BINDING_1D_ARRAY = 0x8C1C, + eGL_TEXTURE_BINDING_1D_ARRAY_EXT = 0x8C1C, + eGL_TEXTURE_BINDING_2D = 0x8069, + eGL_TEXTURE_BINDING_2D_ARRAY = 0x8C1D, + eGL_TEXTURE_BINDING_2D_ARRAY_EXT = 0x8C1D, + eGL_TEXTURE_BINDING_2D_MULTISAMPLE = 0x9104, + eGL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 0x9105, + eGL_TEXTURE_BINDING_3D = 0x806A, + eGL_TEXTURE_BINDING_BUFFER = 0x8C2C, + eGL_TEXTURE_BINDING_BUFFER_ARB = 0x8C2C, + eGL_TEXTURE_BINDING_BUFFER_EXT = 0x8C2C, + eGL_TEXTURE_BINDING_CUBE_MAP = 0x8514, + eGL_TEXTURE_BINDING_CUBE_MAP_ARB = 0x8514, + eGL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 0x900A, + eGL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB = 0x900A, + eGL_TEXTURE_BINDING_CUBE_MAP_EXT = 0x8514, + eGL_TEXTURE_BINDING_RECTANGLE = 0x84F6, + eGL_TEXTURE_BINDING_RECTANGLE_ARB = 0x84F6, + eGL_TEXTURE_BINDING_RECTANGLE_NV = 0x84F6, + eGL_TEXTURE_BINDING_RENDERBUFFER_NV = 0x8E53, + eGL_TEXTURE_BLUE_SIZE = 0x805E, + eGL_TEXTURE_BLUE_SIZE_EXT = 0x805E, + eGL_TEXTURE_BLUE_TYPE = 0x8C12, + eGL_TEXTURE_BLUE_TYPE_ARB = 0x8C12, + eGL_TEXTURE_BORDER_COLOR = 0x1004, + eGL_TEXTURE_BORDER_VALUES_NV = 0x871A, + eGL_TEXTURE_BUFFER = 0x8C2A, + eGL_TEXTURE_BUFFER_ARB = 0x8C2A, + eGL_TEXTURE_BUFFER_BINDING = 0x8C2A, + eGL_TEXTURE_BUFFER_DATA_STORE_BINDING = 0x8C2D, + eGL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB = 0x8C2D, + eGL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT = 0x8C2D, + eGL_TEXTURE_BUFFER_EXT = 0x8C2A, + eGL_TEXTURE_BUFFER_FORMAT_ARB = 0x8C2E, + eGL_TEXTURE_BUFFER_FORMAT_EXT = 0x8C2E, + eGL_TEXTURE_BUFFER_OFFSET = 0x919D, + eGL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 0x919F, + eGL_TEXTURE_BUFFER_SIZE = 0x919E, + eGL_TEXTURE_CLIPMAP_CENTER_SGIX = 0x8171, + eGL_TEXTURE_CLIPMAP_DEPTH_SGIX = 0x8176, + eGL_TEXTURE_CLIPMAP_FRAME_SGIX = 0x8172, + eGL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX = 0x8175, + eGL_TEXTURE_CLIPMAP_OFFSET_SGIX = 0x8173, + eGL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX = 0x8174, + eGL_TEXTURE_COLOR_SAMPLES_NV = 0x9046, + eGL_TEXTURE_COLOR_TABLE_SGI = 0x80BC, + eGL_TEXTURE_COLOR_WRITEMASK_SGIS = 0x81EF, + eGL_TEXTURE_COMPARE_FAIL_VALUE_ARB = 0x80BF, + eGL_TEXTURE_COMPARE_FUNC = 0x884D, + eGL_TEXTURE_COMPARE_FUNC_ARB = 0x884D, + eGL_TEXTURE_COMPARE_MODE = 0x884C, + eGL_TEXTURE_COMPARE_MODE_ARB = 0x884C, + eGL_TEXTURE_COMPARE_OPERATOR_SGIX = 0x819B, + eGL_TEXTURE_COMPARE_SGIX = 0x819A, + eGL_TEXTURE_COMPRESSED = 0x86A1, + eGL_TEXTURE_COMPRESSED_ARB = 0x86A1, + eGL_TEXTURE_COMPRESSED_BLOCK_HEIGHT = 0x82B2, + eGL_TEXTURE_COMPRESSED_BLOCK_SIZE = 0x82B3, + eGL_TEXTURE_COMPRESSED_BLOCK_WIDTH = 0x82B1, + eGL_TEXTURE_COMPRESSED_IMAGE_SIZE = 0x86A0, + eGL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB = 0x86A0, + eGL_TEXTURE_COMPRESSION_HINT = 0x84EF, + eGL_TEXTURE_COMPRESSION_HINT_ARB = 0x84EF, + eGL_TEXTURE_CONSTANT_DATA_SUNX = 0x81D6, + eGL_TEXTURE_COORD_ARRAY_ADDRESS_NV = 0x8F25, + eGL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x889A, + eGL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB = 0x889A, + eGL_TEXTURE_COORD_ARRAY_COUNT_EXT = 0x808B, + eGL_TEXTURE_COORD_ARRAY_EXT = 0x8078, + eGL_TEXTURE_COORD_ARRAY_LENGTH_NV = 0x8F2F, + eGL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL = 0x83F8, + eGL_TEXTURE_COORD_ARRAY_POINTER_EXT = 0x8092, + eGL_TEXTURE_COORD_ARRAY_SIZE_EXT = 0x8088, + eGL_TEXTURE_COORD_ARRAY_STRIDE_EXT = 0x808A, + eGL_TEXTURE_COORD_ARRAY_TYPE_EXT = 0x8089, + eGL_TEXTURE_COORD_NV = 0x8C79, + eGL_TEXTURE_COVERAGE_SAMPLES_NV = 0x9045, + eGL_TEXTURE_CUBE_MAP = 0x8513, + eGL_TEXTURE_CUBE_MAP_ARB = 0x8513, + eGL_TEXTURE_CUBE_MAP_ARRAY = 0x9009, + eGL_TEXTURE_CUBE_MAP_ARRAY_ARB = 0x9009, + eGL_TEXTURE_CUBE_MAP_EXT = 0x8513, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = 0x8516, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT = 0x8516, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = 0x8518, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT = 0x8518, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = 0x851A, + eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT = 0x851A, + eGL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515, + eGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = 0x8515, + eGL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT = 0x8515, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = 0x8517, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT = 0x8517, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = 0x8519, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT = 0x8519, + eGL_TEXTURE_CUBE_MAP_SEAMLESS = 0x884F, + eGL_TEXTURE_DEFORMATION_BIT_SGIX = 0x00000001, + eGL_TEXTURE_DEFORMATION_SGIX = 0x8195, + eGL_TEXTURE_DEPTH = 0x8071, + eGL_TEXTURE_DEPTH_EXT = 0x8071, + eGL_TEXTURE_DEPTH_SIZE = 0x884A, + eGL_TEXTURE_DEPTH_SIZE_ARB = 0x884A, + eGL_TEXTURE_DEPTH_TYPE = 0x8C16, + eGL_TEXTURE_DEPTH_TYPE_ARB = 0x8C16, + eGL_TEXTURE_DS_SIZE_NV = 0x871D, + eGL_TEXTURE_DT_SIZE_NV = 0x871E, + eGL_TEXTURE_ENV_BIAS_SGIX = 0x80BE, + eGL_TEXTURE_FETCH_BARRIER_BIT = 0x00000008, + eGL_TEXTURE_FETCH_BARRIER_BIT_EXT = 0x00000008, + eGL_TEXTURE_FILTER4_SIZE_SGIS = 0x8147, + eGL_TEXTURE_FILTER_CONTROL = 0x8500, + eGL_TEXTURE_FILTER_CONTROL_EXT = 0x8500, + eGL_TEXTURE_FIXED_SAMPLE_LOCATIONS = 0x9107, + eGL_TEXTURE_FLOAT_COMPONENTS_NV = 0x888C, + eGL_TEXTURE_FREE_MEMORY_ATI = 0x87FC, + eGL_TEXTURE_GATHER = 0x82A2, + eGL_TEXTURE_GATHER_SHADOW = 0x82A3, + eGL_TEXTURE_GEQUAL_R_SGIX = 0x819D, + eGL_TEXTURE_GREEN_SIZE = 0x805D, + eGL_TEXTURE_GREEN_SIZE_EXT = 0x805D, + eGL_TEXTURE_GREEN_TYPE = 0x8C11, + eGL_TEXTURE_GREEN_TYPE_ARB = 0x8C11, + eGL_TEXTURE_HEIGHT = 0x1001, + eGL_TEXTURE_HI_SIZE_NV = 0x871B, + eGL_TEXTURE_IMAGE_FORMAT = 0x828F, + eGL_TEXTURE_IMAGE_TYPE = 0x8290, + eGL_TEXTURE_IMMUTABLE_FORMAT = 0x912F, + eGL_TEXTURE_IMMUTABLE_LEVELS = 0x82DF, + eGL_TEXTURE_INDEX_SIZE_EXT = 0x80ED, + eGL_TEXTURE_INTENSITY_SIZE_EXT = 0x8061, + eGL_TEXTURE_INTENSITY_TYPE = 0x8C15, + eGL_TEXTURE_INTENSITY_TYPE_ARB = 0x8C15, + eGL_TEXTURE_INTERNAL_FORMAT = 0x1003, + eGL_TEXTURE_LEQUAL_R_SGIX = 0x819C, + eGL_TEXTURE_LIGHTING_MODE_HP = 0x8167, + eGL_TEXTURE_LIGHT_EXT = 0x8350, + eGL_TEXTURE_LOD_BIAS = 0x8501, + eGL_TEXTURE_LOD_BIAS_EXT = 0x8501, + eGL_TEXTURE_LOD_BIAS_R_SGIX = 0x8190, + eGL_TEXTURE_LOD_BIAS_S_SGIX = 0x818E, + eGL_TEXTURE_LOD_BIAS_T_SGIX = 0x818F, + eGL_TEXTURE_LO_SIZE_NV = 0x871C, + eGL_TEXTURE_LUMINANCE_SIZE_EXT = 0x8060, + eGL_TEXTURE_LUMINANCE_TYPE = 0x8C14, + eGL_TEXTURE_LUMINANCE_TYPE_ARB = 0x8C14, + eGL_TEXTURE_MAG_FILTER = 0x2800, + eGL_TEXTURE_MAG_SIZE_NV = 0x871F, + eGL_TEXTURE_MATERIAL_FACE_EXT = 0x8351, + eGL_TEXTURE_MATERIAL_PARAMETER_EXT = 0x8352, + eGL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE, + eGL_TEXTURE_MAX_CLAMP_R_SGIX = 0x836B, + eGL_TEXTURE_MAX_CLAMP_S_SGIX = 0x8369, + eGL_TEXTURE_MAX_CLAMP_T_SGIX = 0x836A, + eGL_TEXTURE_MAX_LEVEL = 0x813D, + eGL_TEXTURE_MAX_LEVEL_SGIS = 0x813D, + eGL_TEXTURE_MAX_LOD = 0x813B, + eGL_TEXTURE_MAX_LOD_SGIS = 0x813B, + eGL_TEXTURE_MEMORY_LAYOUT_INTEL = 0x83FF, + eGL_TEXTURE_MIN_FILTER = 0x2801, + eGL_TEXTURE_MIN_LOD = 0x813A, + eGL_TEXTURE_MIN_LOD_SGIS = 0x813A, + eGL_TEXTURE_MULTI_BUFFER_HINT_SGIX = 0x812E, + eGL_TEXTURE_NORMAL_EXT = 0x85AF, + eGL_TEXTURE_POST_SPECULAR_HP = 0x8168, + eGL_TEXTURE_PRE_SPECULAR_HP = 0x8169, + eGL_TEXTURE_PRIORITY_EXT = 0x8066, + eGL_TEXTURE_RANGE_LENGTH_APPLE = 0x85B7, + eGL_TEXTURE_RANGE_POINTER_APPLE = 0x85B8, + eGL_TEXTURE_RECTANGLE = 0x84F5, + eGL_TEXTURE_RECTANGLE_ARB = 0x84F5, + eGL_TEXTURE_RECTANGLE_NV = 0x84F5, + eGL_TEXTURE_RED_SIZE = 0x805C, + eGL_TEXTURE_RED_SIZE_EXT = 0x805C, + eGL_TEXTURE_RED_TYPE = 0x8C10, + eGL_TEXTURE_RED_TYPE_ARB = 0x8C10, + eGL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV = 0x8E54, + eGL_TEXTURE_RENDERBUFFER_NV = 0x8E55, + eGL_TEXTURE_RESIDENT_EXT = 0x8067, + eGL_TEXTURE_SAMPLES = 0x9106, + eGL_TEXTURE_SHADER_NV = 0x86DE, + eGL_TEXTURE_SHADOW = 0x82A1, + eGL_TEXTURE_SHARED_SIZE = 0x8C3F, + eGL_TEXTURE_SHARED_SIZE_EXT = 0x8C3F, + eGL_TEXTURE_SPARSE_ARB = 0x91A6, + eGL_TEXTURE_SRGB_DECODE_EXT = 0x8A48, + eGL_TEXTURE_STENCIL_SIZE = 0x88F1, + eGL_TEXTURE_STENCIL_SIZE_EXT = 0x88F1, + eGL_TEXTURE_STORAGE_HINT_APPLE = 0x85BC, + eGL_TEXTURE_STORAGE_SPARSE_BIT_AMD = 0x00000001, + eGL_TEXTURE_SWIZZLE_A = 0x8E45, + eGL_TEXTURE_SWIZZLE_A_EXT = 0x8E45, + eGL_TEXTURE_SWIZZLE_B = 0x8E44, + eGL_TEXTURE_SWIZZLE_B_EXT = 0x8E44, + eGL_TEXTURE_SWIZZLE_G = 0x8E43, + eGL_TEXTURE_SWIZZLE_G_EXT = 0x8E43, + eGL_TEXTURE_SWIZZLE_R = 0x8E42, + eGL_TEXTURE_SWIZZLE_RGBA = 0x8E46, + eGL_TEXTURE_SWIZZLE_RGBA_EXT = 0x8E46, + eGL_TEXTURE_SWIZZLE_R_EXT = 0x8E42, + eGL_TEXTURE_TOO_LARGE_EXT = 0x8065, + eGL_TEXTURE_UNSIGNED_REMAP_MODE_NV = 0x888F, + eGL_TEXTURE_UPDATE_BARRIER_BIT = 0x00000100, + eGL_TEXTURE_UPDATE_BARRIER_BIT_EXT = 0x00000100, + eGL_TEXTURE_VIEW = 0x82B5, + eGL_TEXTURE_VIEW_MIN_LAYER = 0x82DD, + eGL_TEXTURE_VIEW_MIN_LEVEL = 0x82DB, + eGL_TEXTURE_VIEW_NUM_LAYERS = 0x82DE, + eGL_TEXTURE_VIEW_NUM_LEVELS = 0x82DC, + eGL_TEXTURE_WIDTH = 0x1000, + eGL_TEXTURE_WRAP_Q_SGIS = 0x8137, + eGL_TEXTURE_WRAP_R = 0x8072, + eGL_TEXTURE_WRAP_R_EXT = 0x8072, + eGL_TEXTURE_WRAP_S = 0x2802, + eGL_TEXTURE_WRAP_T = 0x2803, + eGL_TEXT_FRAGMENT_SHADER_ATI = 0x8200, + eGL_TIMEOUT_EXPIRED = 0x911B, + eGL_TIMESTAMP = 0x8E28, + eGL_TIME_ELAPSED = 0x88BF, + eGL_TIME_ELAPSED_EXT = 0x88BF, + eGL_TOP_LEVEL_ARRAY_SIZE = 0x930C, + eGL_TOP_LEVEL_ARRAY_STRIDE = 0x930D, + eGL_TRACK_MATRIX_NV = 0x8648, + eGL_TRACK_MATRIX_TRANSFORM_NV = 0x8649, + eGL_TRANSFORM_FEEDBACK = 0x8E22, + eGL_TRANSFORM_FEEDBACK_ACTIVE = 0x8E24, + eGL_TRANSFORM_FEEDBACK_ATTRIBS_NV = 0x8C7E, + eGL_TRANSFORM_FEEDBACK_BARRIER_BIT = 0x00000800, + eGL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT = 0x00000800, + eGL_TRANSFORM_FEEDBACK_BINDING = 0x8E25, + eGL_TRANSFORM_FEEDBACK_BINDING_NV = 0x8E25, + eGL_TRANSFORM_FEEDBACK_BUFFER = 0x8C8E, + eGL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE = 0x8E24, + eGL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV = 0x8E24, + eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x8C8F, + eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT = 0x8C8F, + eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV = 0x8C8F, + eGL_TRANSFORM_FEEDBACK_BUFFER_EXT = 0x8C8E, + eGL_TRANSFORM_FEEDBACK_BUFFER_INDEX = 0x934B, + eGL_TRANSFORM_FEEDBACK_BUFFER_MODE = 0x8C7F, + eGL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT = 0x8C7F, + eGL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV = 0x8C7F, + eGL_TRANSFORM_FEEDBACK_BUFFER_NV = 0x8C8E, + eGL_TRANSFORM_FEEDBACK_BUFFER_PAUSED = 0x8E23, + eGL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV = 0x8E23, + eGL_TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x8C85, + eGL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT = 0x8C85, + eGL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV = 0x8C85, + eGL_TRANSFORM_FEEDBACK_BUFFER_START = 0x8C84, + eGL_TRANSFORM_FEEDBACK_BUFFER_START_EXT = 0x8C84, + eGL_TRANSFORM_FEEDBACK_BUFFER_START_NV = 0x8C84, + eGL_TRANSFORM_FEEDBACK_BUFFER_STRIDE = 0x934C, + eGL_TRANSFORM_FEEDBACK_NV = 0x8E22, + eGL_TRANSFORM_FEEDBACK_PAUSED = 0x8E23, + eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 0x8C88, + eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT = 0x8C88, + eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV = 0x8C88, + eGL_TRANSFORM_FEEDBACK_RECORD_NV = 0x8C86, + eGL_TRANSFORM_FEEDBACK_VARYING = 0x92F4, + eGL_TRANSFORM_FEEDBACK_VARYINGS = 0x8C83, + eGL_TRANSFORM_FEEDBACK_VARYINGS_EXT = 0x8C83, + eGL_TRANSFORM_FEEDBACK_VARYINGS_NV = 0x8C83, + eGL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = 0x8C76, + eGL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT = 0x8C76, + eGL_TRANSFORM_HINT_APPLE = 0x85B1, + eGL_TRANSLATE_2D_NV = 0x9090, + eGL_TRANSLATE_3D_NV = 0x9091, + eGL_TRANSLATE_X_NV = 0x908E, + eGL_TRANSLATE_Y_NV = 0x908F, + eGL_TRANSPOSE_AFFINE_2D_NV = 0x9096, + eGL_TRANSPOSE_AFFINE_3D_NV = 0x9098, + eGL_TRANSPOSE_COLOR_MATRIX = 0x84E6, + eGL_TRANSPOSE_COLOR_MATRIX_ARB = 0x84E6, + eGL_TRANSPOSE_CURRENT_MATRIX_ARB = 0x88B7, + eGL_TRANSPOSE_MODELVIEW_MATRIX = 0x84E3, + eGL_TRANSPOSE_MODELVIEW_MATRIX_ARB = 0x84E3, + eGL_TRANSPOSE_NV = 0x862C, + eGL_TRANSPOSE_PROGRAM_MATRIX_EXT = 0x8E2E, + eGL_TRANSPOSE_PROJECTION_MATRIX = 0x84E4, + eGL_TRANSPOSE_PROJECTION_MATRIX_ARB = 0x84E4, + eGL_TRANSPOSE_TEXTURE_MATRIX = 0x84E5, + eGL_TRANSPOSE_TEXTURE_MATRIX_ARB = 0x84E5, + eGL_TRIANGLES = 0x0004, + eGL_TRIANGLES_ADJACENCY = 0x000C, + eGL_TRIANGLES_ADJACENCY_ARB = 0x000C, + eGL_TRIANGLES_ADJACENCY_EXT = 0x000C, + eGL_TRIANGLE_FAN = 0x0006, + eGL_TRIANGLE_LIST_SUN = 0x81D7, + eGL_TRIANGLE_MESH_SUN = 0x8615, + eGL_TRIANGLE_STRIP = 0x0005, + eGL_TRIANGLE_STRIP_ADJACENCY = 0x000D, + eGL_TRIANGLE_STRIP_ADJACENCY_ARB = 0x000D, + eGL_TRIANGLE_STRIP_ADJACENCY_EXT = 0x000D, + eGL_TRIANGULAR_NV = 0x90A5, + eGL_TYPE = 0x92FA, + eGL_UNCORRELATED_NV = 0x9282, + eGL_UNDEFINED_APPLE = 0x8A1C, + eGL_UNDEFINED_VERTEX = 0x8260, + eGL_UNIFORM = 0x92E1, + eGL_UNIFORM_ARRAY_STRIDE = 0x8A3C, + eGL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX = 0x92DA, + eGL_UNIFORM_BARRIER_BIT = 0x00000004, + eGL_UNIFORM_BARRIER_BIT_EXT = 0x00000004, + eGL_UNIFORM_BLOCK = 0x92E2, + eGL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x8A42, + eGL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8A43, + eGL_UNIFORM_BLOCK_BINDING = 0x8A3F, + eGL_UNIFORM_BLOCK_DATA_SIZE = 0x8A40, + eGL_UNIFORM_BLOCK_INDEX = 0x8A3A, + eGL_UNIFORM_BLOCK_NAME_LENGTH = 0x8A41, + eGL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER = 0x90EC, + eGL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46, + eGL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER = 0x8A45, + eGL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER = 0x84F0, + eGL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x84F1, + eGL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8A44, + eGL_UNIFORM_BUFFER = 0x8A11, + eGL_UNIFORM_BUFFER_BINDING = 0x8A28, + eGL_UNIFORM_BUFFER_BINDING_EXT = 0x8DEF, + eGL_UNIFORM_BUFFER_EXT = 0x8DEE, + eGL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34, + eGL_UNIFORM_BUFFER_SIZE = 0x8A2A, + eGL_UNIFORM_BUFFER_START = 0x8A29, + eGL_UNIFORM_IS_ROW_MAJOR = 0x8A3E, + eGL_UNIFORM_MATRIX_STRIDE = 0x8A3D, + eGL_UNIFORM_NAME_LENGTH = 0x8A39, + eGL_UNIFORM_OFFSET = 0x8A3B, + eGL_UNIFORM_SIZE = 0x8A38, + eGL_UNIFORM_TYPE = 0x8A37, + eGL_UNKNOWN_CONTEXT_RESET_ARB = 0x8255, + eGL_UNPACK_ALIGNMENT = 0x0CF5, + eGL_UNPACK_CLIENT_STORAGE_APPLE = 0x85B2, + eGL_UNPACK_CMYK_HINT_EXT = 0x800F, + eGL_UNPACK_COMPRESSED_BLOCK_DEPTH = 0x9129, + eGL_UNPACK_COMPRESSED_BLOCK_HEIGHT = 0x9128, + eGL_UNPACK_COMPRESSED_BLOCK_SIZE = 0x912A, + eGL_UNPACK_COMPRESSED_BLOCK_WIDTH = 0x9127, + eGL_UNPACK_CONSTANT_DATA_SUNX = 0x81D5, + eGL_UNPACK_IMAGE_DEPTH_SGIS = 0x8133, + eGL_UNPACK_IMAGE_HEIGHT = 0x806E, + eGL_UNPACK_IMAGE_HEIGHT_EXT = 0x806E, + eGL_UNPACK_LSB_FIRST = 0x0CF1, + eGL_UNPACK_RESAMPLE_OML = 0x8985, + eGL_UNPACK_RESAMPLE_SGIX = 0x842D, + eGL_UNPACK_ROW_BYTES_APPLE = 0x8A16, + eGL_UNPACK_ROW_LENGTH = 0x0CF2, + eGL_UNPACK_SKIP_IMAGES = 0x806D, + eGL_UNPACK_SKIP_IMAGES_EXT = 0x806D, + eGL_UNPACK_SKIP_PIXELS = 0x0CF4, + eGL_UNPACK_SKIP_ROWS = 0x0CF3, + eGL_UNPACK_SKIP_VOLUMES_SGIS = 0x8132, + eGL_UNPACK_SUBSAMPLE_RATE_SGIX = 0x85A1, + eGL_UNPACK_SWAP_BYTES = 0x0CF0, + eGL_UNSIGNALED = 0x9118, + eGL_UNSIGNED_BYTE = 0x1401, + eGL_UNSIGNED_BYTE_2_3_3_REV = 0x8362, + eGL_UNSIGNED_BYTE_3_3_2 = 0x8032, + eGL_UNSIGNED_BYTE_3_3_2_EXT = 0x8032, + eGL_UNSIGNED_IDENTITY_NV = 0x8536, + eGL_UNSIGNED_INT = 0x1405, + eGL_UNSIGNED_INT16_NV = 0x8FF0, + eGL_UNSIGNED_INT16_VEC2_NV = 0x8FF1, + eGL_UNSIGNED_INT16_VEC3_NV = 0x8FF2, + eGL_UNSIGNED_INT16_VEC4_NV = 0x8FF3, + eGL_UNSIGNED_INT64_AMD = 0x8BC2, + eGL_UNSIGNED_INT64_ARB = 0x140F, + eGL_UNSIGNED_INT64_NV = 0x140F, + eGL_UNSIGNED_INT64_VEC2_NV = 0x8FF5, + eGL_UNSIGNED_INT64_VEC3_NV = 0x8FF6, + eGL_UNSIGNED_INT64_VEC4_NV = 0x8FF7, + eGL_UNSIGNED_INT8_NV = 0x8FEC, + eGL_UNSIGNED_INT8_VEC2_NV = 0x8FED, + eGL_UNSIGNED_INT8_VEC3_NV = 0x8FEE, + eGL_UNSIGNED_INT8_VEC4_NV = 0x8FEF, + eGL_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B, + eGL_UNSIGNED_INT_10F_11F_11F_REV_EXT = 0x8C3B, + eGL_UNSIGNED_INT_10_10_10_2 = 0x8036, + eGL_UNSIGNED_INT_10_10_10_2_EXT = 0x8036, + eGL_UNSIGNED_INT_24_8 = 0x84FA, + eGL_UNSIGNED_INT_24_8_EXT = 0x84FA, + eGL_UNSIGNED_INT_24_8_NV = 0x84FA, + eGL_UNSIGNED_INT_2_10_10_10_REV = 0x8368, + eGL_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E, + eGL_UNSIGNED_INT_5_9_9_9_REV_EXT = 0x8C3E, + eGL_UNSIGNED_INT_8_8_8_8 = 0x8035, + eGL_UNSIGNED_INT_8_8_8_8_EXT = 0x8035, + eGL_UNSIGNED_INT_8_8_8_8_REV = 0x8367, + eGL_UNSIGNED_INT_8_8_S8_S8_REV_NV = 0x86DB, + eGL_UNSIGNED_INT_ATOMIC_COUNTER = 0x92DB, + eGL_UNSIGNED_INT_IMAGE_1D = 0x9062, + eGL_UNSIGNED_INT_IMAGE_1D_ARRAY = 0x9068, + eGL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT = 0x9068, + eGL_UNSIGNED_INT_IMAGE_1D_EXT = 0x9062, + eGL_UNSIGNED_INT_IMAGE_2D = 0x9063, + eGL_UNSIGNED_INT_IMAGE_2D_ARRAY = 0x9069, + eGL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT = 0x9069, + eGL_UNSIGNED_INT_IMAGE_2D_EXT = 0x9063, + eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE = 0x906B, + eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x906C, + eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT = 0x906C, + eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT = 0x906B, + eGL_UNSIGNED_INT_IMAGE_2D_RECT = 0x9065, + eGL_UNSIGNED_INT_IMAGE_2D_RECT_EXT = 0x9065, + eGL_UNSIGNED_INT_IMAGE_3D = 0x9064, + eGL_UNSIGNED_INT_IMAGE_3D_EXT = 0x9064, + eGL_UNSIGNED_INT_IMAGE_BUFFER = 0x9067, + eGL_UNSIGNED_INT_IMAGE_BUFFER_EXT = 0x9067, + eGL_UNSIGNED_INT_IMAGE_CUBE = 0x9066, + eGL_UNSIGNED_INT_IMAGE_CUBE_EXT = 0x9066, + eGL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 0x906A, + eGL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT = 0x906A, + eGL_UNSIGNED_INT_S8_S8_8_8_NV = 0x86DA, + eGL_UNSIGNED_INT_SAMPLER_1D = 0x8DD1, + eGL_UNSIGNED_INT_SAMPLER_1D_ARRAY = 0x8DD6, + eGL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT = 0x8DD6, + eGL_UNSIGNED_INT_SAMPLER_1D_EXT = 0x8DD1, + eGL_UNSIGNED_INT_SAMPLER_2D = 0x8DD2, + eGL_UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7, + eGL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT = 0x8DD7, + eGL_UNSIGNED_INT_SAMPLER_2D_EXT = 0x8DD2, + eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 0x910A, + eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910D, + eGL_UNSIGNED_INT_SAMPLER_2D_RECT = 0x8DD5, + eGL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT = 0x8DD5, + eGL_UNSIGNED_INT_SAMPLER_3D = 0x8DD3, + eGL_UNSIGNED_INT_SAMPLER_3D_EXT = 0x8DD3, + eGL_UNSIGNED_INT_SAMPLER_BUFFER = 0x8DD8, + eGL_UNSIGNED_INT_SAMPLER_BUFFER_AMD = 0x9003, + eGL_UNSIGNED_INT_SAMPLER_BUFFER_EXT = 0x8DD8, + eGL_UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4, + eGL_UNSIGNED_INT_SAMPLER_CUBE_EXT = 0x8DD4, + eGL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 0x900F, + eGL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB = 0x900F, + eGL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV = 0x8E58, + eGL_UNSIGNED_INT_VEC2 = 0x8DC6, + eGL_UNSIGNED_INT_VEC2_EXT = 0x8DC6, + eGL_UNSIGNED_INT_VEC3 = 0x8DC7, + eGL_UNSIGNED_INT_VEC3_EXT = 0x8DC7, + eGL_UNSIGNED_INT_VEC4 = 0x8DC8, + eGL_UNSIGNED_INT_VEC4_EXT = 0x8DC8, + eGL_UNSIGNED_INVERT_NV = 0x8537, + eGL_UNSIGNED_NORMALIZED = 0x8C17, + eGL_UNSIGNED_NORMALIZED_ARB = 0x8C17, + eGL_UNSIGNED_SHORT = 0x1403, + eGL_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366, + eGL_UNSIGNED_SHORT_4_4_4_4 = 0x8033, + eGL_UNSIGNED_SHORT_4_4_4_4_EXT = 0x8033, + eGL_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365, + eGL_UNSIGNED_SHORT_5_5_5_1 = 0x8034, + eGL_UNSIGNED_SHORT_5_5_5_1_EXT = 0x8034, + eGL_UNSIGNED_SHORT_5_6_5 = 0x8363, + eGL_UNSIGNED_SHORT_5_6_5_REV = 0x8364, + eGL_UNSIGNED_SHORT_8_8_APPLE = 0x85BA, + eGL_UNSIGNED_SHORT_8_8_MESA = 0x85BA, + eGL_UNSIGNED_SHORT_8_8_REV_APPLE = 0x85BB, + eGL_UNSIGNED_SHORT_8_8_REV_MESA = 0x85BB, + eGL_UPPER_LEFT = 0x8CA2, + eGL_USE_MISSING_GLYPH_NV = 0x90AA, + eGL_UTF16_NV = 0x909B, + eGL_UTF8_NV = 0x909A, + eGL_VALIDATE_STATUS = 0x8B83, + eGL_VARIABLE_A_NV = 0x8523, + eGL_VARIABLE_B_NV = 0x8524, + eGL_VARIABLE_C_NV = 0x8525, + eGL_VARIABLE_D_NV = 0x8526, + eGL_VARIABLE_E_NV = 0x8527, + eGL_VARIABLE_F_NV = 0x8528, + eGL_VARIABLE_G_NV = 0x8529, + eGL_VARIANT_ARRAY_EXT = 0x87E8, + eGL_VARIANT_ARRAY_POINTER_EXT = 0x87E9, + eGL_VARIANT_ARRAY_STRIDE_EXT = 0x87E6, + eGL_VARIANT_ARRAY_TYPE_EXT = 0x87E7, + eGL_VARIANT_DATATYPE_EXT = 0x87E5, + eGL_VARIANT_EXT = 0x87C1, + eGL_VARIANT_VALUE_EXT = 0x87E4, + eGL_VBO_FREE_MEMORY_ATI = 0x87FB, + eGL_VECTOR_EXT = 0x87BF, + eGL_VENDOR = 0x1F00, + eGL_VERSION = 0x1F02, + eGL_VERTEX23_BIT_PGI = 0x00000004, + eGL_VERTEX4_BIT_PGI = 0x00000008, + eGL_VERTEX_ARRAY = 0x8074, + eGL_VERTEX_ARRAY_ADDRESS_NV = 0x8F21, + eGL_VERTEX_ARRAY_BINDING = 0x85B5, + eGL_VERTEX_ARRAY_BINDING_APPLE = 0x85B5, + eGL_VERTEX_ARRAY_BUFFER_BINDING = 0x8896, + eGL_VERTEX_ARRAY_BUFFER_BINDING_ARB = 0x8896, + eGL_VERTEX_ARRAY_COUNT_EXT = 0x807D, + eGL_VERTEX_ARRAY_EXT = 0x8074, + eGL_VERTEX_ARRAY_LENGTH_NV = 0x8F2B, + eGL_VERTEX_ARRAY_OBJECT_AMD = 0x9154, + eGL_VERTEX_ARRAY_OBJECT_EXT = 0x9154, + eGL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL = 0x83F5, + eGL_VERTEX_ARRAY_POINTER_EXT = 0x808E, + eGL_VERTEX_ARRAY_RANGE_APPLE = 0x851D, + eGL_VERTEX_ARRAY_RANGE_LENGTH_APPLE = 0x851E, + eGL_VERTEX_ARRAY_RANGE_LENGTH_NV = 0x851E, + eGL_VERTEX_ARRAY_RANGE_NV = 0x851D, + eGL_VERTEX_ARRAY_RANGE_POINTER_APPLE = 0x8521, + eGL_VERTEX_ARRAY_RANGE_POINTER_NV = 0x8521, + eGL_VERTEX_ARRAY_RANGE_VALID_NV = 0x851F, + eGL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV = 0x8533, + eGL_VERTEX_ARRAY_SIZE_EXT = 0x807A, + eGL_VERTEX_ARRAY_STORAGE_HINT_APPLE = 0x851F, + eGL_VERTEX_ARRAY_STRIDE_EXT = 0x807C, + eGL_VERTEX_ARRAY_TYPE_EXT = 0x807B, + eGL_VERTEX_ATTRIB_ARRAY0_NV = 0x8650, + eGL_VERTEX_ATTRIB_ARRAY10_NV = 0x865A, + eGL_VERTEX_ATTRIB_ARRAY11_NV = 0x865B, + eGL_VERTEX_ATTRIB_ARRAY12_NV = 0x865C, + eGL_VERTEX_ATTRIB_ARRAY13_NV = 0x865D, + eGL_VERTEX_ATTRIB_ARRAY14_NV = 0x865E, + eGL_VERTEX_ATTRIB_ARRAY15_NV = 0x865F, + eGL_VERTEX_ATTRIB_ARRAY1_NV = 0x8651, + eGL_VERTEX_ATTRIB_ARRAY2_NV = 0x8652, + eGL_VERTEX_ATTRIB_ARRAY3_NV = 0x8653, + eGL_VERTEX_ATTRIB_ARRAY4_NV = 0x8654, + eGL_VERTEX_ATTRIB_ARRAY5_NV = 0x8655, + eGL_VERTEX_ATTRIB_ARRAY6_NV = 0x8656, + eGL_VERTEX_ATTRIB_ARRAY7_NV = 0x8657, + eGL_VERTEX_ATTRIB_ARRAY8_NV = 0x8658, + eGL_VERTEX_ATTRIB_ARRAY9_NV = 0x8659, + eGL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV = 0x8F20, + eGL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 0x00000001, + eGL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT = 0x00000001, + eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F, + eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB = 0x889F, + eGL_VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE, + eGL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB = 0x88FE, + eGL_VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622, + eGL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB = 0x8622, + eGL_VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD, + eGL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT = 0x88FD, + eGL_VERTEX_ATTRIB_ARRAY_INTEGER_NV = 0x88FD, + eGL_VERTEX_ATTRIB_ARRAY_LENGTH_NV = 0x8F2A, + eGL_VERTEX_ATTRIB_ARRAY_LONG = 0x874E, + eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A, + eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB = 0x886A, + eGL_VERTEX_ATTRIB_ARRAY_POINTER = 0x8645, + eGL_VERTEX_ATTRIB_ARRAY_POINTER_ARB = 0x8645, + eGL_VERTEX_ATTRIB_ARRAY_SIZE = 0x8623, + eGL_VERTEX_ATTRIB_ARRAY_SIZE_ARB = 0x8623, + eGL_VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624, + eGL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB = 0x8624, + eGL_VERTEX_ATTRIB_ARRAY_TYPE = 0x8625, + eGL_VERTEX_ATTRIB_ARRAY_TYPE_ARB = 0x8625, + eGL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV = 0x8F1E, + eGL_VERTEX_ATTRIB_BINDING = 0x82D4, + eGL_VERTEX_ATTRIB_MAP1_APPLE = 0x8A00, + eGL_VERTEX_ATTRIB_MAP1_COEFF_APPLE = 0x8A03, + eGL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE = 0x8A05, + eGL_VERTEX_ATTRIB_MAP1_ORDER_APPLE = 0x8A04, + eGL_VERTEX_ATTRIB_MAP1_SIZE_APPLE = 0x8A02, + eGL_VERTEX_ATTRIB_MAP2_APPLE = 0x8A01, + eGL_VERTEX_ATTRIB_MAP2_COEFF_APPLE = 0x8A07, + eGL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE = 0x8A09, + eGL_VERTEX_ATTRIB_MAP2_ORDER_APPLE = 0x8A08, + eGL_VERTEX_ATTRIB_MAP2_SIZE_APPLE = 0x8A06, + eGL_VERTEX_ATTRIB_RELATIVE_OFFSET = 0x82D5, + eGL_VERTEX_BINDING_BUFFER = 0x8F4F, + eGL_VERTEX_BINDING_DIVISOR = 0x82D6, + eGL_VERTEX_BINDING_OFFSET = 0x82D7, + eGL_VERTEX_BINDING_STRIDE = 0x82D8, + eGL_VERTEX_BLEND_ARB = 0x86A7, + eGL_VERTEX_CONSISTENT_HINT_PGI = 0x1A22B, + eGL_VERTEX_DATA_HINT_PGI = 0x1A22A, + eGL_VERTEX_ELEMENT_SWIZZLE_AMD = 0x91A4, + eGL_VERTEX_ID_NV = 0x8C7B, + eGL_VERTEX_ID_SWIZZLE_AMD = 0x91A5, + eGL_VERTEX_PRECLIP_HINT_SGIX = 0x83EF, + eGL_VERTEX_PRECLIP_SGIX = 0x83EE, + eGL_VERTEX_PROGRAM_ARB = 0x8620, + eGL_VERTEX_PROGRAM_BINDING_NV = 0x864A, + eGL_VERTEX_PROGRAM_NV = 0x8620, + eGL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV = 0x8DA2, + eGL_VERTEX_PROGRAM_POINT_SIZE = 0x8642, + eGL_VERTEX_PROGRAM_POINT_SIZE_ARB = 0x8642, + eGL_VERTEX_PROGRAM_POINT_SIZE_NV = 0x8642, + eGL_VERTEX_PROGRAM_TWO_SIDE = 0x8643, + eGL_VERTEX_PROGRAM_TWO_SIDE_ARB = 0x8643, + eGL_VERTEX_PROGRAM_TWO_SIDE_NV = 0x8643, + eGL_VERTEX_SHADER = 0x8B31, + eGL_VERTEX_SHADER_ARB = 0x8B31, + eGL_VERTEX_SHADER_BINDING_EXT = 0x8781, + eGL_VERTEX_SHADER_BIT = 0x00000001, + eGL_VERTEX_SHADER_EXT = 0x8780, + eGL_VERTEX_SHADER_INSTRUCTIONS_EXT = 0x87CF, + eGL_VERTEX_SHADER_INVARIANTS_EXT = 0x87D1, + eGL_VERTEX_SHADER_LOCALS_EXT = 0x87D3, + eGL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = 0x87D2, + eGL_VERTEX_SHADER_OPTIMIZED_EXT = 0x87D4, + eGL_VERTEX_SHADER_VARIANTS_EXT = 0x87D0, + eGL_VERTEX_SOURCE_ATI = 0x8774, + eGL_VERTEX_STATE_PROGRAM_NV = 0x8621, + eGL_VERTEX_STREAM0_ATI = 0x876C, + eGL_VERTEX_STREAM1_ATI = 0x876D, + eGL_VERTEX_STREAM2_ATI = 0x876E, + eGL_VERTEX_STREAM3_ATI = 0x876F, + eGL_VERTEX_STREAM4_ATI = 0x8770, + eGL_VERTEX_STREAM5_ATI = 0x8771, + eGL_VERTEX_STREAM6_ATI = 0x8772, + eGL_VERTEX_STREAM7_ATI = 0x8773, + eGL_VERTEX_SUBROUTINE = 0x92E8, + eGL_VERTEX_SUBROUTINE_UNIFORM = 0x92EE, + eGL_VERTEX_TEXTURE = 0x829B, + eGL_VERTEX_WEIGHTING_EXT = 0x8509, + eGL_VERTEX_WEIGHT_ARRAY_EXT = 0x850C, + eGL_VERTEX_WEIGHT_ARRAY_POINTER_EXT = 0x8510, + eGL_VERTEX_WEIGHT_ARRAY_SIZE_EXT = 0x850D, + eGL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT = 0x850F, + eGL_VERTEX_WEIGHT_ARRAY_TYPE_EXT = 0x850E, + eGL_VIBRANCE_BIAS_NV = 0x8719, + eGL_VIBRANCE_SCALE_NV = 0x8713, + eGL_VIDEO_BUFFER_BINDING_NV = 0x9021, + eGL_VIDEO_BUFFER_INTERNAL_FORMAT_NV = 0x902D, + eGL_VIDEO_BUFFER_NV = 0x9020, + eGL_VIDEO_BUFFER_PITCH_NV = 0x9028, + eGL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV = 0x903B, + eGL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV = 0x903A, + eGL_VIDEO_CAPTURE_FRAME_HEIGHT_NV = 0x9039, + eGL_VIDEO_CAPTURE_FRAME_WIDTH_NV = 0x9038, + eGL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV = 0x903C, + eGL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV = 0x9026, + eGL_VIDEO_COLOR_CONVERSION_MATRIX_NV = 0x9029, + eGL_VIDEO_COLOR_CONVERSION_MAX_NV = 0x902A, + eGL_VIDEO_COLOR_CONVERSION_MIN_NV = 0x902B, + eGL_VIDEO_COLOR_CONVERSION_OFFSET_NV = 0x902C, + eGL_VIEWPORT = 0x0BA2, + eGL_VIEWPORT_BOUNDS_RANGE = 0x825D, + eGL_VIEWPORT_INDEX_PROVOKING_VERTEX = 0x825F, + eGL_VIEWPORT_SUBPIXEL_BITS = 0x825C, + eGL_VIEW_CLASS_128_BITS = 0x82C4, + eGL_VIEW_CLASS_16_BITS = 0x82CA, + eGL_VIEW_CLASS_24_BITS = 0x82C9, + eGL_VIEW_CLASS_32_BITS = 0x82C8, + eGL_VIEW_CLASS_48_BITS = 0x82C7, + eGL_VIEW_CLASS_64_BITS = 0x82C6, + eGL_VIEW_CLASS_8_BITS = 0x82CB, + eGL_VIEW_CLASS_96_BITS = 0x82C5, + eGL_VIEW_CLASS_BPTC_FLOAT = 0x82D3, + eGL_VIEW_CLASS_BPTC_UNORM = 0x82D2, + eGL_VIEW_CLASS_RGTC1_RED = 0x82D0, + eGL_VIEW_CLASS_RGTC2_RG = 0x82D1, + eGL_VIEW_CLASS_S3TC_DXT1_RGB = 0x82CC, + eGL_VIEW_CLASS_S3TC_DXT1_RGBA = 0x82CD, + eGL_VIEW_CLASS_S3TC_DXT3_RGBA = 0x82CE, + eGL_VIEW_CLASS_S3TC_DXT5_RGBA = 0x82CF, + eGL_VIEW_COMPATIBILITY_CLASS = 0x82B6, + eGL_VIRTUAL_PAGE_SIZE_INDEX_ARB = 0x91A7, + eGL_VIRTUAL_PAGE_SIZE_X_AMD = 0x9195, + eGL_VIRTUAL_PAGE_SIZE_X_ARB = 0x9195, + eGL_VIRTUAL_PAGE_SIZE_Y_AMD = 0x9196, + eGL_VIRTUAL_PAGE_SIZE_Y_ARB = 0x9196, + eGL_VIRTUAL_PAGE_SIZE_Z_AMD = 0x9197, + eGL_VIRTUAL_PAGE_SIZE_Z_ARB = 0x9197, + eGL_VIVIDLIGHT_NV = 0x92A6, + eGL_VOLATILE_APPLE = 0x8A1A, + eGL_WAIT_FAILED = 0x911D, + eGL_WARPS_PER_SM_NV = 0x933A, + eGL_WARP_SIZE_NV = 0x9339, + eGL_WEIGHT_ARRAY_ARB = 0x86AD, + eGL_WEIGHT_ARRAY_BUFFER_BINDING = 0x889E, + eGL_WEIGHT_ARRAY_BUFFER_BINDING_ARB = 0x889E, + eGL_WEIGHT_ARRAY_POINTER_ARB = 0x86AC, + eGL_WEIGHT_ARRAY_SIZE_ARB = 0x86AB, + eGL_WEIGHT_ARRAY_STRIDE_ARB = 0x86AA, + eGL_WEIGHT_ARRAY_TYPE_ARB = 0x86A9, + eGL_WEIGHT_SUM_UNITY_ARB = 0x86A6, + eGL_WIDE_LINE_HINT_PGI = 0x1A222, + eGL_WRAP_BORDER_SUN = 0x81D4, + eGL_WRITE_DISCARD_NV = 0x88BE, + eGL_WRITE_ONLY = 0x88B9, + eGL_WRITE_ONLY_ARB = 0x88B9, + eGL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV = 0x887A, + eGL_WRITE_PIXEL_DATA_RANGE_NV = 0x8878, + eGL_WRITE_PIXEL_DATA_RANGE_POINTER_NV = 0x887C, + eGL_W_EXT = 0x87D8, + eGL_XOR = 0x1506, + eGL_XOR_NV = 0x1506, + eGL_X_EXT = 0x87D5, + eGL_YCBAYCR8A_4224_NV = 0x9032, + eGL_YCBCR_422_APPLE = 0x85B9, + eGL_YCBCR_MESA = 0x8757, + eGL_YCBYCR8_422_NV = 0x9031, + eGL_YCRCBA_SGIX = 0x8319, + eGL_YCRCB_422_SGIX = 0x81BB, + eGL_YCRCB_444_SGIX = 0x81BC, + eGL_YCRCB_SGIX = 0x8318, + eGL_Y_EXT = 0x87D6, + eGL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV = 0x9036, + eGL_Z4Y12Z4CB12Z4CR12_444_NV = 0x9037, + eGL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV = 0x9035, + eGL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV = 0x9034, + eGL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV = 0x9033, + eGL_ZERO_EXT = 0x87DD, + eGL_Z_EXT = 0x87D7, + eWGL_ACCELERATION_ARB = 0x2003, + eWGL_ACCELERATION_EXT = 0x2003, + eWGL_ACCESS_READ_ONLY_NV = 0x00000000, + eWGL_ACCESS_READ_WRITE_NV = 0x00000001, + eWGL_ACCESS_WRITE_DISCARD_NV = 0x00000002, + eWGL_ACCUM_ALPHA_BITS_ARB = 0x2021, + eWGL_ACCUM_ALPHA_BITS_EXT = 0x2021, + eWGL_ACCUM_BITS_ARB = 0x201D, + eWGL_ACCUM_BITS_EXT = 0x201D, + eWGL_ACCUM_BLUE_BITS_ARB = 0x2020, + eWGL_ACCUM_BLUE_BITS_EXT = 0x2020, + eWGL_ACCUM_GREEN_BITS_ARB = 0x201F, + eWGL_ACCUM_GREEN_BITS_EXT = 0x201F, + eWGL_ACCUM_RED_BITS_ARB = 0x201E, + eWGL_ACCUM_RED_BITS_EXT = 0x201E, + eWGL_ALPHA_BITS_ARB = 0x201B, + eWGL_ALPHA_BITS_EXT = 0x201B, + eWGL_ALPHA_SHIFT_ARB = 0x201C, + eWGL_ALPHA_SHIFT_EXT = 0x201C, + eWGL_AUX0_ARB = 0x2087, + eWGL_AUX1_ARB = 0x2088, + eWGL_AUX2_ARB = 0x2089, + eWGL_AUX3_ARB = 0x208A, + eWGL_AUX4_ARB = 0x208B, + eWGL_AUX5_ARB = 0x208C, + eWGL_AUX6_ARB = 0x208D, + eWGL_AUX7_ARB = 0x208E, + eWGL_AUX8_ARB = 0x208F, + eWGL_AUX9_ARB = 0x2090, + eWGL_AUX_BUFFERS_ARB = 0x2024, + eWGL_AUX_BUFFERS_EXT = 0x2024, + eWGL_BACK_COLOR_BUFFER_BIT_ARB = 0x00000002, + eWGL_BACK_LEFT_ARB = 0x2085, + eWGL_BACK_RIGHT_ARB = 0x2086, + eWGL_BIND_TO_TEXTURE_DEPTH_NV = 0x20A3, + eWGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV = 0x20A4, + eWGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV = 0x20B4, + eWGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV = 0x20B3, + eWGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV = 0x20B2, + eWGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV = 0x20B1, + eWGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV = 0x20A1, + eWGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV = 0x20A0, + eWGL_BIND_TO_TEXTURE_RGBA_ARB = 0x2071, + eWGL_BIND_TO_TEXTURE_RGB_ARB = 0x2070, + eWGL_BIND_TO_VIDEO_RGBA_NV = 0x20C1, + eWGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV = 0x20C2, + eWGL_BIND_TO_VIDEO_RGB_NV = 0x20C0, + eWGL_BLUE_BITS_ARB = 0x2019, + eWGL_BLUE_BITS_EXT = 0x2019, + eWGL_BLUE_SHIFT_ARB = 0x201A, + eWGL_BLUE_SHIFT_EXT = 0x201A, + eWGL_COLOR_BITS_ARB = 0x2014, + eWGL_COLOR_BITS_EXT = 0x2014, + eWGL_COLOR_SAMPLES_NV = 0x20B9, + eWGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002, + eWGL_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001, + eWGL_CONTEXT_DEBUG_BIT_ARB = 0x00000001, + eWGL_CONTEXT_ES2_PROFILE_BIT_EXT = 0x00000004, + eWGL_CONTEXT_ES_PROFILE_BIT_EXT = 0x00000004, + eWGL_CONTEXT_FLAGS_ARB = 0x2094, + eWGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002, + eWGL_CONTEXT_LAYER_PLANE_ARB = 0x2093, + eWGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091, + eWGL_CONTEXT_MINOR_VERSION_ARB = 0x2092, + eWGL_CONTEXT_PROFILE_MASK_ARB = 0x9126, + eWGL_CONTEXT_RESET_ISOLATION_BIT_ARB = 0x00000008, + eWGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB = 0x8256, + eWGL_CONTEXT_ROBUST_ACCESS_BIT_ARB = 0x00000004, + eWGL_COVERAGE_SAMPLES_NV = 0x2042, + eWGL_CUBE_MAP_FACE_ARB = 0x207C, + eWGL_DEPTH_BITS_ARB = 0x2022, + eWGL_DEPTH_BITS_EXT = 0x2022, + eWGL_DEPTH_BUFFER_BIT_ARB = 0x00000004, + eWGL_DEPTH_COMPONENT_NV = 0x20A7, + eWGL_DEPTH_FLOAT_EXT = 0x2040, + eWGL_DEPTH_TEXTURE_FORMAT_NV = 0x20A5, + eWGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D = 0x2050, + eWGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D = 0x2051, + eWGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D = 0x2052, + eWGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D = 0x2053, + eWGL_DOUBLE_BUFFER_ARB = 0x2011, + eWGL_DOUBLE_BUFFER_EXT = 0x2011, + eWGL_DRAW_TO_BITMAP_ARB = 0x2002, + eWGL_DRAW_TO_BITMAP_EXT = 0x2002, + eWGL_DRAW_TO_PBUFFER_ARB = 0x202D, + eWGL_DRAW_TO_PBUFFER_EXT = 0x202D, + eWGL_DRAW_TO_WINDOW_ARB = 0x2001, + eWGL_DRAW_TO_WINDOW_EXT = 0x2001, + eWGL_FLOAT_COMPONENTS_NV = 0x20B0, + eWGL_FRAMEBUFFER_SRGB_CAPABLE_ARB = 0x20A9, + eWGL_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x20A9, + eWGL_FRONT_COLOR_BUFFER_BIT_ARB = 0x00000001, + eWGL_FRONT_LEFT_ARB = 0x2083, + eWGL_FRONT_RIGHT_ARB = 0x2084, + eWGL_FULL_ACCELERATION_ARB = 0x2027, + eWGL_FULL_ACCELERATION_EXT = 0x2027, + eWGL_GAMMA_EXCLUDE_DESKTOP_I3D = 0x204F, + eWGL_GAMMA_TABLE_SIZE_I3D = 0x204E, + eWGL_GENERIC_ACCELERATION_ARB = 0x2026, + eWGL_GENERIC_ACCELERATION_EXT = 0x2026, + eWGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D = 0x2049, + eWGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D = 0x2048, + eWGL_GENLOCK_SOURCE_EDGE_BOTH_I3D = 0x204C, + eWGL_GENLOCK_SOURCE_EDGE_FALLING_I3D = 0x204A, + eWGL_GENLOCK_SOURCE_EDGE_RISING_I3D = 0x204B, + eWGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D = 0x2046, + eWGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D = 0x2045, + eWGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D = 0x2047, + eWGL_GENLOCK_SOURCE_MULTIVIEW_I3D = 0x2044, + eWGL_GPU_CLOCK_AMD = 0x21A4, + eWGL_GPU_FASTEST_TARGET_GPUS_AMD = 0x21A2, + eWGL_GPU_NUM_PIPES_AMD = 0x21A5, + eWGL_GPU_NUM_RB_AMD = 0x21A7, + eWGL_GPU_NUM_SIMD_AMD = 0x21A6, + eWGL_GPU_NUM_SPI_AMD = 0x21A8, + eWGL_GPU_OPENGL_VERSION_STRING_AMD = 0x1F02, + eWGL_GPU_RAM_AMD = 0x21A3, + eWGL_GPU_RENDERER_STRING_AMD = 0x1F01, + eWGL_GPU_VENDOR_AMD = 0x1F00, + eWGL_GREEN_BITS_ARB = 0x2017, + eWGL_GREEN_BITS_EXT = 0x2017, + eWGL_GREEN_SHIFT_ARB = 0x2018, + eWGL_GREEN_SHIFT_EXT = 0x2018, + eWGL_IMAGE_BUFFER_LOCK_I3D = 0x00000002, + eWGL_IMAGE_BUFFER_MIN_ACCESS_I3D = 0x00000001, + eWGL_LOSE_CONTEXT_ON_RESET_ARB = 0x8252, + eWGL_MAX_PBUFFER_HEIGHT_ARB = 0x2030, + eWGL_MAX_PBUFFER_HEIGHT_EXT = 0x2030, + eWGL_MAX_PBUFFER_PIXELS_ARB = 0x202E, + eWGL_MAX_PBUFFER_PIXELS_EXT = 0x202E, + eWGL_MAX_PBUFFER_WIDTH_ARB = 0x202F, + eWGL_MAX_PBUFFER_WIDTH_EXT = 0x202F, + eWGL_MIPMAP_LEVEL_ARB = 0x207B, + eWGL_MIPMAP_TEXTURE_ARB = 0x2074, + eWGL_NEED_PALETTE_ARB = 0x2004, + eWGL_NEED_PALETTE_EXT = 0x2004, + eWGL_NEED_SYSTEM_PALETTE_ARB = 0x2005, + eWGL_NEED_SYSTEM_PALETTE_EXT = 0x2005, + eWGL_NO_ACCELERATION_ARB = 0x2025, + eWGL_NO_ACCELERATION_EXT = 0x2025, + eWGL_NO_RESET_NOTIFICATION_ARB = 0x8261, + eWGL_NO_TEXTURE_ARB = 0x2077, + eWGL_NUMBER_OVERLAYS_ARB = 0x2008, + eWGL_NUMBER_OVERLAYS_EXT = 0x2008, + eWGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000, + eWGL_NUMBER_PIXEL_FORMATS_EXT = 0x2000, + eWGL_NUMBER_UNDERLAYS_ARB = 0x2009, + eWGL_NUMBER_UNDERLAYS_EXT = 0x2009, + eWGL_NUM_VIDEO_CAPTURE_SLOTS_NV = 0x20CF, + eWGL_NUM_VIDEO_SLOTS_NV = 0x20F0, + eWGL_OPTIMAL_PBUFFER_HEIGHT_EXT = 0x2032, + eWGL_OPTIMAL_PBUFFER_WIDTH_EXT = 0x2031, + eWGL_PBUFFER_HEIGHT_ARB = 0x2035, + eWGL_PBUFFER_HEIGHT_EXT = 0x2035, + eWGL_PBUFFER_LARGEST_ARB = 0x2033, + eWGL_PBUFFER_LARGEST_EXT = 0x2033, + eWGL_PBUFFER_LOST_ARB = 0x2036, + eWGL_PBUFFER_WIDTH_ARB = 0x2034, + eWGL_PBUFFER_WIDTH_EXT = 0x2034, + eWGL_PIXEL_TYPE_ARB = 0x2013, + eWGL_PIXEL_TYPE_EXT = 0x2013, + eWGL_RED_BITS_ARB = 0x2015, + eWGL_RED_BITS_EXT = 0x2015, + eWGL_RED_SHIFT_ARB = 0x2016, + eWGL_RED_SHIFT_EXT = 0x2016, + eWGL_SAMPLES_3DFX = 0x2061, + eWGL_SAMPLES_ARB = 0x2042, + eWGL_SAMPLES_EXT = 0x2042, + eWGL_SAMPLE_BUFFERS_3DFX = 0x2060, + eWGL_SAMPLE_BUFFERS_ARB = 0x2041, + eWGL_SAMPLE_BUFFERS_EXT = 0x2041, + eWGL_SHARE_ACCUM_ARB = 0x200E, + eWGL_SHARE_ACCUM_EXT = 0x200E, + eWGL_SHARE_DEPTH_ARB = 0x200C, + eWGL_SHARE_DEPTH_EXT = 0x200C, + eWGL_SHARE_STENCIL_ARB = 0x200D, + eWGL_SHARE_STENCIL_EXT = 0x200D, + eWGL_STENCIL_BITS_ARB = 0x2023, + eWGL_STENCIL_BITS_EXT = 0x2023, + eWGL_STENCIL_BUFFER_BIT_ARB = 0x00000008, + eWGL_STEREO_ARB = 0x2012, + eWGL_STEREO_EMITTER_DISABLE_3DL = 0x2056, + eWGL_STEREO_EMITTER_ENABLE_3DL = 0x2055, + eWGL_STEREO_EXT = 0x2012, + eWGL_STEREO_POLARITY_INVERT_3DL = 0x2058, + eWGL_STEREO_POLARITY_NORMAL_3DL = 0x2057, + eWGL_SUPPORT_GDI_ARB = 0x200F, + eWGL_SUPPORT_GDI_EXT = 0x200F, + eWGL_SUPPORT_OPENGL_ARB = 0x2010, + eWGL_SUPPORT_OPENGL_EXT = 0x2010, + eWGL_SWAP_COPY_ARB = 0x2029, + eWGL_SWAP_COPY_EXT = 0x2029, + eWGL_SWAP_EXCHANGE_ARB = 0x2028, + eWGL_SWAP_EXCHANGE_EXT = 0x2028, + eWGL_SWAP_LAYER_BUFFERS_ARB = 0x2006, + eWGL_SWAP_LAYER_BUFFERS_EXT = 0x2006, + eWGL_SWAP_METHOD_ARB = 0x2007, + eWGL_SWAP_METHOD_EXT = 0x2007, + eWGL_SWAP_UNDEFINED_ARB = 0x202A, + eWGL_SWAP_UNDEFINED_EXT = 0x202A, + eWGL_TEXTURE_1D_ARB = 0x2079, + eWGL_TEXTURE_2D_ARB = 0x207A, + eWGL_TEXTURE_CUBE_MAP_ARB = 0x2078, + eWGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = 0x207E, + eWGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = 0x2080, + eWGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = 0x2082, + eWGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = 0x207D, + eWGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = 0x207F, + eWGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = 0x2081, + eWGL_TEXTURE_DEPTH_COMPONENT_NV = 0x20A6, + eWGL_TEXTURE_FLOAT_RGBA_NV = 0x20B8, + eWGL_TEXTURE_FLOAT_RGB_NV = 0x20B7, + eWGL_TEXTURE_FLOAT_RG_NV = 0x20B6, + eWGL_TEXTURE_FLOAT_R_NV = 0x20B5, + eWGL_TEXTURE_FORMAT_ARB = 0x2072, + eWGL_TEXTURE_RECTANGLE_NV = 0x20A2, + eWGL_TEXTURE_RGBA_ARB = 0x2076, + eWGL_TEXTURE_RGB_ARB = 0x2075, + eWGL_TEXTURE_TARGET_ARB = 0x2073, + eWGL_TRANSPARENT_ALPHA_VALUE_ARB = 0x203A, + eWGL_TRANSPARENT_ARB = 0x200A, + eWGL_TRANSPARENT_BLUE_VALUE_ARB = 0x2039, + eWGL_TRANSPARENT_EXT = 0x200A, + eWGL_TRANSPARENT_GREEN_VALUE_ARB = 0x2038, + eWGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B, + eWGL_TRANSPARENT_RED_VALUE_ARB = 0x2037, + eWGL_TRANSPARENT_VALUE_EXT = 0x200B, + eWGL_TYPE_COLORINDEX_ARB = 0x202C, + eWGL_TYPE_COLORINDEX_EXT = 0x202C, + eWGL_TYPE_RGBA_ARB = 0x202B, + eWGL_TYPE_RGBA_EXT = 0x202B, + eWGL_TYPE_RGBA_FLOAT_ARB = 0x21A0, + eWGL_TYPE_RGBA_FLOAT_ATI = 0x21A0, + eWGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT = 0x20A8, + eWGL_UNIQUE_ID_NV = 0x20CE, + eWGL_VIDEO_OUT_ALPHA_NV = 0x20C4, + eWGL_VIDEO_OUT_COLOR_AND_ALPHA_NV = 0x20C6, + eWGL_VIDEO_OUT_COLOR_AND_DEPTH_NV = 0x20C7, + eWGL_VIDEO_OUT_COLOR_NV = 0x20C3, + eWGL_VIDEO_OUT_DEPTH_NV = 0x20C5, + eWGL_VIDEO_OUT_FIELD_1 = 0x20C9, + eWGL_VIDEO_OUT_FIELD_2 = 0x20CA, + eWGL_VIDEO_OUT_FRAME = 0x20C8, + eWGL_VIDEO_OUT_STACKED_FIELDS_1_2 = 0x20CB, + eWGL_VIDEO_OUT_STACKED_FIELDS_2_1 = 0x20CC, + RADGLenum_Force_Uint = 0xffffffff, +}; diff --git a/renderdoc/driver/gl/gl_hookset.h b/renderdoc/driver/gl/gl_hookset.h new file mode 100644 index 0000000000..3c30d36caa --- /dev/null +++ b/renderdoc/driver/gl/gl_hookset.h @@ -0,0 +1,154 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "gl_common.h" +#include "gl_legacy_procs.h" + +struct GLHookSet +{ + // ++ dllexport + PFNGLBINDTEXTUREPROC glBindTexture; + PFNGLBLENDFUNCPROC glBlendFunc; + PFNGLCLEARPROC glClear; + PFNGLCLEARCOLORPROC glClearColor; + PFNGLCLEARDEPTHPROC glClearDepth; + PFNGLDEPTHFUNCPROC glDepthFunc; + PFNGLDISABLEPROC glDisable; + PFNGLDRAWARRAYSPROC glDrawArrays; + PFNGLENABLEPROC glEnable; + PFNGLGENTEXTURESPROC glGenTextures; + PFNGLDELETETEXTURESPROC glDeleteTextures; + PFNGLGETERRORPROC glGetError; + PFNGLGETFLOATVPROC glGetFloatv; + PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv; + PFNGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv; + PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv; + PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv; + PFNGLGETINTEGERVPROC glGetIntegerv; + PFNGLGETSTRINGPROC glGetString; + PFNGLHINTPROC glHint; + PFNGLPIXELSTOREIPROC glPixelStorei; + PFNGLPIXELSTOREFPROC glPixelStoref; + PFNGLPOLYGONMODEPROC glPolygonMode; + PFNGLREADPIXELSPROC glReadPixels; + PFNGLREADBUFFERPROC glReadBuffer; + PFNGLTEXIMAGE1DPROC glTexImage1D; + PFNGLTEXIMAGE2DPROC glTexImage2D; + PFNGLTEXPARAMETERIPROC glTexParameteri; + PFNGLVIEWPORTPROC glViewport; + // legacy + PFNGLLIGHTFVPROC glLightfv; + PFNGLMATERIALFVPROC glMaterialfv; + PFNGLGENLISTSPROC glGenLists; + PFNGLNEWLISTPROC glNewList; + PFNGLENDLISTPROC glEndList; + PFNGLCALLLISTPROC glCallList; + PFNGLSHADEMODELPROC glShadeModel; + PFNGLBEGINPROC glBegin; + PFNGLENDPROC glEnd; + PFNGLVERTEX3FPROC glVertex3f; + PFNGLNORMAL3FPROC glNormal3f; + PFNGLPUSHMATRIXPROC glPushMatrix; + PFNGLPOPMATRIXPROC glPopMatrix; + PFNGLMATRIXMODEPROC glMatrixMode; + PFNGLLOADIDENTITYPROC glLoadIdentity; + PFNGLFRUSTUMPROC glFrustum; + PFNGLTRANSLATEFPROC glTranslatef; + PFNGLROTATEFPROC glRotatef; + // -- + + // ++ gl + PFNGLACTIVETEXTUREPROC glActiveTexture; + PFNGLTEXSTORAGE2DPROC glTexStorage2D; + PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D; + PFNGLGENERATEMIPMAPPROC glGenerateMipmap; + PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ; + PFNGLGETINTERNALFORMATI64VPROC glGetInternalformati64v; + PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; + PFNGLGETSTRINGIPROC glGetStringi; + PFNGLGETINTEGERI_VPROC glGetIntegeri_v; + PFNGLCREATESHADERPROC glCreateShader; + PFNGLDELETESHADERPROC glDeleteShader; + PFNGLSHADERSOURCEPROC glShaderSource; + PFNGLCOMPILESHADERPROC glCompileShader; + PFNGLGETSHADERIVPROC glGetShaderiv; + PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; + PFNGLCREATEPROGRAMPROC glCreateProgram; + PFNGLDELETEPROGRAMPROC glDeleteProgram; + PFNGLATTACHSHADERPROC glAttachShader; + PFNGLLINKPROGRAMPROC glLinkProgram; + PFNGLUSEPROGRAMPROC glUseProgram; + PFNGLGETPROGRAMIVPROC glGetProgramiv; + PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; + PFNGLGETPROGRAMINTERFACEIVPROC glGetProgramInterfaceiv; + PFNGLGETPROGRAMRESOURCEIVPROC glGetProgramResourceiv; + PFNGLGETPROGRAMRESOURCENAMEPROC glGetProgramResourceName; + PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback; // aliases glDebugMessageCallbackARB + PFNGLGETOBJECTLABELPROC glGetObjectLabel; + PFNGLOBJECTLABELPROC glObjectLabel; + PFNGLGENBUFFERSPROC glGenBuffers; + PFNGLBINDBUFFERPROC glBindBuffer; + PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; + PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; + PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture; + PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; + PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv; + PFNGLBUFFERDATAPROC glBufferData; + PFNGLBINDBUFFERBASEPROC glBindBufferBase; + PFNGLMAPBUFFERRANGEPROC glMapBufferRange; + PFNGLUNMAPBUFFERPROC glUnmapBuffer; + PFNGLDELETEBUFFERSPROC glDeleteBuffers; + PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData; + PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; + PFNGLBINDVERTEXARRAYPROC glBindVertexArray; + PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; + PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; + PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; + PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv; + PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv; + PFNGLGENSAMPLERSPROC glGenSamplers; + PFNGLBINDSAMPLERPROC glBindSampler; + PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri; + PFNGLCLEARBUFFERFVPROC glClearBufferfv; + PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; + PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform; + PFNGLGETUNIFORMFVPROC glGetUniformfv; + PFNGLGETUNIFORMIVPROC glGetUniformiv; + PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; + PFNGLUNIFORM3FVPROC glUniform3fv; + PFNGLUNIFORM4FVPROC glUniform4fv; + PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glDrawArraysInstancedBaseInstance; + // -- + + // ++ wgl + // -- + + // ++ glx + // -- +}; + +#include "gl_hookset_defs.h" diff --git a/renderdoc/driver/gl/gl_hookset_defs.h b/renderdoc/driver/gl/gl_hookset_defs.h new file mode 100644 index 0000000000..a738f6c109 --- /dev/null +++ b/renderdoc/driver/gl/gl_hookset_defs.h @@ -0,0 +1,334 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +// it's recommended that you auto-generate this file with hookset.pl, but you can manually edit it +// if you prefer. +//////////////////////////////////////////////////// + +// dllexport functions +#define DLLExportHooks() \ + HookInit(glBindTexture); \ + HookInit(glBlendFunc); \ + HookInit(glClear); \ + HookInit(glClearColor); \ + HookInit(glClearDepth); \ + HookInit(glDepthFunc); \ + HookInit(glDisable); \ + HookInit(glDrawArrays); \ + HookInit(glEnable); \ + HookInit(glGenTextures); \ + HookInit(glDeleteTextures); \ + HookInit(glGetError); \ + HookInit(glGetFloatv); \ + HookInit(glGetTexLevelParameteriv); \ + HookInit(glGetTexLevelParameterfv); \ + HookInit(glGetTexParameterfv); \ + HookInit(glGetTexParameteriv); \ + HookInit(glGetIntegerv); \ + HookInit(glGetString); \ + HookInit(glHint); \ + HookInit(glPixelStorei); \ + HookInit(glPixelStoref); \ + HookInit(glPolygonMode); \ + HookInit(glReadPixels); \ + HookInit(glReadBuffer); \ + HookInit(glTexImage1D); \ + HookInit(glTexImage2D); \ + HookInit(glTexParameteri); \ + HookInit(glViewport); \ + HookInit(glLightfv); \ + HookInit(glMaterialfv); \ + HookInit(glGenLists); \ + HookInit(glNewList); \ + HookInit(glEndList); \ + HookInit(glCallList); \ + HookInit(glShadeModel); \ + HookInit(glBegin); \ + HookInit(glEnd); \ + HookInit(glVertex3f); \ + HookInit(glNormal3f); \ + HookInit(glPushMatrix); \ + HookInit(glPopMatrix); \ + HookInit(glMatrixMode); \ + HookInit(glLoadIdentity); \ + HookInit(glFrustum); \ + HookInit(glTranslatef); \ + HookInit(glRotatef); \ + + + +// wgl extensions +#define HookCheckWGLExtensions() \ + + + +// glx extensions +#define HookCheckGLXExtensions() \ + + + +// gl extensions +#define HookCheckGLExtensions() \ + HookExtension(PFNGLACTIVETEXTUREPROC, glActiveTexture); \ + HookExtension(PFNGLTEXSTORAGE2DPROC, glTexStorage2D); \ + HookExtension(PFNGLTEXSUBIMAGE2DPROC, glTexSubImage2D); \ + HookExtension(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap); \ + HookExtension(PFNGLGETINTERNALFORMATIVPROC, glGetInternalformativ); \ + HookExtension(PFNGLGETINTERNALFORMATI64VPROC, glGetInternalformati64v); \ + HookExtension(PFNGLGETBUFFERPARAMETERIVPROC, glGetBufferParameteriv); \ + HookExtension(PFNGLGETSTRINGIPROC, glGetStringi); \ + HookExtension(PFNGLGETINTEGERI_VPROC, glGetIntegeri_v); \ + HookExtension(PFNGLCREATESHADERPROC, glCreateShader); \ + HookExtension(PFNGLDELETESHADERPROC, glDeleteShader); \ + HookExtension(PFNGLSHADERSOURCEPROC, glShaderSource); \ + HookExtension(PFNGLCOMPILESHADERPROC, glCompileShader); \ + HookExtension(PFNGLGETSHADERIVPROC, glGetShaderiv); \ + HookExtension(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog); \ + HookExtension(PFNGLCREATEPROGRAMPROC, glCreateProgram); \ + HookExtension(PFNGLDELETEPROGRAMPROC, glDeleteProgram); \ + HookExtension(PFNGLATTACHSHADERPROC, glAttachShader); \ + HookExtension(PFNGLLINKPROGRAMPROC, glLinkProgram); \ + HookExtension(PFNGLUSEPROGRAMPROC, glUseProgram); \ + HookExtension(PFNGLGETPROGRAMIVPROC, glGetProgramiv); \ + HookExtension(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog); \ + HookExtension(PFNGLGETPROGRAMINTERFACEIVPROC, glGetProgramInterfaceiv); \ + HookExtension(PFNGLGETPROGRAMRESOURCEIVPROC, glGetProgramResourceiv); \ + HookExtension(PFNGLGETPROGRAMRESOURCENAMEPROC, glGetProgramResourceName); \ + HookExtension(PFNGLDEBUGMESSAGECALLBACKPROC, glDebugMessageCallback); \ + HookExtensionAlias(PFNGLDEBUGMESSAGECALLBACKPROC, glDebugMessageCallback, glDebugMessageCallbackARB); \ + HookExtension(PFNGLGETOBJECTLABELPROC, glGetObjectLabel); \ + HookExtension(PFNGLOBJECTLABELPROC, glObjectLabel); \ + HookExtension(PFNGLGENBUFFERSPROC, glGenBuffers); \ + HookExtension(PFNGLBINDBUFFERPROC, glBindBuffer); \ + HookExtension(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers); \ + HookExtension(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer); \ + HookExtension(PFNGLFRAMEBUFFERTEXTUREPROC, glFramebufferTexture); \ + HookExtension(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers); \ + HookExtension(PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC, glGetFramebufferAttachmentParameteriv); \ + HookExtension(PFNGLBUFFERDATAPROC, glBufferData); \ + HookExtension(PFNGLBINDBUFFERBASEPROC, glBindBufferBase); \ + HookExtension(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange); \ + HookExtension(PFNGLUNMAPBUFFERPROC, glUnmapBuffer); \ + HookExtension(PFNGLDELETEBUFFERSPROC, glDeleteBuffers); \ + HookExtension(PFNGLGETBUFFERSUBDATAPROC, glGetBufferSubData); \ + HookExtension(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays); \ + HookExtension(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray); \ + HookExtension(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays); \ + HookExtension(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer); \ + HookExtension(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray); \ + HookExtension(PFNGLGETVERTEXATTRIBIVPROC, glGetVertexAttribiv); \ + HookExtension(PFNGLGETVERTEXATTRIBPOINTERVPROC, glGetVertexAttribPointerv); \ + HookExtension(PFNGLGENSAMPLERSPROC, glGenSamplers); \ + HookExtension(PFNGLBINDSAMPLERPROC, glBindSampler); \ + HookExtension(PFNGLSAMPLERPARAMETERIPROC, glSamplerParameteri); \ + HookExtension(PFNGLCLEARBUFFERFVPROC, glClearBufferfv); \ + HookExtension(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation); \ + HookExtension(PFNGLGETACTIVEUNIFORMPROC, glGetActiveUniform); \ + HookExtension(PFNGLGETUNIFORMFVPROC, glGetUniformfv); \ + HookExtension(PFNGLGETUNIFORMIVPROC, glGetUniformiv); \ + HookExtension(PFNGLUNIFORMMATRIX4FVPROC, glUniformMatrix4fv); \ + HookExtension(PFNGLUNIFORM3FVPROC, glUniform3fv); \ + HookExtension(PFNGLUNIFORM4FVPROC, glUniform4fv); \ + HookExtension(PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC, glDrawArraysInstancedBaseInstance); \ + HookExtension(PFNGLBINDTEXTUREPROC, glBindTexture); \ + HookExtension(PFNGLBLENDFUNCPROC, glBlendFunc); \ + HookExtension(PFNGLCLEARPROC, glClear); \ + HookExtension(PFNGLCLEARCOLORPROC, glClearColor); \ + HookExtension(PFNGLCLEARDEPTHPROC, glClearDepth); \ + HookExtension(PFNGLDEPTHFUNCPROC, glDepthFunc); \ + HookExtension(PFNGLDISABLEPROC, glDisable); \ + HookExtension(PFNGLDRAWARRAYSPROC, glDrawArrays); \ + HookExtension(PFNGLENABLEPROC, glEnable); \ + HookExtension(PFNGLGENTEXTURESPROC, glGenTextures); \ + HookExtension(PFNGLDELETETEXTURESPROC, glDeleteTextures); \ + HookExtension(PFNGLGETERRORPROC, glGetError); \ + HookExtension(PFNGLGETFLOATVPROC, glGetFloatv); \ + HookExtension(PFNGLGETTEXLEVELPARAMETERIVPROC, glGetTexLevelParameteriv); \ + HookExtension(PFNGLGETTEXLEVELPARAMETERFVPROC, glGetTexLevelParameterfv); \ + HookExtension(PFNGLGETTEXPARAMETERFVPROC, glGetTexParameterfv); \ + HookExtension(PFNGLGETTEXPARAMETERIVPROC, glGetTexParameteriv); \ + HookExtension(PFNGLGETINTEGERVPROC, glGetIntegerv); \ + HookExtension(PFNGLGETSTRINGPROC, glGetString); \ + HookExtension(PFNGLHINTPROC, glHint); \ + HookExtension(PFNGLPIXELSTOREIPROC, glPixelStorei); \ + HookExtension(PFNGLPIXELSTOREFPROC, glPixelStoref); \ + HookExtension(PFNGLPOLYGONMODEPROC, glPolygonMode); \ + HookExtension(PFNGLREADPIXELSPROC, glReadPixels); \ + HookExtension(PFNGLREADBUFFERPROC, glReadBuffer); \ + HookExtension(PFNGLTEXIMAGE1DPROC, glTexImage1D); \ + HookExtension(PFNGLTEXIMAGE2DPROC, glTexImage2D); \ + HookExtension(PFNGLTEXPARAMETERIPROC, glTexParameteri); \ + HookExtension(PFNGLVIEWPORTPROC, glViewport); \ + HookExtension(PFNGLLIGHTFVPROC, glLightfv); \ + HookExtension(PFNGLMATERIALFVPROC, glMaterialfv); \ + HookExtension(PFNGLGENLISTSPROC, glGenLists); \ + HookExtension(PFNGLNEWLISTPROC, glNewList); \ + HookExtension(PFNGLENDLISTPROC, glEndList); \ + HookExtension(PFNGLCALLLISTPROC, glCallList); \ + HookExtension(PFNGLSHADEMODELPROC, glShadeModel); \ + HookExtension(PFNGLBEGINPROC, glBegin); \ + HookExtension(PFNGLENDPROC, glEnd); \ + HookExtension(PFNGLVERTEX3FPROC, glVertex3f); \ + HookExtension(PFNGLNORMAL3FPROC, glNormal3f); \ + HookExtension(PFNGLPUSHMATRIXPROC, glPushMatrix); \ + HookExtension(PFNGLPOPMATRIXPROC, glPopMatrix); \ + HookExtension(PFNGLMATRIXMODEPROC, glMatrixMode); \ + HookExtension(PFNGLLOADIDENTITYPROC, glLoadIdentity); \ + HookExtension(PFNGLFRUSTUMPROC, glFrustum); \ + HookExtension(PFNGLTRANSLATEFPROC, glTranslatef); \ + HookExtension(PFNGLROTATEFPROC, glRotatef); \ + + + +// dllexport functions +#define DefineDLLExportHooks() \ + HookWrapper2(void, glBindTexture, GLenum, target, GLuint, texture); \ + HookWrapper2(void, glBlendFunc, GLenum, sfactor, GLenum, dfactor); \ + HookWrapper1(void, glClear, GLbitfield, mask); \ + HookWrapper4(void, glClearColor, GLfloat, red, GLfloat, green, GLfloat, blue, GLfloat, alpha); \ + HookWrapper1(void, glClearDepth, GLdouble, depth); \ + HookWrapper1(void, glDepthFunc, GLenum, func); \ + HookWrapper1(void, glDisable, GLenum, cap); \ + HookWrapper3(void, glDrawArrays, GLenum, mode, GLint, first, GLsizei, count); \ + HookWrapper1(void, glEnable, GLenum, cap); \ + HookWrapper2(void, glGenTextures, GLsizei, n, GLuint *, textures); \ + HookWrapper2(void, glDeleteTextures, GLsizei, n, const GLuint *, textures); \ + HookWrapper0(GLenum, glGetError); \ + HookWrapper2(void, glGetFloatv, GLenum, pname, GLfloat *, data); \ + HookWrapper4(void, glGetTexLevelParameteriv, GLenum, target, GLint, level, GLenum, pname, GLint *, params); \ + HookWrapper4(void, glGetTexLevelParameterfv, GLenum, target, GLint, level, GLenum, pname, GLfloat *, params); \ + HookWrapper3(void, glGetTexParameterfv, GLenum, target, GLenum, pname, GLfloat *, params); \ + HookWrapper3(void, glGetTexParameteriv, GLenum, target, GLenum, pname, GLint *, params); \ + HookWrapper2(void, glGetIntegerv, GLenum, pname, GLint *, data); \ + HookWrapper1(const GLubyte *, glGetString, GLenum, name); \ + HookWrapper2(void, glHint, GLenum, target, GLenum, mode); \ + HookWrapper2(void, glPixelStorei, GLenum, pname, GLint, param); \ + HookWrapper2(void, glPixelStoref, GLenum, pname, GLfloat, param); \ + HookWrapper2(void, glPolygonMode, GLenum, face, GLenum, mode); \ + HookWrapper7(void, glReadPixels, GLint, x, GLint, y, GLsizei, width, GLsizei, height, GLenum, format, GLenum, type, void *, pixels); \ + HookWrapper1(void, glReadBuffer, GLenum, mode); \ + HookWrapper8(void, glTexImage1D, GLenum, target, GLint, level, GLint, internalformat, GLsizei, width, GLint, border, GLenum, format, GLenum, type, const void *, pixels); \ + HookWrapper9(void, glTexImage2D, GLenum, target, GLint, level, GLint, internalformat, GLsizei, width, GLsizei, height, GLint, border, GLenum, format, GLenum, type, const void *, pixels); \ + HookWrapper3(void, glTexParameteri, GLenum, target, GLenum, pname, GLint, param); \ + HookWrapper4(void, glViewport, GLint, x, GLint, y, GLsizei, width, GLsizei, height); \ + HookWrapper3(void, glLightfv, GLenum, light, GLenum, pname, const GLfloat *, params); \ + HookWrapper3(void, glMaterialfv, GLenum, face, GLenum, pname, const GLfloat *, params); \ + HookWrapper1(GLuint, glGenLists, GLsizei, range); \ + HookWrapper2(void, glNewList, GLuint, list, GLenum, mode); \ + HookWrapper0(void, glEndList); \ + HookWrapper1(void, glCallList, GLuint, list); \ + HookWrapper1(void, glShadeModel, GLenum, mode); \ + HookWrapper1(void, glBegin, GLenum, mode); \ + HookWrapper0(void, glEnd); \ + HookWrapper3(void, glVertex3f, GLfloat, x, GLfloat, y, GLfloat, z); \ + HookWrapper3(void, glNormal3f, GLfloat, nx, GLfloat, ny, GLfloat, nz); \ + HookWrapper0(void, glPushMatrix); \ + HookWrapper0(void, glPopMatrix); \ + HookWrapper1(void, glMatrixMode, GLenum, mode); \ + HookWrapper0(void, glLoadIdentity); \ + HookWrapper6(void, glFrustum, GLdouble, left, GLdouble, right, GLdouble, bottom, GLdouble, top, GLdouble, zNear, GLdouble, zFar); \ + HookWrapper3(void, glTranslatef, GLfloat, x, GLfloat, y, GLfloat, z); \ + HookWrapper4(void, glRotatef, GLfloat, angle, GLfloat, x, GLfloat, y, GLfloat, z); \ + + + +// wgl extensions +#define DefineWGLExtensionHooks() \ + + + +// glx extensions +#define DefineGLXExtensionHooks() \ + + + +// gl extensions +#define DefineGLExtensionHooks() \ + HookWrapper1(void, glActiveTexture, GLenum, texture); \ + HookWrapper5(void, glTexStorage2D, GLenum, target, GLsizei, levels, GLenum, internalformat, GLsizei, width, GLsizei, height); \ + HookWrapper9(void, glTexSubImage2D, GLenum, target, GLint, level, GLint, xoffset, GLint, yoffset, GLsizei, width, GLsizei, height, GLenum, format, GLenum, type, const void *, pixels); \ + HookWrapper1(void, glGenerateMipmap, GLenum, target); \ + HookWrapper5(void, glGetInternalformativ, GLenum, target, GLenum, internalformat, GLenum, pname, GLsizei, bufSize, GLint *, params); \ + HookWrapper5(void, glGetInternalformati64v, GLenum, target, GLenum, internalformat, GLenum, pname, GLsizei, bufSize, GLint64 *, params); \ + HookWrapper3(void, glGetBufferParameteriv, GLenum, target, GLenum, pname, GLint *, params); \ + HookWrapper2(const GLubyte *, glGetStringi, GLenum, name, GLuint, index); \ + HookWrapper3(void, glGetIntegeri_v, GLenum, target, GLuint, index, GLint *, data); \ + HookWrapper1(GLuint, glCreateShader, GLenum, type); \ + HookWrapper1(void, glDeleteShader, GLuint, shader); \ + HookWrapper4(void, glShaderSource, GLuint, shader, GLsizei, count, const GLchar *const*, string, const GLint *, length); \ + HookWrapper1(void, glCompileShader, GLuint, shader); \ + HookWrapper3(void, glGetShaderiv, GLuint, shader, GLenum, pname, GLint *, params); \ + HookWrapper4(void, glGetShaderInfoLog, GLuint, shader, GLsizei, bufSize, GLsizei *, length, GLchar *, infoLog); \ + HookWrapper0(GLuint, glCreateProgram); \ + HookWrapper1(void, glDeleteProgram, GLuint, program); \ + HookWrapper2(void, glAttachShader, GLuint, program, GLuint, shader); \ + HookWrapper1(void, glLinkProgram, GLuint, program); \ + HookWrapper1(void, glUseProgram, GLuint, program); \ + HookWrapper3(void, glGetProgramiv, GLuint, program, GLenum, pname, GLint *, params); \ + HookWrapper4(void, glGetProgramInfoLog, GLuint, program, GLsizei, bufSize, GLsizei *, length, GLchar *, infoLog); \ + HookWrapper4(void, glGetProgramInterfaceiv, GLuint, program, GLenum, programInterface, GLenum, pname, GLint *, params); \ + HookWrapper8(void, glGetProgramResourceiv, GLuint, program, GLenum, programInterface, GLuint, index, GLsizei, propCount, const GLenum *, props, GLsizei, bufSize, GLsizei *, length, GLint *, params); \ + HookWrapper6(void, glGetProgramResourceName, GLuint, program, GLenum, programInterface, GLuint, index, GLsizei, bufSize, GLsizei *, length, GLchar *, name); \ + HookWrapper2(void, glDebugMessageCallback, GLDEBUGPROC, callback, const void *, userParam); \ + HookWrapper5(void, glGetObjectLabel, GLenum, identifier, GLuint, name, GLsizei, bufSize, GLsizei *, length, GLchar *, label); \ + HookWrapper4(void, glObjectLabel, GLenum, identifier, GLuint, name, GLsizei, length, const GLchar *, label); \ + HookWrapper2(void, glGenBuffers, GLsizei, n, GLuint *, buffers); \ + HookWrapper2(void, glBindBuffer, GLenum, target, GLuint, buffer); \ + HookWrapper2(void, glGenFramebuffers, GLsizei, n, GLuint *, framebuffers); \ + HookWrapper2(void, glBindFramebuffer, GLenum, target, GLuint, framebuffer); \ + HookWrapper4(void, glFramebufferTexture, GLenum, target, GLenum, attachment, GLuint, texture, GLint, level); \ + HookWrapper2(void, glDeleteFramebuffers, GLsizei, n, const GLuint *, framebuffers); \ + HookWrapper4(void, glGetFramebufferAttachmentParameteriv, GLenum, target, GLenum, attachment, GLenum, pname, GLint *, params); \ + HookWrapper4(void, glBufferData, GLenum, target, GLsizeiptr, size, const void *, data, GLenum, usage); \ + HookWrapper3(void, glBindBufferBase, GLenum, target, GLuint, index, GLuint, buffer); \ + HookWrapper4(void *, glMapBufferRange, GLenum, target, GLintptr, offset, GLsizeiptr, length, GLbitfield, access); \ + HookWrapper1(GLboolean, glUnmapBuffer, GLenum, target); \ + HookWrapper2(void, glDeleteBuffers, GLsizei, n, const GLuint *, buffers); \ + HookWrapper4(void, glGetBufferSubData, GLenum, target, GLintptr, offset, GLsizeiptr, size, void *, data); \ + HookWrapper2(void, glGenVertexArrays, GLsizei, n, GLuint *, arrays); \ + HookWrapper1(void, glBindVertexArray, GLuint, array); \ + HookWrapper2(void, glDeleteVertexArrays, GLsizei, n, const GLuint *, arrays); \ + HookWrapper6(void, glVertexAttribPointer, GLuint, index, GLint, size, GLenum, type, GLboolean, normalized, GLsizei, stride, const void *, pointer); \ + HookWrapper1(void, glEnableVertexAttribArray, GLuint, index); \ + HookWrapper3(void, glGetVertexAttribiv, GLuint, index, GLenum, pname, GLint *, params); \ + HookWrapper3(void, glGetVertexAttribPointerv, GLuint, index, GLenum, pname, void **, pointer); \ + HookWrapper2(void, glGenSamplers, GLsizei, count, GLuint *, samplers); \ + HookWrapper2(void, glBindSampler, GLuint, unit, GLuint, sampler); \ + HookWrapper3(void, glSamplerParameteri, GLuint, sampler, GLenum, pname, GLint, param); \ + HookWrapper3(void, glClearBufferfv, GLenum, buffer, GLint, drawbuffer, const GLfloat *, value); \ + HookWrapper2(GLint, glGetUniformLocation, GLuint, program, const GLchar *, name); \ + HookWrapper7(void, glGetActiveUniform, GLuint, program, GLuint, index, GLsizei, bufSize, GLsizei *, length, GLint *, size, GLenum *, type, GLchar *, name); \ + HookWrapper3(void, glGetUniformfv, GLuint, program, GLint, location, GLfloat *, params); \ + HookWrapper3(void, glGetUniformiv, GLuint, program, GLint, location, GLint *, params); \ + HookWrapper4(void, glUniformMatrix4fv, GLint, location, GLsizei, count, GLboolean, transpose, const GLfloat *, value); \ + HookWrapper3(void, glUniform3fv, GLint, location, GLsizei, count, const GLfloat *, value); \ + HookWrapper3(void, glUniform4fv, GLint, location, GLsizei, count, const GLfloat *, value); \ + HookWrapper5(void, glDrawArraysInstancedBaseInstance, GLenum, mode, GLint, first, GLsizei, count, GLsizei, instancecount, GLuint, baseinstance); \ + + + + diff --git a/renderdoc/driver/gl/gl_legacy_procs.h b/renderdoc/driver/gl/gl_legacy_procs.h new file mode 100644 index 0000000000..9b9d62849d --- /dev/null +++ b/renderdoc/driver/gl/gl_legacy_procs.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +typedef void (APIENTRYP PFNGLLIGHTFVPROC) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMATERIALFVPROC) (GLenum face, GLenum pname, const GLfloat *params); +typedef GLuint (APIENTRYP PFNGLGENLISTSPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLNEWLISTPROC) (GLuint list, GLenum mode); +typedef void (APIENTRYP PFNGLENDLISTPROC) (void); +typedef void (APIENTRYP PFNGLCALLLISTPROC) (GLuint list); +typedef void (APIENTRYP PFNGLSHADEMODELPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLBEGINPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLENDPROC) (void); +typedef void (APIENTRYP PFNGLVERTEX3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLNORMAL3FPROC) (GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRYP PFNGLPUSHMATRIXPROC) (void); +typedef void (APIENTRYP PFNGLPOPMATRIXPROC) (void); +typedef void (APIENTRYP PFNGLMATRIXMODEPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLLOADIDENTITYPROC) (void); +typedef void (APIENTRYP PFNGLFRUSTUMPROC) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLTRANSLATEFPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLROTATEFPROC) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); + diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp new file mode 100644 index 0000000000..ebccd60696 --- /dev/null +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -0,0 +1,34 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/gl/gl_manager.h" +#include "driver/gl/gl_driver.h" + +bool GLResourceManager::SerialisableResource(ResourceId id, GLResourceRecord *record) +{ + if(id == m_GL->GetContextResourceID()) + return false; + return true; +} diff --git a/renderdoc/driver/gl/gl_manager.h b/renderdoc/driver/gl/gl_manager.h new file mode 100644 index 0000000000..c9bb0e133e --- /dev/null +++ b/renderdoc/driver/gl/gl_manager.h @@ -0,0 +1,136 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "core/resource_manager.h" + +#include "driver/gl/gl_resources.h" + +class WrappedOpenGL; + +class GLResourceManager : public ResourceManager +{ + public: + GLResourceManager(WrappedOpenGL *gl) : m_GL(gl) {} + ~GLResourceManager() {} + + void Shutdown() + { + while(!m_GLResourceRecords.empty()) + { + auto it = m_GLResourceRecords.begin(); + ResourceId id = it->second->GetResourceID(); + it->second->Delete(this); + + if(!m_GLResourceRecords.empty() && m_GLResourceRecords.begin()->second->GetResourceID() == id) + m_GLResourceRecords.erase(m_GLResourceRecords.begin()); + } + + m_CurrentResourceIds.clear(); + + ResourceManager::Shutdown(); + } + + inline void RemoveResourceRecord(ResourceId id) + { + for(auto it = m_GLResourceRecords.begin(); it != m_GLResourceRecords.end(); it++) + { + if(it->second->GetResourceID() == id) + { + m_GLResourceRecords.erase(it); + break; + } + } + + ResourceManager::RemoveResourceRecord(id); + } + + ResourceId RegisterResource(GLResource res) + { + ResourceId id = TrackedResource::GetNewUniqueID(); + m_CurrentResourceIds[res] = id; + AddCurrentResource(id, res); + return id; + } + + void UnregisterResource(GLResource res) + { + auto it = m_CurrentResourceIds.find(res); + if(it != m_CurrentResourceIds.end()) + { + ReleaseCurrentResource(it->second); + m_CurrentResourceIds.erase(res); + } + } + + ResourceId GetID(GLResource res) + { + auto it = m_CurrentResourceIds.find(res); + if(it != m_CurrentResourceIds.end()) + return it->second; + return ResourceId(); + } + + GLResourceRecord *AddResourceRecord(ResourceId id) + { + GLResourceRecord *ret = ResourceManager::AddResourceRecord(id); + GLResource res = GetCurrentResource(id); + + m_GLResourceRecords[res] = ret; + + return ret; + } + + using ResourceManager::GetResourceRecord; + + GLResourceRecord *GetResourceRecord(GLResource res) + { + auto it = m_GLResourceRecords.find(res); + if(it != m_GLResourceRecords.end()) + return it->second; + + return ResourceManager::GetResourceRecord(GetID(res)); + } + + private: + bool SerialisableResource(ResourceId id, GLResourceRecord *record); + + bool ResourceTypeRelease(GLResource res) { return true; } + + bool Need_InitialState(GLResource res) { return false; } + bool Need_InitialStateChunk(GLResource res) { return false; } + bool Prepare_InitialState(GLResource res) { return true; } + bool Serialise_InitialState(GLResource res) { return true; } + void Create_InitialState(ResourceId id, GLResource live, bool hasData) { } + void Apply_InitialState(GLResource live, GLResource initial, uint32_t count) { } + + map m_GLResourceRecords; + + map m_CurrentResourceIds; + + WrappedOpenGL *m_GL; +}; + diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp new file mode 100644 index 0000000000..d967962cb9 --- /dev/null +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -0,0 +1,1315 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "gl_replay.h" +#include "gl_driver.h" +#include "gl_resources.h" + +#include "common/string_utils.h" + +GLReplay::GLReplay() +{ + m_pDriver = NULL; + m_Proxy = false; + + RDCEraseEl(m_ReplayCtx); + m_DebugCtx = NULL; + + m_OutputWindowID = 1; +} + +void GLReplay::Shutdown() +{ + delete m_pDriver; + + CloseReplayContext(); +} + +#pragma region Implemented + +void GLReplay::ReadLogInitialisation() +{ + MakeCurrentReplayContext(&m_ReplayCtx); + m_pDriver->ReadLogInitialisation(); +} + +void GLReplay::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType) +{ + MakeCurrentReplayContext(&m_ReplayCtx); + m_pDriver->ReplayLog(frameID, startEventID, endEventID, replayType); +} + +vector GLReplay::GetFrameRecord() +{ + return m_pDriver->GetFrameRecord(); +} + +ResourceId GLReplay::GetLiveID(ResourceId id) +{ + return m_pDriver->GetResourceManager()->GetLiveID(id); +} + +APIProperties GLReplay::GetAPIProperties() +{ + APIProperties ret; + + ret.pipelineType = ePipelineState_OpenGL; + + return ret; +} + +vector GLReplay::GetBuffers() +{ + vector ret; + + for(auto it=m_pDriver->m_Buffers.begin(); it != m_pDriver->m_Buffers.end(); ++it) + ret.push_back(it->first); + + return ret; +} + +vector GLReplay::GetTextures() +{ + vector ret; + + for(auto it=m_pDriver->m_Textures.begin(); it != m_pDriver->m_Textures.end(); ++it) + ret.push_back(it->first); + + return ret; +} + +void GLReplay::SetReplayData(GLWindowingData data) +{ + m_ReplayCtx = data; + + InitDebugData(); +} + +void GLReplay::InitCallstackResolver() +{ + m_pDriver->GetSerialiser()->InitCallstackResolver(); +} + +bool GLReplay::HasCallstacks() +{ + return m_pDriver->GetSerialiser()->HasCallstacks(); +} + +Callstack::StackResolver *GLReplay::GetCallstackResolver() +{ + return m_pDriver->GetSerialiser()->GetCallstackResolver(); +} + +void GLReplay::CreateOutputWindowBackbuffer(OutputWindow &outwin) +{ + if(m_pDriver == NULL) return; + + MakeCurrentReplayContext(m_DebugCtx); + + WrappedOpenGL &gl = *m_pDriver; + + // create fake backbuffer for this output window. + // We'll make an FBO for this backbuffer on the replay context, so we can + // use the replay context to do the hard work of rendering to it, then just + // blit across to the real default framebuffer on the output window context + gl.glGenFramebuffers(1, &outwin.BlitData.windowFBO); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, outwin.BlitData.windowFBO); + + gl.glGenTextures(1, &outwin.BlitData.backbuffer); + gl.glBindTexture(eGL_TEXTURE_2D, outwin.BlitData.backbuffer); + + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGB8, outwin.width, outwin.height); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, outwin.BlitData.backbuffer, 0); + + outwin.BlitData.replayFBO = 0; +} + +void GLReplay::InitOutputWindow(OutputWindow &outwin) +{ + if(m_pDriver == NULL) return; + + MakeCurrentReplayContext(&outwin); + + WrappedOpenGL &gl = *m_pDriver; + + gl.glGenVertexArrays(1, &outwin.BlitData.emptyVAO); + gl.glBindVertexArray(outwin.BlitData.emptyVAO); +} + +bool GLReplay::CheckResizeOutputWindow(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return false; + + OutputWindow &outw = m_OutputWindows[id]; + + if(outw.wnd == 0) + return false; + + int32_t w, h; + GetOutputWindowDimensions(id, w, h); + + if(w != outw.width || h != outw.height) + { + outw.width = w; + outw.height = h; + + MakeCurrentReplayContext(m_DebugCtx); + + WrappedOpenGL &gl = *m_pDriver; + + gl.glDeleteTextures(1, &outw.BlitData.backbuffer); + gl.glDeleteFramebuffers(1, &outw.BlitData.windowFBO); + + CreateOutputWindowBackbuffer(outw); + + return true; + } + + return false; +} + +void GLReplay::BindOutputWindow(uint64_t id, bool depth) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + MakeCurrentReplayContext(m_DebugCtx); + + m_pDriver->glBindFramebuffer(eGL_FRAMEBUFFER, outw.BlitData.windowFBO); + m_pDriver->glViewport(0, 0, outw.width, outw.height); + + DebugData.outWidth = float(outw.width); DebugData.outHeight = float(outw.height); +} + +void GLReplay::ClearOutputWindowColour(uint64_t id, float col[4]) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + MakeCurrentReplayContext(m_DebugCtx); + + m_pDriver->glClearBufferfv(eGL_COLOR, 0, col); +} + +void GLReplay::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + MakeCurrentReplayContext(&outw); + + m_pDriver->glClearBufferfv(eGL_DEPTH, 0, &depth); +} + +void GLReplay::FlipOutputWindow(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + MakeCurrentReplayContext(&outw); + + WrappedOpenGL &gl = *m_pDriver; + + gl.glBindFramebuffer(eGL_FRAMEBUFFER, 0); + gl.glViewport(0, 0, outw.width, outw.height); + + gl.glUseProgram(DebugData.blitProg); + + gl.glActiveTexture(eGL_TEXTURE0); + gl.glBindTexture(eGL_TEXTURE_2D, outw.BlitData.backbuffer); + + gl.glBindVertexArray(outw.BlitData.emptyVAO); + gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + + SwapBuffers(&outw); +} + +vector GLReplay::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) +{ + vector ret; + + if(m_pDriver->m_Buffers.find(buff) == m_pDriver->m_Buffers.end()) + { + RDCWARN("Requesting data for non-existant buffer %llu", buff); + return ret; + } + + auto &buf = m_pDriver->m_Buffers[buff]; + + if(len > 0 && offset+len > buf.size) + { + RDCWARN("Attempting to read off the end of the array. Will be clamped"); + len = RDCMIN(len, uint32_t(buf.size-offset)); + } + else if(len == 0) + { + len = (uint32_t)buf.size; + } + + ret.resize(len); + + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(m_DebugCtx); + + gl.glBindBuffer(eGL_COPY_READ_BUFFER, buf.resource.name); + + gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, (GLintptr)offset, (GLsizeiptr)len, &ret[0]); + + return ret; +} + +bool GLReplay::IsRenderOutput(ResourceId id) +{ + for(int32_t i=0; i < m_CurPipelineState.m_FB.Color.count; i++) + { + if(m_CurPipelineState.m_FB.Color[i] == id) + return true; + } + + if(m_CurPipelineState.m_FB.Depth == id || + m_CurPipelineState.m_FB.Stencil == id) + return true; + + return false; +} + +#pragma endregion + +#pragma region Mostly Implemented + +FetchTexture GLReplay::GetTexture(ResourceId id) +{ + FetchTexture tex; + + MakeCurrentReplayContext(&m_ReplayCtx); + + auto &res = m_pDriver->m_Textures[id]; + + if(res.resource.Namespace == eResUnknown) + { + RDCERR("Details for invalid texture id %llu requested", id); + RDCEraseEl(tex); + return tex; + } + + WrappedOpenGL &gl = *m_pDriver; + + tex.ID = m_pDriver->GetResourceManager()->GetOriginalID(id); + + gl.glBindTexture(res.curType, res.resource.name); + + // if I call this for levels 1, 2, .. etc. Can I get sizes that aren't mip dimensions? + GLint width = 1, height = 1, depth = 1, samples=1; + gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_WIDTH, &width); + gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_HEIGHT, &height); + gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_DEPTH, &depth); + gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_SAMPLES, &samples); + + if(res.width == 0) + { + RDCWARN("TextureData::width didn't get filled out, setting at last minute"); + res.width = width; + } + if(res.height == 0) + { + RDCWARN("TextureData::height didn't get filled out, setting at last minute"); + res.height = height; + } + if(res.depth == 0) + { + RDCWARN("TextureData::depth didn't get filled out, setting at last minute"); + res.depth = depth; + } + + // reasonably common defaults + tex.msQual = 0; + tex.msSamp = 1; + tex.width = tex.height = tex.depth = tex.arraysize = 1; + tex.cubemap = false; + + switch(res.curType) + { + case eGL_TEXTURE_1D: + case eGL_TEXTURE_BUFFER: + tex.dimension = 1; + tex.width = (uint32_t)width; + break; + case eGL_TEXTURE_1D_ARRAY: + tex.dimension = 1; + tex.width = (uint32_t)width; + tex.arraysize = depth; + break; + case eGL_TEXTURE_2D: + case eGL_TEXTURE_RECTANGLE: + case eGL_TEXTURE_2D_MULTISAMPLE: + case eGL_TEXTURE_CUBE_MAP: + tex.dimension = 2; + tex.width = (uint32_t)width; + tex.height = (uint32_t)height; + tex.cubemap = (res.curType == eGL_TEXTURE_CUBE_MAP); + tex.msSamp = (res.curType == eGL_TEXTURE_2D_MULTISAMPLE ? samples : 1); + break; + case eGL_TEXTURE_2D_ARRAY: + case eGL_TEXTURE_2D_MULTISAMPLE_ARRAY: + case eGL_TEXTURE_CUBE_MAP_ARRAY: + tex.dimension = 2; + tex.width = (uint32_t)width; + tex.height = (uint32_t)height; + tex.arraysize = depth; + tex.cubemap = (res.curType == eGL_TEXTURE_CUBE_MAP_ARRAY); + tex.msSamp = (res.curType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY ? samples : 1); + break; + case eGL_TEXTURE_3D: + tex.dimension = 3; + tex.width = (uint32_t)width; + tex.height = (uint32_t)height; + tex.depth = (uint32_t)depth; + break; + + default: + tex.dimension = 2; + RDCERR("Unexpected texture enum %hs", ToStr::Get(res.curType).c_str()); + } + + GLint immut = 0; + gl.glGetTexParameteriv(res.curType, eGL_TEXTURE_IMMUTABLE_FORMAT, &immut); + + if(immut) + { + gl.glGetTexParameteriv(res.curType, eGL_TEXTURE_IMMUTABLE_LEVELS, &immut); + tex.mips = (uint32_t)immut; + } + else + { + // assuming complete texture + GLint mips = 1; + gl.glGetTexParameteriv(res.curType, eGL_TEXTURE_MAX_LEVEL, &mips); + tex.mips = (uint32_t)mips; + } + + tex.numSubresources = tex.mips*tex.arraysize; + + // surely this will be the same for each level... right? that would be insane if it wasn't + GLint fmt = 0; + gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_INTERNAL_FORMAT, &fmt); + + tex.format = MakeResourceFormat(gl, res.curType, (GLenum)fmt); + + string str = ""; + char name[128] = {0}; + gl.glGetObjectLabel(eGL_TEXTURE, res.resource.name, 127, NULL, name); + str = name; + tex.customName = true; + + if(str == "") + { + tex.customName = false; + str = StringFormat::Fmt("Texture%dD %llu", tex.dimension, tex.ID); + } + + tex.name = widen(str); + + tex.creationFlags = eTextureCreate_SRV; + if(tex.format.compType == eCompType_Depth) + tex.creationFlags |= eTextureCreate_DSV; + GLNOTIMP("creationFlags are not calculated yet"); + + tex.byteSize = 0; + GLNOTIMP("Not calculating bytesize"); + + return tex; +} + +FetchBuffer GLReplay::GetBuffer(ResourceId id) +{ + FetchBuffer ret; + + MakeCurrentReplayContext(&m_ReplayCtx); + + auto &res = m_pDriver->m_Buffers[id]; + + if(res.resource.Namespace == eResUnknown) + { + RDCERR("Details for invalid buffer id %llu requested", id); + RDCEraseEl(ret); + return ret; + } + + WrappedOpenGL &gl = *m_pDriver; + + ret.ID = m_pDriver->GetResourceManager()->GetOriginalID(id); + + gl.glBindBuffer(res.curType, res.resource.name); + + ret.structureSize = 0; + GLNOTIMP("Not fetching structure size (if there's an equivalent)"); + + ret.creationFlags = 0; + switch(res.curType) + { + case eGL_ARRAY_BUFFER: + ret.creationFlags = eBufferCreate_VB; + break; + case eGL_ELEMENT_ARRAY_BUFFER: + ret.creationFlags = eBufferCreate_IB; + break; + default: + RDCERR("Unexpected buffer type %hs", ToStr::Get(res.curType).c_str()); + } + + GLint size; + gl.glGetBufferParameteriv(res.curType, eGL_BUFFER_SIZE, &size); + + ret.byteSize = ret.length = (uint32_t)size; + + if(res.size == 0) + { + RDCWARN("BufferData::size didn't get filled out, setting at last minute"); + res.size = ret.byteSize; + } + + string str = ""; + char name[128] = {0}; + gl.glGetObjectLabel(eGL_BUFFER, res.resource.name, 127, NULL, name); + str = name; + ret.customName = true; + + if(str == "") + { + ret.customName = false; + str = StringFormat::Fmt("Buffer %llu", ret.ID); + } + + ret.name = widen(str); + + return ret; +} + +ShaderReflection *GLReplay::GetShader(ResourceId id) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(&m_ReplayCtx); + + GLuint curProg = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg); + + auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(curProg))]; + auto &shaderDetails = m_pDriver->m_Shaders[id]; + + auto &refl = shaderDetails.reflection; + + // initialise reflection data + // TODO: do this earlier. In glLinkProgram? + if(refl.DebugInfo.files.count == 0) + { + refl.DebugInfo.entryFunc = "main"; + refl.DebugInfo.compileFlags = 0; + create_array_uninit(refl.DebugInfo.files, shaderDetails.sources.size()); + for(size_t i=0; i < shaderDetails.sources.size(); i++) + { + refl.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i); + refl.DebugInfo.files[i].second = shaderDetails.sources[i]; + } + + refl.Disassembly = ""; + + vector resources; + + GLint numUniforms = 0; + gl.glGetProgramInterfaceiv(curProg, eGL_UNIFORM, eGL_ACTIVE_RESOURCES, &numUniforms); + + const size_t numProps = 6; + + GLenum resProps[numProps] = { + eGL_REFERENCED_BY_VERTEX_SHADER, + + eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, eGL_BLOCK_INDEX, eGL_ARRAY_SIZE, + }; + + if(shaderDetails.type == eGL_VERTEX_SHADER) resProps[0] = eGL_REFERENCED_BY_VERTEX_SHADER; + if(shaderDetails.type == eGL_TESS_CONTROL_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_CONTROL_SHADER; + if(shaderDetails.type == eGL_TESS_EVALUATION_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_EVALUATION_SHADER; + if(shaderDetails.type == eGL_GEOMETRY_SHADER) resProps[0] = eGL_REFERENCED_BY_GEOMETRY_SHADER; + if(shaderDetails.type == eGL_FRAGMENT_SHADER) resProps[0] = eGL_REFERENCED_BY_FRAGMENT_SHADER; + if(shaderDetails.type == eGL_COMPUTE_SHADER) resProps[0] = eGL_REFERENCED_BY_COMPUTE_SHADER; + + for(GLint u=0; u < numUniforms; u++) + { + GLint values[numProps]; + gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values); + + // skip if unused by this stage + if(values[0] == GL_FALSE) + continue; + + ShaderResource res; + res.IsSampler = false; // no separate sampler objects in GL + + if(values[1] == GL_SAMPLER_2D) + { + res.IsSRV = true; + res.IsTexture = true; + res.IsUAV = false; + res.resType = eResType_Texture2D; + res.variableType.descriptor.name = "sampler2D"; + res.variableType.descriptor.rows = 1; + res.variableType.descriptor.cols = 4; + res.variableType.descriptor.elements = 1; + } + else if(values[1] == GL_INT_SAMPLER_1D) + { + res.IsSRV = true; + res.IsTexture = true; + res.IsUAV = false; + res.resType = eResType_Texture1D; + res.variableType.descriptor.name = "isampler1D"; + res.variableType.descriptor.rows = 1; + res.variableType.descriptor.cols = 4; + res.variableType.descriptor.elements = 1; + } + else + { + // fill in more sampler types + continue; + } + + res.variableAddress = values[3]; + + create_array_uninit(res.name, values[2]+1); + gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, res.name.elems); + res.name.count--; // trim off trailing null + + resources.push_back(res); + } + + refl.Resources = resources; + + vector globalUniforms; + + for(GLint u=0; u < numUniforms; u++) + { + GLint values[numProps]; + gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values); + + // skip if unused by this stage + if(values[0] == GL_FALSE) + continue; + + // don't look at block uniforms just yet + if(values[4] != -1) + { + GLNOTIMP("Not fetching uniforms in UBOs (should become their own ConstantBlocks)"); + continue; + } + + ShaderConstant var; + + if(values[1] == GL_FLOAT_VEC4) + { + var.type.descriptor.name = "vec4"; + var.type.descriptor.rows = 1; + var.type.descriptor.cols = 4; + var.type.descriptor.elements = values[5]; + } + else if(values[1] == GL_FLOAT_VEC3) + { + var.type.descriptor.name = "vec3"; + var.type.descriptor.rows = 1; + var.type.descriptor.cols = 3; + var.type.descriptor.elements = values[5]; + } + else if(values[1] == GL_FLOAT_MAT4) + { + var.type.descriptor.name = "mat4"; + var.type.descriptor.rows = 4; + var.type.descriptor.cols = 4; + var.type.descriptor.elements = values[5]; + } + else + { + // fill in more uniform types + continue; + } + + var.reg.vec = values[3]; + var.reg.comp = 0; + + create_array_uninit(var.name, values[2]+1); + gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, var.name.elems); + var.name.count--; // trim off trailing null + + if(strchr(var.name.elems, '.')) + { + GLNOTIMP("Variable contains . - structure not reconstructed"); + } + + globalUniforms.push_back(var); + } + + vector cbuffers; + + if(!globalUniforms.empty()) + { + ConstantBlock globals; + globals.name = "Globals"; + globals.bufferAddress = -1; + globals.variables = globalUniforms; + + cbuffers.push_back(globals); + } + + // here we would iterate over UNIFORM_BLOCKs or similar + + // TODO: fill in Interfaces with shader subroutines? + // TODO: find a way of generating input/output signature. + // The only way I can think of doing this is to generate separable programs for each + // shader stage, but that requires modifying the glsl to redeclare built-in blocks if necessary. + + refl.ConstantBlocks = cbuffers; + } + + // update samplers with latest uniform values + for(int32_t i=0; i < refl.Resources.count; i++) + { + if(refl.Resources.elems[i].IsSRV && refl.Resources.elems[i].IsTexture) + gl.glGetUniformiv(curProg, refl.Resources.elems[i].variableAddress, (GLint *)&refl.Resources.elems[i].bindPoint); + } + + return &refl; +} + +void GLReplay::SavePipelineState() +{ + GLPipelineState &pipe = m_CurPipelineState; + WrappedOpenGL &gl = *m_pDriver; + GLResourceManager *rm = m_pDriver->GetResourceManager(); + + MakeCurrentReplayContext(&m_ReplayCtx); + + // Index buffer + + pipe.m_VtxIn.ibuffer.Offset = m_pDriver->m_LastIndexOffset; + + pipe.m_VtxIn.ibuffer.Format = ResourceFormat(); + pipe.m_VtxIn.ibuffer.Format.special = false; + pipe.m_VtxIn.ibuffer.Format.compCount = 1; + pipe.m_VtxIn.ibuffer.Format.compType = eCompType_UInt; + switch(m_pDriver->m_LastIndexSize) + { + default: + break; + case eGL_UNSIGNED_BYTE: + pipe.m_VtxIn.ibuffer.Format.compByteWidth = 1; + pipe.m_VtxIn.ibuffer.Format.strname = L"GL_UNSIGNED_BYTE"; + break; + case eGL_UNSIGNED_SHORT: + pipe.m_VtxIn.ibuffer.Format.compByteWidth = 2; + pipe.m_VtxIn.ibuffer.Format.strname = L"GL_UNSIGNED_SHORT"; + break; + case eGL_UNSIGNED_INT: + pipe.m_VtxIn.ibuffer.Format.compByteWidth = 4; + pipe.m_VtxIn.ibuffer.Format.strname = L"GL_UNSIGNED_INT"; + break; + } + + GLint curIdxBuf = 0; + gl.glGetIntegerv(eGL_ELEMENT_ARRAY_BUFFER_BINDING, &curIdxBuf); + + pipe.m_VtxIn.ibuffer.Buffer = rm->GetOriginalID(rm->GetID(BufferRes(curIdxBuf))); + + // Vertex buffers and attributes + GLint numVBufferBindings = 16; + gl.glGetIntegerv(eGL_MAX_VERTEX_ATTRIB_BINDINGS, &numVBufferBindings); + + GLint numVAttribBindings = 16; + gl.glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, &numVAttribBindings); + + create_array_uninit(pipe.m_VtxIn.vbuffers, numVBufferBindings); + create_array_uninit(pipe.m_VtxIn.attributes, numVAttribBindings); + + for(GLuint i=0; i < (GLuint)numVBufferBindings; i++) + { + GLint vb = 0; + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, &vb); + pipe.m_VtxIn.vbuffers[i].Buffer = rm->GetOriginalID(rm->GetID(BufferRes(vb))); + + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Stride); + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Offset); + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Divisor); + pipe.m_VtxIn.vbuffers[i].PerInstance = (pipe.m_VtxIn.vbuffers[i].Divisor != 0); + } + + for(GLuint i=0; i < (GLuint)numVAttribBindings; i++) + { + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *)&pipe.m_VtxIn.attributes[i].Enabled); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_BINDING, (GLint *)&pipe.m_VtxIn.attributes[i].BufferSlot); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_RELATIVE_OFFSET, (GLint*)&pipe.m_VtxIn.attributes[i].RelativeOffset); + + GLenum type = eGL_FLOAT; + GLint normalized = 0; + + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&type); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &normalized); + + ResourceFormat fmt; + + fmt.special = false; + fmt.compCount = 4; + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, (GLint *)&fmt.compCount); + + switch(type) + { + default: + case eGL_BYTE: + fmt.compByteWidth = 1; + fmt.compType = normalized ? eCompType_SInt : eCompType_SNorm; + fmt.strname = StringFormat::WFmt(L"GL_BYTE%d", fmt.compCount) + (normalized ? L"" : L"_SNORM"); + break; + case eGL_UNSIGNED_BYTE: + fmt.compByteWidth = 1; + fmt.compType = normalized ? eCompType_UInt : eCompType_UNorm; + fmt.strname = StringFormat::WFmt(L"GL_UNSIGNED_BYTE%d", fmt.compCount) + (normalized ? L"" : L"_UNORM"); + break; + case eGL_SHORT: + fmt.compByteWidth = 2; + fmt.compType = normalized ? eCompType_SInt : eCompType_SNorm; + fmt.strname = StringFormat::WFmt(L"GL_SHORT%d", fmt.compCount) + (normalized ? L"" : L"_SNORM"); + break; + case eGL_UNSIGNED_SHORT: + fmt.compByteWidth = 2; + fmt.compType = normalized ? eCompType_UInt : eCompType_UNorm; + fmt.strname = StringFormat::WFmt(L"GL_UNSIGNED_SHORT%d", fmt.compCount) + (normalized ? L"" : L"_UNORM"); + break; + case eGL_INT: + fmt.compByteWidth = 4; + fmt.compType = normalized ? eCompType_SInt : eCompType_SNorm; + fmt.strname = StringFormat::WFmt(L"GL_INT%d", fmt.compCount) + (normalized ? L"" : L"_SNORM"); + break; + case eGL_UNSIGNED_INT: + fmt.compByteWidth = 4; + fmt.compType = normalized ? eCompType_UInt : eCompType_UNorm; + fmt.strname = StringFormat::WFmt(L"GL_UNSIGNED_INT%d", fmt.compCount) + (normalized ? L"" : L"_UNORM"); + break; + case eGL_FLOAT: + fmt.compByteWidth = 4; + fmt.compType = eCompType_Float; + fmt.strname = StringFormat::WFmt(L"GL_FLOAT%d", fmt.compCount); + break; + case eGL_DOUBLE: + fmt.compByteWidth = 8; + fmt.compType = eCompType_Double; + fmt.strname = StringFormat::WFmt(L"GL_DOUBLE%d", fmt.compCount); + break; + case eGL_HALF_FLOAT: + fmt.compByteWidth = 2; + fmt.compType = eCompType_Float; + fmt.strname = StringFormat::WFmt(L"GL_HALF_FLOAT%d", fmt.compCount); + break; + case eGL_INT_2_10_10_10_REV: + fmt.special = true; + fmt.specialFormat = eSpecial_R10G10B10A2; + fmt.compCount = 4; + fmt.compType = eCompType_UInt; + fmt.strname = L"GL_INT_2_10_10_10_REV"; + break; + case eGL_UNSIGNED_INT_2_10_10_10_REV: + fmt.special = true; + fmt.specialFormat = eSpecial_R10G10B10A2; + fmt.compCount = 4; + fmt.compType = eCompType_SInt; + fmt.strname = L"eGL_UNSIGNED_INT_2_10_10_10_REV"; + break; + case eGL_UNSIGNED_INT_10F_11F_11F_REV: + fmt.special = true; + fmt.specialFormat = eSpecial_R11G11B10; + fmt.compCount = 3; + fmt.compType = eCompType_SInt; + fmt.strname = L"eGL_UNSIGNED_INT_10F_11F_11F_REV"; + break; + } + + pipe.m_VtxIn.attributes[i].Format = fmt; + } + + switch(m_pDriver->m_LastDrawMode) + { + default: + pipe.m_VtxIn.Topology = eTopology_Unknown; + break; + case GL_POINTS: + pipe.m_VtxIn.Topology = eTopology_PointList; + break; + case GL_LINE_STRIP: + pipe.m_VtxIn.Topology = eTopology_LineStrip; + break; + case GL_LINE_LOOP: + pipe.m_VtxIn.Topology = eTopology_LineLoop; + break; + case GL_LINES: + pipe.m_VtxIn.Topology = eTopology_LineList; + break; + case GL_LINE_STRIP_ADJACENCY: + pipe.m_VtxIn.Topology = eTopology_LineStrip_Adj; + break; + case GL_LINES_ADJACENCY: + pipe.m_VtxIn.Topology = eTopology_LineList_Adj; + break; + case GL_TRIANGLE_STRIP: + pipe.m_VtxIn.Topology = eTopology_TriangleStrip; + break; + case GL_TRIANGLE_FAN: + pipe.m_VtxIn.Topology = eTopology_TriangleFan; + break; + case GL_TRIANGLES: + pipe.m_VtxIn.Topology = eTopology_TriangleList; + break; + case GL_TRIANGLE_STRIP_ADJACENCY: + pipe.m_VtxIn.Topology = eTopology_TriangleStrip_Adj; + break; + case GL_TRIANGLES_ADJACENCY: + pipe.m_VtxIn.Topology = eTopology_TriangleList_Adj; + break; + case GL_PATCHES: + { + GLint patchCount = 3; + gl.glGetIntegerv(eGL_PATCH_VERTICES, &patchCount); + pipe.m_VtxIn.Topology = PrimitiveTopology(eTopology_PatchList_1CPs+patchCount); + break; + } + } + + // Shader stages + + GLuint curProg = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg); + + auto &progDetails = m_pDriver->m_Programs[rm->GetID(ProgramRes(curProg))]; + + RDCASSERT(progDetails.shaders.size()); + + for(size_t i=0; i < progDetails.shaders.size(); i++) + { + if(m_pDriver->m_Shaders[ progDetails.shaders[i] ].type == eGL_VERTEX_SHADER) + pipe.m_VS.Shader = rm->GetOriginalID(progDetails.shaders[i]); + else if(m_pDriver->m_Shaders[ progDetails.shaders[i] ].type == eGL_FRAGMENT_SHADER) + pipe.m_FS.Shader = rm->GetOriginalID(progDetails.shaders[i]); + } + + pipe.m_VS.stage = eShaderStage_Vertex; + pipe.m_TCS.stage = eShaderStage_Tess_Control; + pipe.m_TES.stage = eShaderStage_Tess_Eval; + pipe.m_GS.stage = eShaderStage_Geometry; + pipe.m_FS.stage = eShaderStage_Fragment; + pipe.m_CS.stage = eShaderStage_Compute; + + // Textures + + GLint numTexUnits = 8; + gl.glGetIntegerv(eGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numTexUnits); + create_array_uninit(pipe.Textures, numTexUnits); + + GLenum activeTexture = eGL_TEXTURE0; + gl.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint*)&activeTexture); + + // GL is ass-backwards in its handling of texture units. When a shader is active + // the types in the glsl samplers inform which targets are used from which texture units + // + // So texture unit 5 can have a 2D bound (texture 52) and a Cube bound (texture 77). + // * if a uniform sampler2D has value 5 then the 2D texture is used, and we sample from 52 + // * if a uniform samplerCube has value 5 then the Cube texture is used, and we sample from 77 + // It's illegal for both a sampler2D and samplerCube to both have the same value (or any two + // different types). It makes it all rather pointless and needlessly complex. + // + // What we have to do then, is consider the program, look at the values of the uniforms, and + // then get the appropriate current binding based on the uniform type. We can warn/alert the + // user if we hit the illegal case of two uniforms with different types but the same value + // + // Handling is different if no shaders are active, but we don't consider that case. + + + // prefetch uniform values in GetShader() + ShaderReflection *refls[6]; + for(size_t s=0; s < progDetails.shaders.size(); s++) + refls[s] = GetShader(progDetails.shaders[s]); + + for(GLint unit=0; unit < numTexUnits; unit++) + { + GLenum binding = eGL_UNKNOWN_ENUM; + GLenum target = eGL_UNKNOWN_ENUM; + + for(size_t s=0; s < progDetails.shaders.size(); s++) + { + if(refls[s] == NULL) continue; + + for(int32_t r=0; r < refls[s]->Resources.count; r++) + { + // bindPoint is the uniform value for this sampler + if(refls[s]->Resources[r].bindPoint == (uint32_t)unit) + { + GLenum t = eGL_UNKNOWN_ENUM; + + switch(refls[s]->Resources[r].resType) + { + case eResType_None: + t = eGL_UNKNOWN_ENUM; + break; + case eResType_Buffer: + t = eGL_TEXTURE_BINDING_BUFFER; + break; + case eResType_Texture1D: + t = eGL_TEXTURE_BINDING_1D; + target = eGL_TEXTURE_1D; + break; + case eResType_Texture1DArray: + t = eGL_TEXTURE_BINDING_1D_ARRAY; + target = eGL_TEXTURE_1D_ARRAY; + break; + case eResType_Texture2D: + t = eGL_TEXTURE_BINDING_2D; + target = eGL_TEXTURE_2D; + break; + case eResType_Texture2DArray: + t = eGL_TEXTURE_BINDING_2D_ARRAY; + target = eGL_TEXTURE_2D_ARRAY; + break; + case eResType_Texture2DMS: + t = eGL_TEXTURE_BINDING_2D_MULTISAMPLE; + target = eGL_TEXTURE_2D_MULTISAMPLE; + break; + case eResType_Texture2DMSArray: + t = eGL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY; + target = eGL_TEXTURE_2D_MULTISAMPLE_ARRAY; + break; + case eResType_Texture3D: + t = eGL_TEXTURE_BINDING_3D; + target = eGL_TEXTURE_3D; + break; + case eResType_TextureCube: + t = eGL_TEXTURE_BINDING_CUBE_MAP; + target = eGL_TEXTURE_CUBE_MAP; + break; + case eResType_TextureCubeArray: + t = eGL_TEXTURE_BINDING_CUBE_MAP_ARRAY; + target = eGL_TEXTURE_CUBE_MAP_ARRAY; + break; + } + + if(binding == eGL_UNKNOWN_ENUM) + { + binding = t; + } + else if(binding == t) + { + // two uniforms with the same type pointing to the same slot is fine + binding = t; + } + else if(binding != t) + { + RDCWARN("Two uniforms pointing to texture unit %d with types %s and %s", unit, ToStr::Get(binding).c_str(), ToStr::Get(t).c_str()); + } + } + } + } + + if(binding != eGL_UNKNOWN_ENUM) + { + gl.glActiveTexture(GLenum(eGL_TEXTURE0+unit)); + + GLuint tex; + gl.glGetIntegerv(binding, (GLint *)&tex); + + // very bespoke/specific + GLint firstSlice = 0; + gl.glGetTexParameteriv(target, eGL_TEXTURE_VIEW_MIN_LEVEL, &firstSlice); + + pipe.Textures[unit].Resource = rm->GetOriginalID(rm->GetID(TextureRes(tex))); + pipe.Textures[unit].FirstSlice = (uint32_t)firstSlice; + } + else + { + // what should we do in this case? there could be something bound just not used, + // it'd be nice to return that + } + } + + gl.glActiveTexture(activeTexture); + + GLuint curFBO = 0; + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&curFBO); + + GLint numCols = 8; + gl.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &numCols); + + GLuint curCol[32] = { 0 }; + GLuint curDepth = 0; + GLuint curStencil = 0; + + RDCASSERT(numCols <= 32); + + // we should never bind the true default framebuffer - if the app did, we will have our fake bound + RDCASSERT(curFBO != 0); + + { + for(GLint i=0; i < numCols; i++) + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0+i), eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curCol[i]); + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curDepth); + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curStencil); + } + + pipe.m_FB.FBO = rm->GetOriginalID(rm->GetID(FramebufferRes(curFBO))); + create_array_uninit(pipe.m_FB.Color, numCols); + for(GLint i=0; i < numCols; i++) + pipe.m_FB.Color[i] = rm->GetOriginalID(rm->GetID(TextureRes(curCol[i]))); + + pipe.m_FB.Depth = rm->GetOriginalID(rm->GetID(TextureRes(curDepth))); + pipe.m_FB.Stencil = rm->GetOriginalID(rm->GetID(TextureRes(curStencil))); +} + +void GLReplay::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(&m_ReplayCtx); + + GLuint curProg = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg); + + auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(curProg))]; + auto &shaderDetails = m_pDriver->m_Shaders[shader]; + + GLint numUniforms = 0; + gl.glGetProgramInterfaceiv(curProg, eGL_UNIFORM, eGL_ACTIVE_RESOURCES, &numUniforms); + + const size_t numProps = 6; + + GLenum resProps[numProps] = { + eGL_REFERENCED_BY_VERTEX_SHADER, + + eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, eGL_BLOCK_INDEX, eGL_ARRAY_SIZE, + }; + + if(shaderDetails.type == eGL_VERTEX_SHADER) resProps[0] = eGL_REFERENCED_BY_VERTEX_SHADER; + if(shaderDetails.type == eGL_TESS_CONTROL_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_CONTROL_SHADER; + if(shaderDetails.type == eGL_TESS_EVALUATION_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_EVALUATION_SHADER; + if(shaderDetails.type == eGL_GEOMETRY_SHADER) resProps[0] = eGL_REFERENCED_BY_GEOMETRY_SHADER; + if(shaderDetails.type == eGL_FRAGMENT_SHADER) resProps[0] = eGL_REFERENCED_BY_FRAGMENT_SHADER; + if(shaderDetails.type == eGL_COMPUTE_SHADER) resProps[0] = eGL_REFERENCED_BY_COMPUTE_SHADER; + + for(GLint u=0; u < numUniforms; u++) + { + GLint values[numProps]; + gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values); + + if(values[0] == GL_FALSE) + continue; + + // don't look at block uniforms just yet + if(values[4] != -1) + continue; + + ShaderVariable var; + + RDCASSERT(values[5] <= 1); // don't handle arrays yet + + if(values[1] == GL_FLOAT_VEC4) + { + var.type = eVar_Float; + var.columns = 4; + var.rows = 1; + + gl.glGetUniformfv(curProg, values[3], var.value.fv); + } + else if(values[1] == GL_FLOAT_VEC3) + { + var.type = eVar_Float; + var.columns = 3; + var.rows = 1; + + gl.glGetUniformfv(curProg, values[3], var.value.fv); + } + else if(values[1] == GL_FLOAT_MAT4) + { + var.type = eVar_Float; + var.columns = 4; + var.rows = 4; + + gl.glGetUniformfv(curProg, values[3], var.value.fv); + } + else + { + continue; + } + + create_array_uninit(var.name, values[2]+1); + gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, var.name.elems); + var.name.count--; // trim off trailing null + + outvars.push_back(var); + } +} + +#pragma endregion + +bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval) +{ + RDCUNIMPLEMENTED(); + return false; +} + +bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram) +{ + RDCUNIMPLEMENTED(); + return false; +} + +void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) +{ + GLNOTIMP("GLReplay::InitPostVSBuffers"); +} + +vector GLReplay::GetUsage(ResourceId id) +{ + GLNOTIMP("GetUsage"); + return vector(); +} + +void GLReplay::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ + RDCUNIMPLEMENTED(); +} + +void GLReplay::FreeTargetResource(ResourceId id) +{ + RDCUNIMPLEMENTED(); +} + +void GLReplay::FreeCustomShader(ResourceId id) +{ + RDCUNIMPLEMENTED(); +} + +PostVSMeshData GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +{ + PostVSMeshData ret; + RDCEraseEl(ret); + + GLNOTIMP("GLReplay::GetPostVSBuffers"); + + return ret; +} + +byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize) +{ + RDCUNIMPLEMENTED(); + return NULL; +} + +void GLReplay::ReplaceResource(ResourceId from, ResourceId to) +{ + RDCUNIMPLEMENTED(); +} + +void GLReplay::RemoveReplacement(ResourceId id) +{ + RDCUNIMPLEMENTED(); +} + +void GLReplay::TimeDrawcalls(rdctype::array &arr) +{ + RDCUNIMPLEMENTED(); +} + +bool GLReplay::SaveTexture(ResourceId tex, uint32_t saveMip, wstring path) +{ + RDCUNIMPLEMENTED(); + return false; +} + +void GLReplay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) +{ + RDCUNIMPLEMENTED(); +} + +void GLReplay::BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) +{ + RDCUNIMPLEMENTED(); +} + +ShaderDebugTrace GLReplay::DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) +{ + RDCUNIMPLEMENTED(); + return ShaderDebugTrace(); +} + +ShaderDebugTrace GLReplay::DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) +{ + RDCUNIMPLEMENTED(); + return ShaderDebugTrace(); +} + +ShaderDebugTrace GLReplay::DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]) +{ + RDCUNIMPLEMENTED(); + return ShaderDebugTrace(); +} + +ResourceId GLReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) +{ + RDCUNIMPLEMENTED(); + return ResourceId(); +} + +ResourceId GLReplay::CreateProxyTexture( FetchTexture templateTex ) +{ + RDCUNIMPLEMENTED(); + return ResourceId(); +} + +void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize) +{ + RDCUNIMPLEMENTED(); +} + +const GLHookSet &GetRealFunctions(); + +// defined in gl_replay_.cpp +ReplayCreateStatus GL_CreateReplayDevice(const wchar_t *logfile, IReplayDriver **driver); + +static DriverRegistration GLDriverRegistration(RDC_OpenGL, L"OpenGL", &GL_CreateReplayDevice); diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h new file mode 100644 index 0000000000..2aa2f717f1 --- /dev/null +++ b/renderdoc/driver/gl/gl_replay.h @@ -0,0 +1,226 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "gl_common.h" +#include "replay/renderdoc.h" +#include "replay/replay_driver.h" +#include "core/core.h" + +class WrappedOpenGL; + +class GLReplay : public IReplayDriver +{ + public: + GLReplay(); + + void SetProxy(bool p) { m_Proxy = p; } + bool IsRemoteProxy() { return m_Proxy; } + + void Shutdown(); + + void SetDriver(WrappedOpenGL *d) { m_pDriver = d; } + + APIProperties GetAPIProperties(); + + vector GetBuffers(); + FetchBuffer GetBuffer(ResourceId id); + + vector GetTextures(); + FetchTexture GetTexture(ResourceId id); + + ShaderReflection *GetShader(ResourceId id); + + vector GetUsage(ResourceId id); + + vector GetFrameRecord(); + + void SavePipelineState(); + D3D11PipelineState GetD3D11PipelineState() { return D3D11PipelineState(); } + GLPipelineState GetGLPipelineState() { return m_CurPipelineState; } + + void FreeTargetResource(ResourceId id); + + void ReadLogInitialisation(); + void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); + void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); + + uint64_t MakeOutputWindow(void *w, bool depth); + void DestroyOutputWindow(uint64_t id); + bool CheckResizeOutputWindow(uint64_t id); + void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); + void ClearOutputWindowColour(uint64_t id, float col[4]); + void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil); + void BindOutputWindow(uint64_t id, bool depth); + bool IsOutputWindowVisible(uint64_t id); + void FlipOutputWindow(uint64_t id); + + void InitPostVSBuffers(uint32_t frameID, uint32_t eventID); + + ResourceId GetLiveID(ResourceId id); + + bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval); + bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram); + + PostVSMeshData GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + + vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize); + + void ReplaceResource(ResourceId from, ResourceId to); + void RemoveReplacement(ResourceId id); + + void TimeDrawcalls(rdctype::array &arr); + + bool SaveTexture(ResourceId tex, uint32_t saveMip, wstring path); + + void RenderMesh(int frameID, vector eventID, MeshDisplay cfg); + + void BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); + void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); + void FreeCustomShader(ResourceId id); + + bool RenderTexture(TextureDisplay cfg); + + void RenderCheckerboard(Vec3f light, Vec3f dark); + + void RenderHighlightBox(float w, float h, float scale); + + void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data); + + ShaderDebugTrace DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); + ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y); + ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]); + + ResourceId RenderOverlay(ResourceId cfg, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip); + + ResourceId CreateProxyTexture(FetchTexture templateTex); + void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize); + + bool IsRenderOutput(ResourceId id); + + void InitCallstackResolver(); + bool HasCallstacks(); + Callstack::StackResolver *GetCallstackResolver(); + + void SetReplayData(GLWindowingData data); + private: + + struct OutputWindow : public GLWindowingData + { + struct + { + // used to blit from defined FBO (VAOs not shared) + GLuint emptyVAO; + + // texture for the below FBO. Resizes with the window + GLuint backbuffer; + + // this FBO is on the debug GL context, not the window's GL context + // when rendering a texture or mesh etc, we render onto this FBO on + // the debug GL context, then blit onto the default framebuffer + // on the window's GL context. + // This is so we don't have to re-create any non-shared resource we + // need for debug rendering on the window's GL context. + GLuint windowFBO; + + // this FBO is the same as the above, but on the replay context, + // for any cases where we need to use the replay context (like + // re-rendering a draw). + GLuint replayFBO; + } BlitData; + + int width, height; + }; + + // any objects that are shared between contexts, we just initialise + // once + struct + { + float outWidth, outHeight; + + string blitvsSource; + string blitfsSource; + string genericvsSource; + string genericfsSource; + + // program that does a blit of texture from input to output, + // no transformation or scaling + GLuint blitProg; + + GLuint texDisplayProg; + + GLuint pointSampler; + GLuint linearSampler; + + GLuint checkerProg; + + GLuint genericProg; + + GLuint meshProg; + GLuint meshVAO; + + GLuint outlineStripVB; + GLuint outlineStripVAO; + + GLuint pickPixelTex; + GLuint pickPixelFBO; + + GLuint overlayTex; + GLuint overlayFBO; + GLint overlayTexWidth, overlayTexHeight; + + GLuint UBOs[2]; + static const size_t UBOSize = 64 * sizeof(Vec4f); + + GLuint emptyVAO; + } DebugData; + + void InitDebugData(); + + GLuint CreateShaderProgram(const char *vs, const char *ps); + + void InitOutputWindow(OutputWindow &outwin); + void CreateOutputWindowBackbuffer(OutputWindow &outwin); + + GLWindowingData m_ReplayCtx; + OutputWindow *m_DebugCtx; + + void MakeCurrentReplayContext(GLWindowingData *ctx); + void SwapBuffers(GLWindowingData *ctx); + void CloseReplayContext(); + + uint64_t m_OutputWindowID; + map m_OutputWindows; + + bool m_Proxy; + + WrappedOpenGL *m_pDriver; + + GLPipelineState m_CurPipelineState; +}; diff --git a/renderdoc/driver/gl/gl_replay_linux.cpp b/renderdoc/driver/gl/gl_replay_linux.cpp new file mode 100644 index 0000000000..ddd341e9ae --- /dev/null +++ b/renderdoc/driver/gl/gl_replay_linux.cpp @@ -0,0 +1,324 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "gl_replay.h" +#include "gl_driver.h" +#include "gl_resources.h" + +#include + +typedef Bool (*PFNGLXMAKECURRENTPROC)(Display *dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display *dpy, GLXContext ctx); +typedef void (*PFNGLXSWAPBUFFERSPROC)(Display *dpy, GLXDrawable drawable); + +PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfigProc = NULL; +PFNGLXCREATEPBUFFERPROC glXCreatePbufferProc = NULL; +PFNGLXDESTROYPBUFFERPROC glXDestroyPbufferProc = NULL; +PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsProc = NULL; +PFNGLXGETPROCADDRESSPROC glXGetFuncProc = NULL; +PFNGLXMAKECONTEXTCURRENTPROC glXMakeContextCurrentProc = NULL; +PFNGLXQUERYDRAWABLEPROC glXQueryDrawableProc = NULL; +PFNGLXDESTROYCONTEXTPROC glXDestroyCtxProc = NULL; +PFNGLXSWAPBUFFERSPROC glXSwapProc = NULL; + +void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) +{ + static GLWindowingData *prev = NULL; + + if(glXMakeContextCurrentProc && ctx && ctx != prev) + { + prev = ctx; + glXMakeContextCurrentProc(ctx->dpy, ctx->wnd, ctx->wnd, ctx->ctx); + } +} + +void GLReplay::SwapBuffers(GLWindowingData *ctx) +{ + glXSwapProc(ctx->dpy, ctx->wnd); +} + +void GLReplay::CloseReplayContext() +{ + if(glXDestroyCtxProc) + { + glXDestroyCtxProc(m_ReplayCtx.dpy, m_ReplayCtx.ctx); + } +} + +uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth) +{ + void **displayAndDrawable = (void **)wn; + + Display *dpy = NULL; + GLXDrawable wnd = 0; + + if(wn) + { + dpy = (Display *)displayAndDrawable[0]; + wnd = (GLXDrawable)displayAndDrawable[1]; + } + else + { + dpy = XOpenDisplay(NULL); + + if(dpy == NULL) + return 0; + + // don't need to care about the fb config as we won't be using the default framebuffer (backbuffer) + static int visAttribs[] = { 0 }; + int numCfgs = 0; + GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + + if(fbcfg == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't choose default framebuffer config"); + return 0; + } + + // don't care about pbuffer properties for same reason as backbuffer + int pbAttribs[] = { GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0 }; + + wnd = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs); + + XFree(fbcfg); + } + + static int visAttribs[] = { + GLX_X_RENDERABLE, True, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DOUBLEBUFFER, True, + 0 + }; + int numCfgs = 0; + GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + + if(fbcfg == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't choose default framebuffer config"); + return eReplayCreate_APIInitFailed; + } + + int attribs[64] = {0}; + int i=0; + + attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = 4; + attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = 3; + attribs[i++] = GLX_CONTEXT_FLAGS_ARB; + attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; + + GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs); + + if(ctx == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability"); + return 0; + } + + XFree(fbcfg); + + OutputWindow win; + win.dpy = dpy; + win.ctx = ctx; + win.wnd = wnd; + + glXQueryDrawableProc(dpy, wnd, GLX_WIDTH, (unsigned int *)&win.width); + glXQueryDrawableProc(dpy, wnd, GLX_HEIGHT, (unsigned int *)&win.height); + + MakeCurrentReplayContext(&win); + + InitOutputWindow(win); + CreateOutputWindowBackbuffer(win); + + uint64_t ret = m_OutputWindowID++; + + m_OutputWindows[ret] = win; + + return 0; +} + +void GLReplay::DestroyOutputWindow(uint64_t id) +{ + auto it = m_OutputWindows.find(id); + if(id == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + glXDestroyCtxProc(outw.dpy, outw.ctx); + + m_OutputWindows.erase(it); +} + +void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + glXQueryDrawableProc(outw.dpy, outw.wnd, GLX_WIDTH, (unsigned int *)&w); + glXQueryDrawableProc(outw.dpy, outw.wnd, GLX_HEIGHT, (unsigned int *)&h); +} + +bool GLReplay::IsOutputWindowVisible(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return false; + + GLNOTIMP("Optimisation missing - output window always returning true"); + + return true; +} + +const GLHookSet &GetRealFunctions(); + +ReplayCreateStatus GL_CreateReplayDevice(const wchar_t *logfile, IReplayDriver **driver) +{ + RDCDEBUG("Creating an OpenGL replay device"); + + if(glXCreateContextAttribsProc == NULL) + { + glXGetFuncProc = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress"); + glXDestroyCtxProc = (PFNGLXDESTROYCONTEXTPROC)dlsym(RTLD_NEXT, "glXDestroyContext"); + glXSwapProc = (PFNGLXSWAPBUFFERSPROC)dlsym(RTLD_NEXT, "glXSwapBuffers"); + glXChooseFBConfigProc = (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig"); + glXCreatePbufferProc = (PFNGLXCREATEPBUFFERPROC)dlsym(RTLD_NEXT, "glXCreatePbufferProc"); + glXDestroyPbufferProc = (PFNGLXDESTROYPBUFFERPROC)dlsym(RTLD_NEXT, "glXDestroyPbuffer"); + glXQueryDrawableProc = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable"); + + if(glXGetFuncProc == NULL || glXDestroyCtxProc == NULL || + glXSwapProc == NULL || glXChooseFBConfigProc == NULL || + glXCreatePbufferProc == NULL || glXDestroyPbufferProc == NULL || + glXQueryDrawableProc == NULL) + { + RDCERR("Couldn't find required entry points, glXGetProcAddress glXDestroyContext glXSwapBuffers"); + return eReplayCreate_APIInitFailed; + } + + glXCreateContextAttribsProc = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetFuncProc((const GLubyte*)"glXCreateContextAttribsARB"); + glXMakeContextCurrentProc = (PFNGLXMAKECONTEXTCURRENTPROC)glXGetFuncProc((const GLubyte*)"glXMakeContextCurrent"); + + if(glXCreateContextAttribsProc == NULL || glXMakeContextCurrentProc == NULL) + { + RDCERR("Couldn't get glx function addresses, glXCreateContextAttribsARB glXMakeContextCurrent"); + return eReplayCreate_APIInitFailed; + } + } + + GLInitParams initParams; + RDCDriver driverType = RDC_OpenGL; + wstring driverName = L"OpenGL"; + if(logfile) + RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, (RDCInitParams *)&initParams); + + if(initParams.SerialiseVersion != GLInitParams::GL_SERIALISE_VERSION) + { + RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GLInitParams::GL_SERIALISE_VERSION, initParams.SerialiseVersion); + return eReplayCreate_APIIncompatibleVersion; + } + + int attribs[64] = {0}; + int i=0; + + attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = 4; + attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = 3; + attribs[i++] = GLX_CONTEXT_FLAGS_ARB; + attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; + + Display *dpy = XOpenDisplay(NULL); + + if(dpy == NULL) + { + RDCERR("Couldn't open default X display"); + return eReplayCreate_APIInitFailed; + } + + // don't need to care about the fb config as we won't be using the default framebuffer (backbuffer) + static int visAttribs[] = { 0 }; + int numCfgs = 0; + GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + + if(fbcfg == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't choose default framebuffer config"); + return eReplayCreate_APIInitFailed; + } + + GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs); + + if(ctx == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability"); + return eReplayCreate_APIHardwareUnsupported; + } + + // don't care about pbuffer properties for same reason as backbuffer + int pbAttribs[] = { GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0 }; + + GLXPbuffer pbuffer = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs); + + XFree(fbcfg); + + Bool res = glXMakeContextCurrentProc(dpy, pbuffer, pbuffer, ctx); + + if(!res) + { + glXDestroyPbufferProc(dpy, pbuffer); + glXDestroyCtxProc(dpy, ctx); + XCloseDisplay(dpy); + RDCERR("Couldn't make pbuffer & context current"); + return eReplayCreate_APIInitFailed; + } + + WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealFunctions()); + gl->Initialise(initParams); + + RDCLOG("Created device."); + GLReplay *replay = gl->GetReplay(); + replay->SetProxy(logfile == NULL); + GLWindowingData data; + data.dpy = dpy; + data.ctx = ctx; + data.wnd = pbuffer; + replay->SetReplayData(data); + + *driver = (IReplayDriver *)replay; + return eReplayCreate_Success; +} diff --git a/renderdoc/driver/gl/gl_replay_win32.cpp b/renderdoc/driver/gl/gl_replay_win32.cpp new file mode 100644 index 0000000000..be4a08f449 --- /dev/null +++ b/renderdoc/driver/gl/gl_replay_win32.cpp @@ -0,0 +1,347 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "gl_replay.h" +#include "gl_driver.h" +#include "gl_resources.h" + +PIXELFORMATDESCRIPTOR pfd = { 0 }; +PFNWGLCREATECONTEXTATTRIBSARBPROC createContextAttribs = NULL; + +typedef PROC (WINAPI *WGLGETPROCADDRESSPROC)(const char*); +typedef HGLRC (WINAPI *WGLCREATECONTEXTPROC)(HDC); +typedef BOOL (WINAPI *WGLMAKECURRENTPROC)(HDC,HGLRC); +typedef BOOL (WINAPI *WGLDELETECONTEXTPROC)(HGLRC); + +WGLGETPROCADDRESSPROC wglGetProc = NULL; +WGLCREATECONTEXTPROC wglCreateRC = NULL; +WGLMAKECURRENTPROC wglMakeCurrentProc = NULL; +WGLDELETECONTEXTPROC wglDeleteRC = NULL; + +void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) +{ + static GLWindowingData *prev = NULL; + + if(wglMakeCurrentProc && ctx && ctx != prev) + { + prev = ctx; + wglMakeCurrentProc(ctx->DC, ctx->RC); + } +} + +void GLReplay::SwapBuffers(GLWindowingData *ctx) +{ + ::SwapBuffers(ctx->DC); +} + +void GLReplay::CloseReplayContext() +{ + if(wglDeleteRC) + { + wglDeleteRC(m_ReplayCtx.RC); + ReleaseDC(m_ReplayCtx.wnd, m_ReplayCtx.DC); + ::DestroyWindow(m_ReplayCtx.wnd); + } +} + +uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth) +{ + HWND w = (HWND)wn; + + if(w == NULL) + w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, GetModuleHandle(NULL), NULL); + + HDC DC = GetDC(w); + + int pf = ChoosePixelFormat(DC, &pfd); + if(pf == 0) + { + ReleaseDC(w, DC); + RDCERR("Couldn't choose pixel format"); + return NULL; + } + + BOOL res = SetPixelFormat(DC, pf, &pfd); + if(res == FALSE) + { + ReleaseDC(w, DC); + RDCERR("Couldn't set pixel format"); + return NULL; + } + + int attribs[64] = {0}; + int i=0; + + attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = 4; + attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = 3; + attribs[i++] = WGL_CONTEXT_FLAGS_ARB; + attribs[i++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB|WGL_CONTEXT_DEBUG_BIT_ARB; + + HGLRC rc = createContextAttribs(DC, m_ReplayCtx.RC, attribs); + if(rc == NULL) + { + ReleaseDC(w, DC); + RDCERR("Couldn't create 4.3 RC - RenderDoc requires OpenGL 4.3 availability"); + return 0; + } + + OutputWindow win; + win.DC = DC; + win.RC = rc; + win.wnd = w; + + RECT rect = {0}; + GetClientRect(w, &rect); + win.width = rect.right-rect.left; + win.height = rect.bottom-rect.top; + + InitOutputWindow(win); + CreateOutputWindowBackbuffer(win); + + uint64_t ret = m_OutputWindowID++; + + m_OutputWindows[ret] = win; + + return ret; +} + +void GLReplay::DestroyOutputWindow(uint64_t id) +{ + auto it = m_OutputWindows.find(id); + if(id == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + wglDeleteRC(outw.RC); + ReleaseDC(outw.wnd, outw.DC); + + m_OutputWindows.erase(it); +} + +void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + RECT rect = {0}; + GetClientRect(outw.wnd, &rect); + w = rect.right-rect.left; + h = rect.bottom-rect.top; +} + +bool GLReplay::IsOutputWindowVisible(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return false; + + return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE); +} + +const GLHookSet &GetRealFunctions(); + +ReplayCreateStatus GL_CreateReplayDevice(const wchar_t *logfile, IReplayDriver **driver) +{ + RDCDEBUG("Creating an OpenGL replay device"); + + HMODULE lib = NULL; + lib = LoadLibraryA("opengl32.dll"); + if(lib == NULL) + { + RDCERR("Failed to load opengl32.dll"); + return eReplayCreate_APIInitFailed; + } + + GLInitParams initParams; + RDCDriver driverType = RDC_OpenGL; + wstring driverName = L"OpenGL"; + if(logfile) + RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, (RDCInitParams *)&initParams); + + if(initParams.SerialiseVersion != GLInitParams::GL_SERIALISE_VERSION) + { + RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GLInitParams::GL_SERIALISE_VERSION, initParams.SerialiseVersion); + return eReplayCreate_APIIncompatibleVersion; + } + + if(wglGetProc == NULL) + { + wglGetProc = (WGLGETPROCADDRESSPROC)GetProcAddress(lib, "wglGetProcAddress"); + wglCreateRC = (WGLCREATECONTEXTPROC)GetProcAddress(lib, "wglCreateContext"); + wglMakeCurrentProc = (WGLMAKECURRENTPROC)GetProcAddress(lib, "wglMakeCurrent"); + wglDeleteRC = (WGLDELETECONTEXTPROC)GetProcAddress(lib, "wglDeleteContext"); + + if(wglGetProc == NULL || wglCreateRC == NULL || + wglMakeCurrentProc == NULL || wglDeleteRC == NULL) + { + RDCERR("Couldn't get wgl function addresses"); + return eReplayCreate_APIInitFailed; + } + + WNDCLASSEX wc; + RDCEraseEl(wc); + wc.style = CS_OWNDC; + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = DefWindowProc; + wc.hInstance = GetModuleHandle(NULL); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszClassName = L"renderdocGLclass"; + + if(!RegisterClassEx(&wc)) + { + RDCERR("Couldn't register GL window class"); + return eReplayCreate_APIInitFailed; + } + + RDCEraseEl(pfd); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 24; + pfd.cStencilBits = 0; + } + + HWND w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, GetModuleHandle(NULL), NULL); + + HDC dc = GetDC(w); + + int pf = ChoosePixelFormat(dc, &pfd); + if(pf == 0) + { + RDCERR("Couldn't choose pixel format"); + return eReplayCreate_APIInitFailed; + } + + BOOL res = SetPixelFormat(dc, pf, &pfd); + if(res == FALSE) + { + RDCERR("Couldn't set pixel format"); + return eReplayCreate_APIInitFailed; + } + + HGLRC rc = wglCreateRC(dc); + if(rc == NULL) + { + RDCERR("Couldn't create simple RC"); + return eReplayCreate_APIInitFailed; + } + + res = wglMakeCurrentProc(dc, rc); + if(res == FALSE) + { + RDCERR("Couldn't make simple RC current"); + return eReplayCreate_APIInitFailed; + } + + createContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProc( "wglCreateContextAttribsARB" ); + + if(createContextAttribs == NULL) + { + RDCERR("RenderDoc requires WGL_ARB_create_context"); + return eReplayCreate_APIHardwareUnsupported; + } + + wglMakeCurrentProc(NULL, NULL); + wglDeleteRC(rc); + ReleaseDC(w, dc); + DestroyWindow(w); + + // we don't use the default framebuffer (backbuffer) for anything, so we make it + // tiny and with no depth/stencil bits + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cDepthBits = 0; + pfd.cStencilBits = 0; + + w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"RenderDoc replay window", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 32, 32, + NULL, NULL, GetModuleHandle(NULL), NULL); + + dc = GetDC(w); + + pf = ChoosePixelFormat(dc, &pfd); + if(pf == 0) + { + RDCERR("Couldn't choose pixel format"); + return eReplayCreate_APIInitFailed; + } + + res = SetPixelFormat(dc, pf, &pfd); + if(res == FALSE) + { + RDCERR("Couldn't set pixel format"); + return eReplayCreate_APIInitFailed; + } + + int attribs[64] = {0}; + int i=0; + + attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = 4; + attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = 3; + attribs[i++] = WGL_CONTEXT_FLAGS_ARB; + attribs[i++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB|WGL_CONTEXT_DEBUG_BIT_ARB; + + rc = createContextAttribs(dc, NULL, attribs); + if(rc == NULL) + { + RDCERR("Couldn't create 4.3 RC - RenderDoc requires OpenGL 4.3 availability"); + return eReplayCreate_APIHardwareUnsupported; + } + + res = wglMakeCurrentProc(dc, rc); + if(res == FALSE) + { + RDCERR("Couldn't make 4.3 RC current"); + return eReplayCreate_APIInitFailed; + } + + WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealFunctions()); + gl->Initialise(initParams); + + RDCLOG("Created device."); + GLReplay *replay = gl->GetReplay(); + replay->SetProxy(logfile == NULL); + GLWindowingData data; + data.DC = dc; + data.RC = rc; + data.wnd = w; + replay->SetReplayData(data); + + *driver = (IReplayDriver *)replay; + return eReplayCreate_Success; +} diff --git a/renderdoc/driver/gl/gl_resources.cpp b/renderdoc/driver/gl/gl_resources.cpp new file mode 100644 index 0000000000..96731d50e1 --- /dev/null +++ b/renderdoc/driver/gl/gl_resources.cpp @@ -0,0 +1,97 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "gl_resources.h" + +size_t GetByteSize(GLsizei w, GLsizei h, GLsizei d, GLenum format, GLenum type, int level, int align) +{ + size_t elemSize = 0; + + switch(type) + { + case eGL_UNSIGNED_BYTE: + case eGL_BYTE: + elemSize = 1; + break; + case eGL_UNSIGNED_SHORT: + case eGL_SHORT: + elemSize = 2; + break; + case eGL_UNSIGNED_INT: + case eGL_INT: + case eGL_FLOAT: + elemSize = 4; + break; + case eGL_UNSIGNED_BYTE_3_3_2: + case eGL_UNSIGNED_BYTE_2_3_3_REV: + return w*h*d; + case eGL_UNSIGNED_SHORT_5_6_5: + case eGL_UNSIGNED_SHORT_5_6_5_REV: + case eGL_UNSIGNED_SHORT_4_4_4_4: + case eGL_UNSIGNED_SHORT_4_4_4_4_REV: + case eGL_UNSIGNED_SHORT_5_5_5_1: + case eGL_UNSIGNED_SHORT_1_5_5_5_REV: + return w*h*d*2; + case eGL_UNSIGNED_INT_8_8_8_8: + case eGL_UNSIGNED_INT_8_8_8_8_REV: + case eGL_UNSIGNED_INT_10_10_10_2: + case eGL_UNSIGNED_INT_2_10_10_10_REV: + return w*h*d*4; + default: + RDCERR("Unhandled Byte Size type %d!", type); + break; + } + + switch(format) + { + case eGL_RED: + case eGL_RED_INTEGER: + case eGL_GREEN: + case eGL_GREEN_INTEGER: + case eGL_BLUE: + case eGL_BLUE_INTEGER: + return w*h*d*elemSize; + case eGL_RG: + case eGL_RG_INTEGER: + return w*h*d*elemSize*2; + case eGL_RGB: + case eGL_RGB_INTEGER: + case eGL_BGR: + case eGL_BGR_INTEGER: + return w*h*d*elemSize*3; + case eGL_RGBA: + case eGL_RGBA_INTEGER: + case eGL_BGRA: + case eGL_BGRA_INTEGER: + return w*h*d*elemSize*4; + default: + RDCERR("Unhandled Byte Size format %d!", format); + break; + } + + RDCERR("Unhandled Byte Size case!"); + + return 0; +} diff --git a/renderdoc/driver/gl/gl_resources.h b/renderdoc/driver/gl/gl_resources.h new file mode 100644 index 0000000000..83be9b5b9c --- /dev/null +++ b/renderdoc/driver/gl/gl_resources.h @@ -0,0 +1,108 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "core/resource_manager.h" + +#include "driver/gl/gl_common.h" + +size_t GetByteSize(GLsizei w, GLsizei h, GLsizei d, GLenum format, GLenum type, int level, int align); + +enum GLNamespace +{ + eResUnknown = 0, + eResSpecial, + eResTexture, + eResSampler, + eResFramebuffer, + eResBuffer, + eResVertexArray, + eResShader, + eResProgram, + eResDisplayList, +}; + +enum GLSpecialResource +{ + eSpecialResDevice = 0, + eSpecialResContext = 0, +}; + +enum NullInitialiser { MakeNullResource }; + +struct GLResource +{ + GLResource() { Namespace = eResUnknown; name = ~0U; } + GLResource(NullInitialiser) { Namespace = eResUnknown; name = ~0U; } + GLResource(GLNamespace n, GLuint i) { Namespace = n; name = i; } + GLNamespace Namespace; + GLuint name; + + bool operator ==(const GLResource &o) const + { + return Namespace == o.Namespace && name == o.name; + } + + bool operator !=(const GLResource &o) const + { + return !(*this == o); + } + + bool operator <(const GLResource &o) const + { + if(Namespace != o.Namespace) return Namespace < o.Namespace; + return name < o.name; + } +}; + +inline GLResource TextureRes(GLuint i) { return GLResource(eResTexture, i); } +inline GLResource SamplerRes(GLuint i) { return GLResource(eResSampler, i); } +inline GLResource FramebufferRes(GLuint i) { return GLResource(eResFramebuffer, i); } +inline GLResource BufferRes(GLuint i) { return GLResource(eResBuffer, i); } +inline GLResource VertexArrayRes(GLuint i) { return GLResource(eResVertexArray, i); } +inline GLResource ShaderRes(GLuint i) { return GLResource(eResShader, i); } +inline GLResource ProgramRes(GLuint i) { return GLResource(eResProgram, i); } +inline GLResource DisplayListRes(GLuint i) { return GLResource(eResDisplayList, i); } + +struct GLResourceRecord : public ResourceRecord +{ + static const NullInitialiser NullResource = MakeNullResource; + + GLResourceRecord(ResourceId id) : + ResourceRecord(id, true), + datatype(eGL_UNKNOWN_ENUM) + { + } + + // pointer into binding chunk where datatype enum lives for this resource + GLenum datatype; +}; + +namespace TrackedResource +{ + ResourceId GetNewUniqueID(); + void SetReplayResourceIDs(); +}; diff --git a/renderdoc/driver/gl/hookset.pl b/renderdoc/driver/gl/hookset.pl new file mode 100644 index 0000000000..3eeee2d6ef --- /dev/null +++ b/renderdoc/driver/gl/hookset.pl @@ -0,0 +1,197 @@ +#!/bin/perl + +use POSIX; + +sub trim { + (my $s = $_[0]) =~ s/^\s+|\s+$//g; + return $s; +} + +my $printdefs = $ARGV[$1] eq "defs"; + +open(HOOKSET, ") +{ + my $line = $_; + + if($line =~ /\/\/ --/) + { + $mode = ""; + } + elsif($line =~ /\/\/ \+\+ ([a-z]*)/) + { + $mode = "dllexport" if $1 eq "dllexport"; + $mode = "wglext" if $1 eq "wgl"; + $mode = "glxext" if $1 eq "glx"; + $mode = "glext" if $1 eq "gl"; + } + elsif($line =~ /^\s*\/\/ .*/) + { + # skip comments + } + elsif($mode ne "") + { + if($line =~ /(PFN.*PROC) (.*);( \/\/ aliases )?([a-zA-Z0-9_ ,]*)?/) + { + my $typedef = $1; + my $name = $2; + my $aliases = $4; + + my $def = trim(`grep -h $typedef gl_legacy_procs.h official/*`); + + if($def =~ /^typedef (.*)\([A-Z *]* $typedef\) \((.*)\);/) + { + my $returnType = trim($1); + my $args = $2; + $args = "" if $args eq "void"; + my $origargs = $args; + $args =~ s/ *([a-zA-Z_][a-zA-Z_0-9]*)(,|\Z)/, $1$2/g; + + my $argcount = () = $args =~ /,/g; + + $argcount = floor(($argcount + 1)/2); + + my $funcdefmacro = "HookWrapper$argcount($returnType, $name"; + $funcdefmacro .= ", $args" if $args ne ""; + $funcdefmacro .= ");"; + + my %func = ('name', $name, 'typedef', $typedef, 'macro', $funcdefmacro, 'ret', $returnType, 'args', $origargs, 'aliases', $aliases); + + push @dllexport, { %func } if $mode eq "dllexport"; + push @wglext, { %func } if $mode eq "wglext"; + push @glxext, { %func } if $mode eq "glxext"; + push @glext, { %func } if $mode eq "glext"; + } + else + { + print "MALFORMED $mode DEFINITION OR NO DEFINITION FOUND FOR $typedef: $def\n"; + } + } + else + { + print "MALFORMED $mode LINE IN gl_hookset.h: $line"; + } + } +} + +close(HOOKSET); + +if($printdefs) +{ + foreach my $el (@dllexport) + { + print " IMPLEMENT_FUNCTION_SERIALISED($el->{ret}, $el->{name}($el->{args}));\n"; + } + print "\n"; + foreach my $el (@wglext) + { + print " IMPLEMENT_FUNCTION_SERIALISED($el->{ret}, $el->{name}($el->{args}));\n"; + } + print "\n"; + foreach my $el (@glext) + { + print " IMPLEMENT_FUNCTION_SERIALISED($el->{ret}, $el->{name}($el->{args}));\n"; + } + print "\n"; + exit; +} + +print "////////////////////////////////////////////////////\n"; +print "\n"; +print "// dllexport functions\n"; +print "#define DLLExportHooks() \\\n"; +foreach my $el (@dllexport) +{ + print " HookInit($el->{name}); \\\n" +} +print "\n"; +print "\n"; +print "\n"; +print "// wgl extensions\n"; +print "#define HookCheckWGLExtensions() \\\n"; +foreach my $el (@wglext) +{ + print " HookExtension($el->{typedef}, $el->{name}); \\\n"; + foreach(split(/, */, $el->{aliases})) + { + print " HookExtensionAlias($el->{typedef}, $el->{name}, $_); \\\n"; + } +} +print "\n"; +print "\n"; +print "\n"; +print "// glx extensions\n"; +print "#define HookCheckGLXExtensions() \\\n"; +foreach my $el (@wglext) +{ + print " HookExtension($el->{typedef}, $el->{name}); \\\n"; + foreach(split(/, */, $el->{aliases})) + { + print " HookExtensionAlias($el->{typedef}, $el->{name}, $_); \\\n"; + } +} +print "\n"; +print "\n"; +print "\n"; +print "// gl extensions\n"; +print "#define HookCheckGLExtensions() \\\n"; +foreach my $el (@glext) +{ + print " HookExtension($el->{typedef}, $el->{name}); \\\n"; + foreach(split(/, */, $el->{aliases})) + { + print " HookExtensionAlias($el->{typedef}, $el->{name}, $_); \\\n"; + } +} +foreach my $el (@dllexport) +{ + print " HookExtension($el->{typedef}, $el->{name}); \\\n" +} +print "\n"; +print "\n"; +print "\n"; +print "// dllexport functions\n"; +print "#define DefineDLLExportHooks() \\\n"; +foreach my $el (@dllexport) +{ + print " $el->{macro} \\\n" +} +print "\n"; +print "\n"; +print "\n"; +print "// wgl extensions\n"; +print "#define DefineWGLExtensionHooks() \\\n"; +foreach my $el (@wglext) +{ + print " $el->{macro} \\\n" +} +print "\n"; +print "\n"; +print "\n"; +print "// glx extensions\n"; +print "#define DefineGLXExtensionHooks() \\\n"; +foreach my $el (@wglext) +{ + print " $el->{macro} \\\n" +} +print "\n"; +print "\n"; +print "\n"; +print "// gl extensions\n"; +print "#define DefineGLExtensionHooks() \\\n"; +foreach my $el (@glext) +{ + print " $el->{macro} \\\n" +} +print "\n"; +print "\n"; +print "\n"; +print "\n"; diff --git a/renderdoc/driver/gl/official/glcorearb.h b/renderdoc/driver/gl/official/glcorearb.h new file mode 100644 index 0000000000..8dcac3530c --- /dev/null +++ b/renderdoc/driver/gl/official/glcorearb.h @@ -0,0 +1,3270 @@ +#ifndef __glcorearb_h_ +#define __glcorearb_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2014 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision: 26007 $ on $Date: 2014-03-19 01:28:09 -0700 (Wed, 19 Mar 2014) $ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +/* glcorearb.h is for use with OpenGL core profile implementations. +** It should should be placed in the same directory as gl.h and +** included as . +** +** glcorearb.h includes only APIs in the latest OpenGL core profile +** implementation together with APIs in newer ARB extensions which +** can be supported by the core profile. It does not, and never will +** include functionality removed from the core profile, such as +** fixed-function vertex and fragment processing. +** +** Do not #include both and either of or +** in the same source file. +*/ + +/* Generated C header for: + * API: gl + * Profile: core + * Versions considered: .* + * Versions emitted: .* + * Default extensions included: glcore + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +typedef void GLvoid; + +// allow for overrides +#ifndef GLenum +typedef unsigned int GLenum; +#endif + +typedef float GLfloat; +typedef int GLint; +typedef int GLsizei; +typedef unsigned int GLbitfield; +typedef double GLdouble; +typedef unsigned int GLuint; +typedef unsigned char GLboolean; +typedef unsigned char GLubyte; +typedef void (APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); +typedef void (APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); +typedef void (APIENTRYP PFNGLPOINTSIZEPROC) (GLfloat size); +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); +typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC) (GLdouble depth); +typedef void (APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); +typedef void (APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); +typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap); +typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap); +typedef void (APIENTRYP PFNGLFINISHPROC) (void); +typedef void (APIENTRYP PFNGLFLUSHPROC) (void); +typedef void (APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); +typedef void (APIENTRYP PFNGLLOGICOPPROC) (GLenum opcode); +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLREADBUFFERPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC) (GLenum pname, GLdouble *data); +typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void); +typedef void (APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); +typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); +typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC) (GLdouble near, GLdouble far); +typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCullFace (GLenum mode); +GLAPI void APIENTRY glFrontFace (GLenum mode); +GLAPI void APIENTRY glHint (GLenum target, GLenum mode); +GLAPI void APIENTRY glLineWidth (GLfloat width); +GLAPI void APIENTRY glPointSize (GLfloat size); +GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode); +GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glDrawBuffer (GLenum mode); +GLAPI void APIENTRY glClear (GLbitfield mask); +GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glClearStencil (GLint s); +GLAPI void APIENTRY glClearDepth (GLdouble depth); +GLAPI void APIENTRY glStencilMask (GLuint mask); +GLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI void APIENTRY glDepthMask (GLboolean flag); +GLAPI void APIENTRY glDisable (GLenum cap); +GLAPI void APIENTRY glEnable (GLenum cap); +GLAPI void APIENTRY glFinish (void); +GLAPI void APIENTRY glFlush (void); +GLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); +GLAPI void APIENTRY glLogicOp (GLenum opcode); +GLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +GLAPI void APIENTRY glDepthFunc (GLenum func); +GLAPI void APIENTRY glPixelStoref (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param); +GLAPI void APIENTRY glReadBuffer (GLenum mode); +GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI void APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); +GLAPI void APIENTRY glGetDoublev (GLenum pname, GLdouble *data); +GLAPI GLenum APIENTRY glGetError (void); +GLAPI void APIENTRY glGetFloatv (GLenum pname, GLfloat *data); +GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data); +GLAPI const GLubyte *APIENTRY glGetString (GLenum name); +GLAPI void APIENTRY glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI void APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap); +GLAPI void APIENTRY glDepthRange (GLdouble near, GLdouble far); +GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_VERSION_1_0 */ + +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +typedef float GLclampf; +typedef double GLclampd; +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_REPEAT 0x2901 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_VERTEX_ARRAY 0x8074 +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); +typedef void (APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params); +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI void APIENTRY glGetPointerv (GLenum pname, void **params); +GLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GLAPI void APIENTRY glCopyTexImage1D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture); +GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); +GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); +GLAPI GLboolean APIENTRY glIsTexture (GLuint texture); +#endif +#endif /* GL_VERSION_1_1 */ + +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_VERSION_1_2 */ + +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTexture (GLenum texture); +GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); +#endif +#endif /* GL_VERSION_1_3 */ + +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); +GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation (GLenum mode); +#endif +#endif /* GL_VERSION_1_4 */ + +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +#include +typedef ptrdiff_t GLsizeiptr; +typedef ptrdiff_t GLintptr; +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQuery (GLuint id); +GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQuery (GLenum target); +GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); +GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); +GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_VERSION_1_5 */ + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +typedef char GLchar; +typedef short GLshort; +typedef signed char GLbyte; +typedef unsigned short GLushort; +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); +GLAPI void APIENTRY glCompileShader (GLuint shader); +GLAPI GLuint APIENTRY glCreateProgram (void); +GLAPI GLuint APIENTRY glCreateShader (GLenum type); +GLAPI void APIENTRY glDeleteProgram (GLuint program); +GLAPI void APIENTRY glDeleteShader (GLuint shader); +GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); +GLAPI GLboolean APIENTRY glIsProgram (GLuint program); +GLAPI GLboolean APIENTRY glIsShader (GLuint shader); +GLAPI void APIENTRY glLinkProgram (GLuint program); +GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI void APIENTRY glUseProgram (GLuint program); +GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glValidateProgram (GLuint program); +GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#endif +#endif /* GL_VERSION_2_0 */ + +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif +#endif /* GL_VERSION_2_1 */ + +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +typedef unsigned short GLhalf; +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); +GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); +GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedback (void); +GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); +GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRender (void); +GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); +GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); +GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmap (GLenum target); +GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glBindVertexArray (GLuint array); +GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); +#endif +#endif /* GL_VERSION_3_0 */ + +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); +GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); +GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif +#endif /* GL_VERSION_3_1 */ + +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +typedef struct __GLsync *GLsync; +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef uint64_t GLuint64; +typedef int64_t GLint64; +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); +typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); +typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI void APIENTRY glProvokingVertex (GLenum mode); +GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); +GLAPI GLboolean APIENTRY glIsSync (GLsync sync); +GLAPI void APIENTRY glDeleteSync (GLsync sync); +GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); +GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); +GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); +#endif +#endif /* GL_VERSION_3_2 */ + +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); +GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); +GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); +GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); +GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); +GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); +GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); +GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); +GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); +GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); +GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); +GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +#endif +#endif /* GL_VERSION_3_3 */ + +#ifndef GL_VERSION_4_0 +#define GL_VERSION_4_0 1 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); +typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); +typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); +typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); +typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); +typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShading (GLfloat value); +GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); +GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); +GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); +GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); +GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); +GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); +GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); +GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); +GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedback (void); +GLAPI void APIENTRY glResumeTransformFeedback (void); +GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); +GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); +GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); +GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); +GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_VERSION_4_0 */ + +#ifndef GL_VERSION_4_1 +#define GL_VERSION_4_1 1 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); +typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); +typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); +typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); +typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReleaseShaderCompiler (void); +GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); +GLAPI void APIENTRY glClearDepthf (GLfloat d); +GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); +GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); +GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); +GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); +GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); +GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); +#endif +#endif /* GL_VERSION_4_1 */ + +#ifndef GL_VERSION_4_2 +#define GL_VERSION_4_2 1 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); +typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); +GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); +GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#endif +#endif /* GL_VERSION_4_2 */ + +#ifndef GL_VERSION_4_3 +#define GL_VERSION_4_3 1 +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_VERTEX_BINDING_BUFFER 0x8F4F +typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); +typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); +GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); +GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); +GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI void APIENTRY glPopDebugGroup (void); +GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_VERSION_4_3 */ + +#ifndef GL_VERSION_4_4 +#define GL_VERSION_4_4 1 +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define GL_TEXTURE_BUFFER_BINDING 0x8C2A +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_CLEAR_TEXTURE 0x9365 +#define GL_LOCATION_COMPONENT 0x934A +#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B +#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); +GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#endif +#endif /* GL_VERSION_4_4 */ + +#ifndef GL_ARB_ES2_compatibility +#define GL_ARB_ES2_compatibility 1 +#endif /* GL_ARB_ES2_compatibility */ + +#ifndef GL_ARB_ES3_compatibility +#define GL_ARB_ES3_compatibility 1 +#endif /* GL_ARB_ES3_compatibility */ + +#ifndef GL_ARB_arrays_of_arrays +#define GL_ARB_arrays_of_arrays 1 +#endif /* GL_ARB_arrays_of_arrays */ + +#ifndef GL_ARB_base_instance +#define GL_ARB_base_instance 1 +#endif /* GL_ARB_base_instance */ + +#ifndef GL_ARB_bindless_texture +#define GL_ARB_bindless_texture 1 +typedef uint64_t GLuint64EXT; +#define GL_UNSIGNED_INT64_ARB 0x140F +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_ARB_bindless_texture */ + +#ifndef GL_ARB_blend_func_extended +#define GL_ARB_blend_func_extended 1 +#endif /* GL_ARB_blend_func_extended */ + +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 +#endif /* GL_ARB_buffer_storage */ + +#ifndef GL_ARB_cl_event +#define GL_ARB_cl_event 1 +struct _cl_context; +struct _cl_event; +#define GL_SYNC_CL_EVENT_ARB 0x8240 +#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#endif +#endif /* GL_ARB_cl_event */ + +#ifndef GL_ARB_clear_buffer_object +#define GL_ARB_clear_buffer_object 1 +#endif /* GL_ARB_clear_buffer_object */ + +#ifndef GL_ARB_clear_texture +#define GL_ARB_clear_texture 1 +#endif /* GL_ARB_clear_texture */ + +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_ARB_compressed_texture_pixel_storage 1 +#endif /* GL_ARB_compressed_texture_pixel_storage */ + +#ifndef GL_ARB_compute_shader +#define GL_ARB_compute_shader 1 +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#endif /* GL_ARB_compute_shader */ + +#ifndef GL_ARB_compute_variable_group_size +#define GL_ARB_compute_variable_group_size 1 +#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 +#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB +#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 +#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#endif +#endif /* GL_ARB_compute_variable_group_size */ + +#ifndef GL_ARB_conservative_depth +#define GL_ARB_conservative_depth 1 +#endif /* GL_ARB_conservative_depth */ + +#ifndef GL_ARB_copy_buffer +#define GL_ARB_copy_buffer 1 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#endif /* GL_ARB_copy_buffer */ + +#ifndef GL_ARB_copy_image +#define GL_ARB_copy_image 1 +#endif /* GL_ARB_copy_image */ + +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#endif +#endif /* GL_ARB_debug_output */ + +#ifndef GL_ARB_depth_buffer_float +#define GL_ARB_depth_buffer_float 1 +#endif /* GL_ARB_depth_buffer_float */ + +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +#endif /* GL_ARB_depth_clamp */ + +#ifndef GL_ARB_draw_buffers_blend +#define GL_ARB_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif +#endif /* GL_ARB_draw_buffers_blend */ + +#ifndef GL_ARB_draw_elements_base_vertex +#define GL_ARB_draw_elements_base_vertex 1 +#endif /* GL_ARB_draw_elements_base_vertex */ + +#ifndef GL_ARB_draw_indirect +#define GL_ARB_draw_indirect 1 +#endif /* GL_ARB_draw_indirect */ + +#ifndef GL_ARB_enhanced_layouts +#define GL_ARB_enhanced_layouts 1 +#endif /* GL_ARB_enhanced_layouts */ + +#ifndef GL_ARB_explicit_attrib_location +#define GL_ARB_explicit_attrib_location 1 +#endif /* GL_ARB_explicit_attrib_location */ + +#ifndef GL_ARB_explicit_uniform_location +#define GL_ARB_explicit_uniform_location 1 +#endif /* GL_ARB_explicit_uniform_location */ + +#ifndef GL_ARB_fragment_coord_conventions +#define GL_ARB_fragment_coord_conventions 1 +#endif /* GL_ARB_fragment_coord_conventions */ + +#ifndef GL_ARB_fragment_layer_viewport +#define GL_ARB_fragment_layer_viewport 1 +#endif /* GL_ARB_fragment_layer_viewport */ + +#ifndef GL_ARB_framebuffer_no_attachments +#define GL_ARB_framebuffer_no_attachments 1 +#endif /* GL_ARB_framebuffer_no_attachments */ + +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +#endif /* GL_ARB_framebuffer_object */ + +#ifndef GL_ARB_framebuffer_sRGB +#define GL_ARB_framebuffer_sRGB 1 +#endif /* GL_ARB_framebuffer_sRGB */ + +#ifndef GL_ARB_get_program_binary +#define GL_ARB_get_program_binary 1 +#endif /* GL_ARB_get_program_binary */ + +#ifndef GL_ARB_gpu_shader5 +#define GL_ARB_gpu_shader5 1 +#endif /* GL_ARB_gpu_shader5 */ + +#ifndef GL_ARB_gpu_shader_fp64 +#define GL_ARB_gpu_shader_fp64 1 +#endif /* GL_ARB_gpu_shader_fp64 */ + +#ifndef GL_ARB_half_float_vertex +#define GL_ARB_half_float_vertex 1 +#endif /* GL_ARB_half_float_vertex */ + +#ifndef GL_ARB_imaging +#define GL_ARB_imaging 1 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#endif /* GL_ARB_imaging */ + +#ifndef GL_ARB_indirect_parameters +#define GL_ARB_indirect_parameters 1 +#define GL_PARAMETER_BUFFER_ARB 0x80EE +#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#endif +#endif /* GL_ARB_indirect_parameters */ + +#ifndef GL_ARB_internalformat_query +#define GL_ARB_internalformat_query 1 +#endif /* GL_ARB_internalformat_query */ + +#ifndef GL_ARB_internalformat_query2 +#define GL_ARB_internalformat_query2 1 +#define GL_SRGB_DECODE_ARB 0x8299 +#endif /* GL_ARB_internalformat_query2 */ + +#ifndef GL_ARB_invalidate_subdata +#define GL_ARB_invalidate_subdata 1 +#endif /* GL_ARB_invalidate_subdata */ + +#ifndef GL_ARB_map_buffer_alignment +#define GL_ARB_map_buffer_alignment 1 +#endif /* GL_ARB_map_buffer_alignment */ + +#ifndef GL_ARB_map_buffer_range +#define GL_ARB_map_buffer_range 1 +#endif /* GL_ARB_map_buffer_range */ + +#ifndef GL_ARB_multi_bind +#define GL_ARB_multi_bind 1 +#endif /* GL_ARB_multi_bind */ + +#ifndef GL_ARB_multi_draw_indirect +#define GL_ARB_multi_draw_indirect 1 +#endif /* GL_ARB_multi_draw_indirect */ + +#ifndef GL_ARB_occlusion_query2 +#define GL_ARB_occlusion_query2 1 +#endif /* GL_ARB_occlusion_query2 */ + +#ifndef GL_ARB_program_interface_query +#define GL_ARB_program_interface_query 1 +#endif /* GL_ARB_program_interface_query */ + +#ifndef GL_ARB_provoking_vertex +#define GL_ARB_provoking_vertex 1 +#endif /* GL_ARB_provoking_vertex */ + +#ifndef GL_ARB_query_buffer_object +#define GL_ARB_query_buffer_object 1 +#endif /* GL_ARB_query_buffer_object */ + +#ifndef GL_ARB_robust_buffer_access_behavior +#define GL_ARB_robust_buffer_access_behavior 1 +#endif /* GL_ARB_robust_buffer_access_behavior */ + +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); +GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); +GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +#endif +#endif /* GL_ARB_robustness */ + +#ifndef GL_ARB_robustness_isolation +#define GL_ARB_robustness_isolation 1 +#endif /* GL_ARB_robustness_isolation */ + +#ifndef GL_ARB_sample_shading +#define GL_ARB_sample_shading 1 +#define GL_SAMPLE_SHADING_ARB 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); +#endif +#endif /* GL_ARB_sample_shading */ + +#ifndef GL_ARB_sampler_objects +#define GL_ARB_sampler_objects 1 +#endif /* GL_ARB_sampler_objects */ + +#ifndef GL_ARB_seamless_cube_map +#define GL_ARB_seamless_cube_map 1 +#endif /* GL_ARB_seamless_cube_map */ + +#ifndef GL_ARB_seamless_cubemap_per_texture +#define GL_ARB_seamless_cubemap_per_texture 1 +#endif /* GL_ARB_seamless_cubemap_per_texture */ + +#ifndef GL_ARB_separate_shader_objects +#define GL_ARB_separate_shader_objects 1 +#endif /* GL_ARB_separate_shader_objects */ + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ARB_shader_atomic_counters 1 +#endif /* GL_ARB_shader_atomic_counters */ + +#ifndef GL_ARB_shader_bit_encoding +#define GL_ARB_shader_bit_encoding 1 +#endif /* GL_ARB_shader_bit_encoding */ + +#ifndef GL_ARB_shader_draw_parameters +#define GL_ARB_shader_draw_parameters 1 +#endif /* GL_ARB_shader_draw_parameters */ + +#ifndef GL_ARB_shader_group_vote +#define GL_ARB_shader_group_vote 1 +#endif /* GL_ARB_shader_group_vote */ + +#ifndef GL_ARB_shader_image_load_store +#define GL_ARB_shader_image_load_store 1 +#endif /* GL_ARB_shader_image_load_store */ + +#ifndef GL_ARB_shader_image_size +#define GL_ARB_shader_image_size 1 +#endif /* GL_ARB_shader_image_size */ + +#ifndef GL_ARB_shader_precision +#define GL_ARB_shader_precision 1 +#endif /* GL_ARB_shader_precision */ + +#ifndef GL_ARB_shader_stencil_export +#define GL_ARB_shader_stencil_export 1 +#endif /* GL_ARB_shader_stencil_export */ + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_ARB_shader_storage_buffer_object 1 +#endif /* GL_ARB_shader_storage_buffer_object */ + +#ifndef GL_ARB_shader_subroutine +#define GL_ARB_shader_subroutine 1 +#endif /* GL_ARB_shader_subroutine */ + +#ifndef GL_ARB_shading_language_420pack +#define GL_ARB_shading_language_420pack 1 +#endif /* GL_ARB_shading_language_420pack */ + +#ifndef GL_ARB_shading_language_include +#define GL_ARB_shading_language_include 1 +#define GL_SHADER_INCLUDE_ARB 0x8DAE +#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define GL_NAMED_STRING_TYPE_ARB 0x8DEA +typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#endif +#endif /* GL_ARB_shading_language_include */ + +#ifndef GL_ARB_shading_language_packing +#define GL_ARB_shading_language_packing 1 +#endif /* GL_ARB_shading_language_packing */ + +#ifndef GL_ARB_sparse_texture +#define GL_ARB_sparse_texture 1 +#define GL_TEXTURE_SPARSE_ARB 0x91A6 +#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define GL_MIN_SPARSE_LEVEL_ARB 0x919B +#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A +#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 +typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#endif +#endif /* GL_ARB_sparse_texture */ + +#ifndef GL_ARB_stencil_texturing +#define GL_ARB_stencil_texturing 1 +#endif /* GL_ARB_stencil_texturing */ + +#ifndef GL_ARB_sync +#define GL_ARB_sync 1 +#endif /* GL_ARB_sync */ + +#ifndef GL_ARB_tessellation_shader +#define GL_ARB_tessellation_shader 1 +#endif /* GL_ARB_tessellation_shader */ + +#ifndef GL_ARB_texture_buffer_object_rgb32 +#define GL_ARB_texture_buffer_object_rgb32 1 +#endif /* GL_ARB_texture_buffer_object_rgb32 */ + +#ifndef GL_ARB_texture_buffer_range +#define GL_ARB_texture_buffer_range 1 +#endif /* GL_ARB_texture_buffer_range */ + +#ifndef GL_ARB_texture_compression_bptc +#define GL_ARB_texture_compression_bptc 1 +#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F +#endif /* GL_ARB_texture_compression_bptc */ + +#ifndef GL_ARB_texture_compression_rgtc +#define GL_ARB_texture_compression_rgtc 1 +#endif /* GL_ARB_texture_compression_rgtc */ + +#ifndef GL_ARB_texture_cube_map_array +#define GL_ARB_texture_cube_map_array 1 +#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F +#endif /* GL_ARB_texture_cube_map_array */ + +#ifndef GL_ARB_texture_gather +#define GL_ARB_texture_gather 1 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F +#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F +#endif /* GL_ARB_texture_gather */ + +#ifndef GL_ARB_texture_mirror_clamp_to_edge +#define GL_ARB_texture_mirror_clamp_to_edge 1 +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ + +#ifndef GL_ARB_texture_multisample +#define GL_ARB_texture_multisample 1 +#endif /* GL_ARB_texture_multisample */ + +#ifndef GL_ARB_texture_query_levels +#define GL_ARB_texture_query_levels 1 +#endif /* GL_ARB_texture_query_levels */ + +#ifndef GL_ARB_texture_query_lod +#define GL_ARB_texture_query_lod 1 +#endif /* GL_ARB_texture_query_lod */ + +#ifndef GL_ARB_texture_rg +#define GL_ARB_texture_rg 1 +#endif /* GL_ARB_texture_rg */ + +#ifndef GL_ARB_texture_rgb10_a2ui +#define GL_ARB_texture_rgb10_a2ui 1 +#endif /* GL_ARB_texture_rgb10_a2ui */ + +#ifndef GL_ARB_texture_stencil8 +#define GL_ARB_texture_stencil8 1 +#endif /* GL_ARB_texture_stencil8 */ + +#ifndef GL_ARB_texture_storage +#define GL_ARB_texture_storage 1 +#endif /* GL_ARB_texture_storage */ + +#ifndef GL_ARB_texture_storage_multisample +#define GL_ARB_texture_storage_multisample 1 +#endif /* GL_ARB_texture_storage_multisample */ + +#ifndef GL_ARB_texture_swizzle +#define GL_ARB_texture_swizzle 1 +#endif /* GL_ARB_texture_swizzle */ + +#ifndef GL_ARB_texture_view +#define GL_ARB_texture_view 1 +#endif /* GL_ARB_texture_view */ + +#ifndef GL_ARB_timer_query +#define GL_ARB_timer_query 1 +#endif /* GL_ARB_timer_query */ + +#ifndef GL_ARB_transform_feedback2 +#define GL_ARB_transform_feedback2 1 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#endif /* GL_ARB_transform_feedback2 */ + +#ifndef GL_ARB_transform_feedback3 +#define GL_ARB_transform_feedback3 1 +#endif /* GL_ARB_transform_feedback3 */ + +#ifndef GL_ARB_transform_feedback_instanced +#define GL_ARB_transform_feedback_instanced 1 +#endif /* GL_ARB_transform_feedback_instanced */ + +#ifndef GL_ARB_uniform_buffer_object +#define GL_ARB_uniform_buffer_object 1 +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#endif /* GL_ARB_uniform_buffer_object */ + +#ifndef GL_ARB_vertex_array_bgra +#define GL_ARB_vertex_array_bgra 1 +#endif /* GL_ARB_vertex_array_bgra */ + +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +#endif /* GL_ARB_vertex_array_object */ + +#ifndef GL_ARB_vertex_attrib_64bit +#define GL_ARB_vertex_attrib_64bit 1 +#endif /* GL_ARB_vertex_attrib_64bit */ + +#ifndef GL_ARB_vertex_attrib_binding +#define GL_ARB_vertex_attrib_binding 1 +#endif /* GL_ARB_vertex_attrib_binding */ + +#ifndef GL_ARB_vertex_type_10f_11f_11f_rev +#define GL_ARB_vertex_type_10f_11f_11f_rev 1 +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ + +#ifndef GL_ARB_vertex_type_2_10_10_10_rev +#define GL_ARB_vertex_type_2_10_10_10_rev 1 +#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ + +#ifndef GL_ARB_viewport_array +#define GL_ARB_viewport_array 1 +#endif /* GL_ARB_viewport_array */ + +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +#endif /* GL_KHR_debug */ + +#ifndef GL_KHR_texture_compression_astc_hdr +#define GL_KHR_texture_compression_astc_hdr 1 +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif /* GL_KHR_texture_compression_astc_hdr */ + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_KHR_texture_compression_astc_ldr 1 +#endif /* GL_KHR_texture_compression_astc_ldr */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/renderdoc/driver/gl/official/glext.h b/renderdoc/driver/gl/official/glext.h new file mode 100644 index 0000000000..997dfe041d --- /dev/null +++ b/renderdoc/driver/gl/official/glext.h @@ -0,0 +1,11162 @@ +#ifndef __glext_h_ +#define __glext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2014 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision: 26320 $ on $Date: 2014-04-17 03:07:07 -0700 (Thu, 17 Apr 2014) $ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +#define GL_GLEXT_VERSION 20140417 + +/* Generated C header for: + * API: gl + * Profile: compatibility + * Versions considered: .* + * Versions emitted: 1\.[2-9]|[234]\.[0-9] + * Default extensions included: gl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_VERSION_1_2 */ + +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTexture (GLenum texture); +GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); +GLAPI void APIENTRY glClientActiveTexture (GLenum texture); +GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); +GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); +GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); +GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); +GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); +GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); +GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); +GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); +GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); +GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); +GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); +GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); +GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); +#endif +#endif /* GL_VERSION_1_3 */ + +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); +GLAPI void APIENTRY glFogCoordf (GLfloat coord); +GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); +GLAPI void APIENTRY glFogCoordd (GLdouble coord); +GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); +GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); +GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); +GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); +GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); +GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); +GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); +GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); +GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); +GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); +GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); +GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); +GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); +GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); +GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); +GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); +GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); +GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2iv (const GLint *v); +GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); +GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3iv (const GLint *v); +GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); +GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation (GLenum mode); +#endif +#endif /* GL_VERSION_1_4 */ + +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +#include +typedef ptrdiff_t GLsizeiptr; +typedef ptrdiff_t GLintptr; +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A +typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQuery (GLuint id); +GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQuery (GLenum target); +GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); +GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); +GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_VERSION_1_5 */ + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +typedef char GLchar; +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); +GLAPI void APIENTRY glCompileShader (GLuint shader); +GLAPI GLuint APIENTRY glCreateProgram (void); +GLAPI GLuint APIENTRY glCreateShader (GLenum type); +GLAPI void APIENTRY glDeleteProgram (GLuint program); +GLAPI void APIENTRY glDeleteShader (GLuint shader); +GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); +GLAPI GLboolean APIENTRY glIsProgram (GLuint program); +GLAPI GLboolean APIENTRY glIsShader (GLuint shader); +GLAPI void APIENTRY glLinkProgram (GLuint program); +GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI void APIENTRY glUseProgram (GLuint program); +GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glValidateProgram (GLuint program); +GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#endif +#endif /* GL_VERSION_2_0 */ + +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif +#endif /* GL_VERSION_2_1 */ + +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +typedef unsigned short GLhalf; +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 +typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); +GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); +GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedback (void); +GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); +GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRender (void); +GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); +GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); +GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmap (GLenum target); +GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glBindVertexArray (GLuint array); +GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); +#endif +#endif /* GL_VERSION_3_0 */ + +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); +GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); +GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif +#endif /* GL_VERSION_3_1 */ + +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +typedef struct __GLsync *GLsync; +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef uint64_t GLuint64; +typedef int64_t GLint64; +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); +typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); +typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI void APIENTRY glProvokingVertex (GLenum mode); +GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); +GLAPI GLboolean APIENTRY glIsSync (GLsync sync); +GLAPI void APIENTRY glDeleteSync (GLsync sync); +GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); +GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); +GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); +#endif +#endif /* GL_VERSION_3_2 */ + +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); +GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); +GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); +GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); +GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); +GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); +GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); +GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); +GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); +GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); +GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); +GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); +#endif +#endif /* GL_VERSION_3_3 */ + +#ifndef GL_VERSION_4_0 +#define GL_VERSION_4_0 1 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); +typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); +typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); +typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); +typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); +typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShading (GLfloat value); +GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); +GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); +GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); +GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); +GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); +GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); +GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); +GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); +GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedback (void); +GLAPI void APIENTRY glResumeTransformFeedback (void); +GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); +GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); +GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); +GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); +GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_VERSION_4_0 */ + +#ifndef GL_VERSION_4_1 +#define GL_VERSION_4_1 1 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); +typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); +typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); +typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); +typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReleaseShaderCompiler (void); +GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); +GLAPI void APIENTRY glClearDepthf (GLfloat d); +GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); +GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); +GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); +GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); +GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); +GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); +#endif +#endif /* GL_VERSION_4_1 */ + +#ifndef GL_VERSION_4_2 +#define GL_VERSION_4_2 1 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); +typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); +GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); +GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#endif +#endif /* GL_VERSION_4_2 */ + +#ifndef GL_VERSION_4_3 +#define GL_VERSION_4_3 1 +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_VERTEX_BINDING_BUFFER 0x8F4F +#define GL_DISPLAY_LIST 0x82E7 +typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); +typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); +GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); +GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); +GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI void APIENTRY glPopDebugGroup (void); +GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_VERSION_4_3 */ + +#ifndef GL_VERSION_4_4 +#define GL_VERSION_4_4 1 +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define GL_TEXTURE_BUFFER_BINDING 0x8C2A +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_CLEAR_TEXTURE 0x9365 +#define GL_LOCATION_COMPONENT 0x934A +#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B +#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); +GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#endif +#endif /* GL_VERSION_4_4 */ + +#ifndef GL_ARB_ES2_compatibility +#define GL_ARB_ES2_compatibility 1 +#endif /* GL_ARB_ES2_compatibility */ + +#ifndef GL_ARB_ES3_compatibility +#define GL_ARB_ES3_compatibility 1 +#endif /* GL_ARB_ES3_compatibility */ + +#ifndef GL_ARB_arrays_of_arrays +#define GL_ARB_arrays_of_arrays 1 +#endif /* GL_ARB_arrays_of_arrays */ + +#ifndef GL_ARB_base_instance +#define GL_ARB_base_instance 1 +#endif /* GL_ARB_base_instance */ + +#ifndef GL_ARB_bindless_texture +#define GL_ARB_bindless_texture 1 +typedef uint64_t GLuint64EXT; +#define GL_UNSIGNED_INT64_ARB 0x140F +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_ARB_bindless_texture */ + +#ifndef GL_ARB_blend_func_extended +#define GL_ARB_blend_func_extended 1 +#endif /* GL_ARB_blend_func_extended */ + +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 +#endif /* GL_ARB_buffer_storage */ + +#ifndef GL_ARB_cl_event +#define GL_ARB_cl_event 1 +struct _cl_context; +struct _cl_event; +#define GL_SYNC_CL_EVENT_ARB 0x8240 +#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#endif +#endif /* GL_ARB_cl_event */ + +#ifndef GL_ARB_clear_buffer_object +#define GL_ARB_clear_buffer_object 1 +#endif /* GL_ARB_clear_buffer_object */ + +#ifndef GL_ARB_clear_texture +#define GL_ARB_clear_texture 1 +#endif /* GL_ARB_clear_texture */ + +#ifndef GL_ARB_color_buffer_float +#define GL_ARB_color_buffer_float 1 +#define GL_RGBA_FLOAT_MODE_ARB 0x8820 +#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A +#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B +#define GL_CLAMP_READ_COLOR_ARB 0x891C +#define GL_FIXED_ONLY_ARB 0x891D +typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); +#endif +#endif /* GL_ARB_color_buffer_float */ + +#ifndef GL_ARB_compatibility +#define GL_ARB_compatibility 1 +#endif /* GL_ARB_compatibility */ + +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_ARB_compressed_texture_pixel_storage 1 +#endif /* GL_ARB_compressed_texture_pixel_storage */ + +#ifndef GL_ARB_compute_shader +#define GL_ARB_compute_shader 1 +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#endif /* GL_ARB_compute_shader */ + +#ifndef GL_ARB_compute_variable_group_size +#define GL_ARB_compute_variable_group_size 1 +#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 +#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB +#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 +#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#endif +#endif /* GL_ARB_compute_variable_group_size */ + +#ifndef GL_ARB_conservative_depth +#define GL_ARB_conservative_depth 1 +#endif /* GL_ARB_conservative_depth */ + +#ifndef GL_ARB_copy_buffer +#define GL_ARB_copy_buffer 1 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#endif /* GL_ARB_copy_buffer */ + +#ifndef GL_ARB_copy_image +#define GL_ARB_copy_image 1 +#endif /* GL_ARB_copy_image */ + +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#endif +#endif /* GL_ARB_debug_output */ + +#ifndef GL_ARB_depth_buffer_float +#define GL_ARB_depth_buffer_float 1 +#endif /* GL_ARB_depth_buffer_float */ + +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +#endif /* GL_ARB_depth_clamp */ + +#ifndef GL_ARB_depth_texture +#define GL_ARB_depth_texture 1 +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#endif /* GL_ARB_depth_texture */ + +#ifndef GL_ARB_draw_buffers +#define GL_ARB_draw_buffers 1 +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15_ARB 0x8834 +typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); +#endif +#endif /* GL_ARB_draw_buffers */ + +#ifndef GL_ARB_draw_buffers_blend +#define GL_ARB_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif +#endif /* GL_ARB_draw_buffers_blend */ + +#ifndef GL_ARB_draw_elements_base_vertex +#define GL_ARB_draw_elements_base_vertex 1 +#endif /* GL_ARB_draw_elements_base_vertex */ + +#ifndef GL_ARB_draw_indirect +#define GL_ARB_draw_indirect 1 +#endif /* GL_ARB_draw_indirect */ + +#ifndef GL_ARB_draw_instanced +#define GL_ARB_draw_instanced 1 +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#endif +#endif /* GL_ARB_draw_instanced */ + +#ifndef GL_ARB_enhanced_layouts +#define GL_ARB_enhanced_layouts 1 +#endif /* GL_ARB_enhanced_layouts */ + +#ifndef GL_ARB_explicit_attrib_location +#define GL_ARB_explicit_attrib_location 1 +#endif /* GL_ARB_explicit_attrib_location */ + +#ifndef GL_ARB_explicit_uniform_location +#define GL_ARB_explicit_uniform_location 1 +#endif /* GL_ARB_explicit_uniform_location */ + +#ifndef GL_ARB_fragment_coord_conventions +#define GL_ARB_fragment_coord_conventions 1 +#endif /* GL_ARB_fragment_coord_conventions */ + +#ifndef GL_ARB_fragment_layer_viewport +#define GL_ARB_fragment_layer_viewport 1 +#endif /* GL_ARB_fragment_layer_viewport */ + +#ifndef GL_ARB_fragment_program +#define GL_ARB_fragment_program 1 +#define GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_LENGTH_ARB 0x8627 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_BINDING_ARB 0x8677 +#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_CURRENT_MATRIX_ARB 0x8641 +#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define GL_MATRIX0_ARB 0x88C0 +#define GL_MATRIX1_ARB 0x88C1 +#define GL_MATRIX2_ARB 0x88C2 +#define GL_MATRIX3_ARB 0x88C3 +#define GL_MATRIX4_ARB 0x88C4 +#define GL_MATRIX5_ARB 0x88C5 +#define GL_MATRIX6_ARB 0x88C6 +#define GL_MATRIX7_ARB 0x88C7 +#define GL_MATRIX8_ARB 0x88C8 +#define GL_MATRIX9_ARB 0x88C9 +#define GL_MATRIX10_ARB 0x88CA +#define GL_MATRIX11_ARB 0x88CB +#define GL_MATRIX12_ARB 0x88CC +#define GL_MATRIX13_ARB 0x88CD +#define GL_MATRIX14_ARB 0x88CE +#define GL_MATRIX15_ARB 0x88CF +#define GL_MATRIX16_ARB 0x88D0 +#define GL_MATRIX17_ARB 0x88D1 +#define GL_MATRIX18_ARB 0x88D2 +#define GL_MATRIX19_ARB 0x88D3 +#define GL_MATRIX20_ARB 0x88D4 +#define GL_MATRIX21_ARB 0x88D5 +#define GL_MATRIX22_ARB 0x88D6 +#define GL_MATRIX23_ARB 0x88D7 +#define GL_MATRIX24_ARB 0x88D8 +#define GL_MATRIX25_ARB 0x88D9 +#define GL_MATRIX26_ARB 0x88DA +#define GL_MATRIX27_ARB 0x88DB +#define GL_MATRIX28_ARB 0x88DC +#define GL_MATRIX29_ARB 0x88DD +#define GL_MATRIX30_ARB 0x88DE +#define GL_MATRIX31_ARB 0x88DF +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string); +typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string); +GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); +GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); +GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string); +GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); +#endif +#endif /* GL_ARB_fragment_program */ + +#ifndef GL_ARB_fragment_program_shadow +#define GL_ARB_fragment_program_shadow 1 +#endif /* GL_ARB_fragment_program_shadow */ + +#ifndef GL_ARB_fragment_shader +#define GL_ARB_fragment_shader 1 +#define GL_FRAGMENT_SHADER_ARB 0x8B30 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#endif /* GL_ARB_fragment_shader */ + +#ifndef GL_ARB_framebuffer_no_attachments +#define GL_ARB_framebuffer_no_attachments 1 +#endif /* GL_ARB_framebuffer_no_attachments */ + +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +#endif /* GL_ARB_framebuffer_object */ + +#ifndef GL_ARB_framebuffer_sRGB +#define GL_ARB_framebuffer_sRGB 1 +#endif /* GL_ARB_framebuffer_sRGB */ + +#ifndef GL_ARB_geometry_shader4 +#define GL_ARB_geometry_shader4 1 +#define GL_LINES_ADJACENCY_ARB 0x000A +#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D +#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 +#define GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif +#endif /* GL_ARB_geometry_shader4 */ + +#ifndef GL_ARB_get_program_binary +#define GL_ARB_get_program_binary 1 +#endif /* GL_ARB_get_program_binary */ + +#ifndef GL_ARB_gpu_shader5 +#define GL_ARB_gpu_shader5 1 +#endif /* GL_ARB_gpu_shader5 */ + +#ifndef GL_ARB_gpu_shader_fp64 +#define GL_ARB_gpu_shader_fp64 1 +#endif /* GL_ARB_gpu_shader_fp64 */ + +#ifndef GL_ARB_half_float_pixel +#define GL_ARB_half_float_pixel 1 +typedef unsigned short GLhalfARB; +#define GL_HALF_FLOAT_ARB 0x140B +#endif /* GL_ARB_half_float_pixel */ + +#ifndef GL_ARB_half_float_vertex +#define GL_ARB_half_float_vertex 1 +#endif /* GL_ARB_half_float_vertex */ + +#ifndef GL_ARB_imaging +#define GL_ARB_imaging 1 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#define GL_CONVOLUTION_1D 0x8010 +#define GL_CONVOLUTION_2D 0x8011 +#define GL_SEPARABLE_2D 0x8012 +#define GL_CONVOLUTION_BORDER_MODE 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS 0x8015 +#define GL_REDUCE 0x8016 +#define GL_CONVOLUTION_FORMAT 0x8017 +#define GL_CONVOLUTION_WIDTH 0x8018 +#define GL_CONVOLUTION_HEIGHT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 +#define GL_HISTOGRAM 0x8024 +#define GL_PROXY_HISTOGRAM 0x8025 +#define GL_HISTOGRAM_WIDTH 0x8026 +#define GL_HISTOGRAM_FORMAT 0x8027 +#define GL_HISTOGRAM_RED_SIZE 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C +#define GL_HISTOGRAM_SINK 0x802D +#define GL_MINMAX 0x802E +#define GL_MINMAX_FORMAT 0x802F +#define GL_MINMAX_SINK 0x8030 +#define GL_TABLE_TOO_LARGE 0x8031 +#define GL_COLOR_MATRIX 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB +#define GL_COLOR_TABLE 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 +#define GL_PROXY_COLOR_TABLE 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 +#define GL_COLOR_TABLE_SCALE 0x80D6 +#define GL_COLOR_TABLE_BIAS 0x80D7 +#define GL_COLOR_TABLE_FORMAT 0x80D8 +#define GL_COLOR_TABLE_WIDTH 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF +#define GL_CONSTANT_BORDER 0x8151 +#define GL_REPLICATE_BORDER 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR 0x8154 +typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table); +GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); +GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); +GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image); +GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glResetHistogram (GLenum target); +GLAPI void APIENTRY glResetMinmax (GLenum target); +#endif +#endif /* GL_ARB_imaging */ + +#ifndef GL_ARB_indirect_parameters +#define GL_ARB_indirect_parameters 1 +#define GL_PARAMETER_BUFFER_ARB 0x80EE +#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#endif +#endif /* GL_ARB_indirect_parameters */ + +#ifndef GL_ARB_instanced_arrays +#define GL_ARB_instanced_arrays 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); +#endif +#endif /* GL_ARB_instanced_arrays */ + +#ifndef GL_ARB_internalformat_query +#define GL_ARB_internalformat_query 1 +#endif /* GL_ARB_internalformat_query */ + +#ifndef GL_ARB_internalformat_query2 +#define GL_ARB_internalformat_query2 1 +#define GL_SRGB_DECODE_ARB 0x8299 +#endif /* GL_ARB_internalformat_query2 */ + +#ifndef GL_ARB_invalidate_subdata +#define GL_ARB_invalidate_subdata 1 +#endif /* GL_ARB_invalidate_subdata */ + +#ifndef GL_ARB_map_buffer_alignment +#define GL_ARB_map_buffer_alignment 1 +#endif /* GL_ARB_map_buffer_alignment */ + +#ifndef GL_ARB_map_buffer_range +#define GL_ARB_map_buffer_range 1 +#endif /* GL_ARB_map_buffer_range */ + +#ifndef GL_ARB_matrix_palette +#define GL_ARB_matrix_palette 1 +#define GL_MATRIX_PALETTE_ARB 0x8840 +#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 +#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 +#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 +#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 +#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 +#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 +#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 +#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 +#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 +typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); +typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); +GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); +GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); +GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); +GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_ARB_matrix_palette */ + +#ifndef GL_ARB_multi_bind +#define GL_ARB_multi_bind 1 +#endif /* GL_ARB_multi_bind */ + +#ifndef GL_ARB_multi_draw_indirect +#define GL_ARB_multi_draw_indirect 1 +#endif /* GL_ARB_multi_draw_indirect */ + +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert); +#endif +#endif /* GL_ARB_multisample */ + +#ifndef GL_ARB_multitexture +#define GL_ARB_multitexture 1 +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3_ARB 0x84C3 +#define GL_TEXTURE4_ARB 0x84C4 +#define GL_TEXTURE5_ARB 0x84C5 +#define GL_TEXTURE6_ARB 0x84C6 +#define GL_TEXTURE7_ARB 0x84C7 +#define GL_TEXTURE8_ARB 0x84C8 +#define GL_TEXTURE9_ARB 0x84C9 +#define GL_TEXTURE10_ARB 0x84CA +#define GL_TEXTURE11_ARB 0x84CB +#define GL_TEXTURE12_ARB 0x84CC +#define GL_TEXTURE13_ARB 0x84CD +#define GL_TEXTURE14_ARB 0x84CE +#define GL_TEXTURE15_ARB 0x84CF +#define GL_TEXTURE16_ARB 0x84D0 +#define GL_TEXTURE17_ARB 0x84D1 +#define GL_TEXTURE18_ARB 0x84D2 +#define GL_TEXTURE19_ARB 0x84D3 +#define GL_TEXTURE20_ARB 0x84D4 +#define GL_TEXTURE21_ARB 0x84D5 +#define GL_TEXTURE22_ARB 0x84D6 +#define GL_TEXTURE23_ARB 0x84D7 +#define GL_TEXTURE24_ARB 0x84D8 +#define GL_TEXTURE25_ARB 0x84D9 +#define GL_TEXTURE26_ARB 0x84DA +#define GL_TEXTURE27_ARB 0x84DB +#define GL_TEXTURE28_ARB 0x84DC +#define GL_TEXTURE29_ARB 0x84DD +#define GL_TEXTURE30_ARB 0x84DE +#define GL_TEXTURE31_ARB 0x84DF +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTextureARB (GLenum texture); +GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); +GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); +GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); +GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); +GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); +GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); +GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); +GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); +GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); +GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); +GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); +#endif +#endif /* GL_ARB_multitexture */ + +#ifndef GL_ARB_occlusion_query +#define GL_ARB_occlusion_query 1 +#define GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define GL_CURRENT_QUERY_ARB 0x8865 +#define GL_QUERY_RESULT_ARB 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#define GL_SAMPLES_PASSED_ARB 0x8914 +typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); +GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQueryARB (GLenum target); +GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); +#endif +#endif /* GL_ARB_occlusion_query */ + +#ifndef GL_ARB_occlusion_query2 +#define GL_ARB_occlusion_query2 1 +#endif /* GL_ARB_occlusion_query2 */ + +#ifndef GL_ARB_pixel_buffer_object +#define GL_ARB_pixel_buffer_object 1 +#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF +#endif /* GL_ARB_pixel_buffer_object */ + +#ifndef GL_ARB_point_parameters +#define GL_ARB_point_parameters 1 +#define GL_POINT_SIZE_MIN_ARB 0x8126 +#define GL_POINT_SIZE_MAX_ARB 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 +#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_ARB_point_parameters */ + +#ifndef GL_ARB_point_sprite +#define GL_ARB_point_sprite 1 +#define GL_POINT_SPRITE_ARB 0x8861 +#define GL_COORD_REPLACE_ARB 0x8862 +#endif /* GL_ARB_point_sprite */ + +#ifndef GL_ARB_program_interface_query +#define GL_ARB_program_interface_query 1 +#endif /* GL_ARB_program_interface_query */ + +#ifndef GL_ARB_provoking_vertex +#define GL_ARB_provoking_vertex 1 +#endif /* GL_ARB_provoking_vertex */ + +#ifndef GL_ARB_query_buffer_object +#define GL_ARB_query_buffer_object 1 +#endif /* GL_ARB_query_buffer_object */ + +#ifndef GL_ARB_robust_buffer_access_behavior +#define GL_ARB_robust_buffer_access_behavior 1 +#endif /* GL_ARB_robust_buffer_access_behavior */ + +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); +typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); +GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); +GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); +GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); +GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); +GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); +GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +#endif +#endif /* GL_ARB_robustness */ + +#ifndef GL_ARB_robustness_isolation +#define GL_ARB_robustness_isolation 1 +#endif /* GL_ARB_robustness_isolation */ + +#ifndef GL_ARB_sample_shading +#define GL_ARB_sample_shading 1 +#define GL_SAMPLE_SHADING_ARB 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); +#endif +#endif /* GL_ARB_sample_shading */ + +#ifndef GL_ARB_sampler_objects +#define GL_ARB_sampler_objects 1 +#endif /* GL_ARB_sampler_objects */ + +#ifndef GL_ARB_seamless_cube_map +#define GL_ARB_seamless_cube_map 1 +#endif /* GL_ARB_seamless_cube_map */ + +#ifndef GL_ARB_seamless_cubemap_per_texture +#define GL_ARB_seamless_cubemap_per_texture 1 +#endif /* GL_ARB_seamless_cubemap_per_texture */ + +#ifndef GL_ARB_separate_shader_objects +#define GL_ARB_separate_shader_objects 1 +#endif /* GL_ARB_separate_shader_objects */ + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ARB_shader_atomic_counters 1 +#endif /* GL_ARB_shader_atomic_counters */ + +#ifndef GL_ARB_shader_bit_encoding +#define GL_ARB_shader_bit_encoding 1 +#endif /* GL_ARB_shader_bit_encoding */ + +#ifndef GL_ARB_shader_draw_parameters +#define GL_ARB_shader_draw_parameters 1 +#endif /* GL_ARB_shader_draw_parameters */ + +#ifndef GL_ARB_shader_group_vote +#define GL_ARB_shader_group_vote 1 +#endif /* GL_ARB_shader_group_vote */ + +#ifndef GL_ARB_shader_image_load_store +#define GL_ARB_shader_image_load_store 1 +#endif /* GL_ARB_shader_image_load_store */ + +#ifndef GL_ARB_shader_image_size +#define GL_ARB_shader_image_size 1 +#endif /* GL_ARB_shader_image_size */ + +#ifndef GL_ARB_shader_objects +#define GL_ARB_shader_objects 1 +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef char GLcharARB; +#define GL_PROGRAM_OBJECT_ARB 0x8B40 +#define GL_SHADER_OBJECT_ARB 0x8B48 +#define GL_OBJECT_TYPE_ARB 0x8B4E +#define GL_OBJECT_SUBTYPE_ARB 0x8B4F +#define GL_FLOAT_VEC2_ARB 0x8B50 +#define GL_FLOAT_VEC3_ARB 0x8B51 +#define GL_FLOAT_VEC4_ARB 0x8B52 +#define GL_INT_VEC2_ARB 0x8B53 +#define GL_INT_VEC3_ARB 0x8B54 +#define GL_INT_VEC4_ARB 0x8B55 +#define GL_BOOL_ARB 0x8B56 +#define GL_BOOL_VEC2_ARB 0x8B57 +#define GL_BOOL_VEC3_ARB 0x8B58 +#define GL_BOOL_VEC4_ARB 0x8B59 +#define GL_FLOAT_MAT2_ARB 0x8B5A +#define GL_FLOAT_MAT3_ARB 0x8B5B +#define GL_FLOAT_MAT4_ARB 0x8B5C +#define GL_SAMPLER_1D_ARB 0x8B5D +#define GL_SAMPLER_2D_ARB 0x8B5E +#define GL_SAMPLER_3D_ARB 0x8B5F +#define GL_SAMPLER_CUBE_ARB 0x8B60 +#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 +#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 +#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 +#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 +#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 +#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 +#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 +#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 +#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 +#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 +#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 +typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); +typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); +typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); +typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); +typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); +typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); +GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); +GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); +GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); +GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); +GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); +GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); +GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); +GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); +GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); +GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); +GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); +GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); +GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#endif +#endif /* GL_ARB_shader_objects */ + +#ifndef GL_ARB_shader_precision +#define GL_ARB_shader_precision 1 +#endif /* GL_ARB_shader_precision */ + +#ifndef GL_ARB_shader_stencil_export +#define GL_ARB_shader_stencil_export 1 +#endif /* GL_ARB_shader_stencil_export */ + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_ARB_shader_storage_buffer_object 1 +#endif /* GL_ARB_shader_storage_buffer_object */ + +#ifndef GL_ARB_shader_subroutine +#define GL_ARB_shader_subroutine 1 +#endif /* GL_ARB_shader_subroutine */ + +#ifndef GL_ARB_shader_texture_lod +#define GL_ARB_shader_texture_lod 1 +#endif /* GL_ARB_shader_texture_lod */ + +#ifndef GL_ARB_shading_language_100 +#define GL_ARB_shading_language_100 1 +#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C +#endif /* GL_ARB_shading_language_100 */ + +#ifndef GL_ARB_shading_language_420pack +#define GL_ARB_shading_language_420pack 1 +#endif /* GL_ARB_shading_language_420pack */ + +#ifndef GL_ARB_shading_language_include +#define GL_ARB_shading_language_include 1 +#define GL_SHADER_INCLUDE_ARB 0x8DAE +#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define GL_NAMED_STRING_TYPE_ARB 0x8DEA +typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#endif +#endif /* GL_ARB_shading_language_include */ + +#ifndef GL_ARB_shading_language_packing +#define GL_ARB_shading_language_packing 1 +#endif /* GL_ARB_shading_language_packing */ + +#ifndef GL_ARB_shadow +#define GL_ARB_shadow 1 +#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C +#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D +#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E +#endif /* GL_ARB_shadow */ + +#ifndef GL_ARB_shadow_ambient +#define GL_ARB_shadow_ambient 1 +#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF +#endif /* GL_ARB_shadow_ambient */ + +#ifndef GL_ARB_sparse_texture +#define GL_ARB_sparse_texture 1 +#define GL_TEXTURE_SPARSE_ARB 0x91A6 +#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define GL_MIN_SPARSE_LEVEL_ARB 0x919B +#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A +#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 +typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#endif +#endif /* GL_ARB_sparse_texture */ + +#ifndef GL_ARB_stencil_texturing +#define GL_ARB_stencil_texturing 1 +#endif /* GL_ARB_stencil_texturing */ + +#ifndef GL_ARB_sync +#define GL_ARB_sync 1 +#endif /* GL_ARB_sync */ + +#ifndef GL_ARB_tessellation_shader +#define GL_ARB_tessellation_shader 1 +#endif /* GL_ARB_tessellation_shader */ + +#ifndef GL_ARB_texture_border_clamp +#define GL_ARB_texture_border_clamp 1 +#define GL_CLAMP_TO_BORDER_ARB 0x812D +#endif /* GL_ARB_texture_border_clamp */ + +#ifndef GL_ARB_texture_buffer_object +#define GL_ARB_texture_buffer_object 1 +#define GL_TEXTURE_BUFFER_ARB 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E +typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); +#endif +#endif /* GL_ARB_texture_buffer_object */ + +#ifndef GL_ARB_texture_buffer_object_rgb32 +#define GL_ARB_texture_buffer_object_rgb32 1 +#endif /* GL_ARB_texture_buffer_object_rgb32 */ + +#ifndef GL_ARB_texture_buffer_range +#define GL_ARB_texture_buffer_range 1 +#endif /* GL_ARB_texture_buffer_range */ + +#ifndef GL_ARB_texture_compression +#define GL_ARB_texture_compression 1 +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img); +#endif +#endif /* GL_ARB_texture_compression */ + +#ifndef GL_ARB_texture_compression_bptc +#define GL_ARB_texture_compression_bptc 1 +#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F +#endif /* GL_ARB_texture_compression_bptc */ + +#ifndef GL_ARB_texture_compression_rgtc +#define GL_ARB_texture_compression_rgtc 1 +#endif /* GL_ARB_texture_compression_rgtc */ + +#ifndef GL_ARB_texture_cube_map +#define GL_ARB_texture_cube_map 1 +#define GL_NORMAL_MAP_ARB 0x8511 +#define GL_REFLECTION_MAP_ARB 0x8512 +#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C +#endif /* GL_ARB_texture_cube_map */ + +#ifndef GL_ARB_texture_cube_map_array +#define GL_ARB_texture_cube_map_array 1 +#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F +#endif /* GL_ARB_texture_cube_map_array */ + +#ifndef GL_ARB_texture_env_add +#define GL_ARB_texture_env_add 1 +#endif /* GL_ARB_texture_env_add */ + +#ifndef GL_ARB_texture_env_combine +#define GL_ARB_texture_env_combine 1 +#define GL_COMBINE_ARB 0x8570 +#define GL_COMBINE_RGB_ARB 0x8571 +#define GL_COMBINE_ALPHA_ARB 0x8572 +#define GL_SOURCE0_RGB_ARB 0x8580 +#define GL_SOURCE1_RGB_ARB 0x8581 +#define GL_SOURCE2_RGB_ARB 0x8582 +#define GL_SOURCE0_ALPHA_ARB 0x8588 +#define GL_SOURCE1_ALPHA_ARB 0x8589 +#define GL_SOURCE2_ALPHA_ARB 0x858A +#define GL_OPERAND0_RGB_ARB 0x8590 +#define GL_OPERAND1_RGB_ARB 0x8591 +#define GL_OPERAND2_RGB_ARB 0x8592 +#define GL_OPERAND0_ALPHA_ARB 0x8598 +#define GL_OPERAND1_ALPHA_ARB 0x8599 +#define GL_OPERAND2_ALPHA_ARB 0x859A +#define GL_RGB_SCALE_ARB 0x8573 +#define GL_ADD_SIGNED_ARB 0x8574 +#define GL_INTERPOLATE_ARB 0x8575 +#define GL_SUBTRACT_ARB 0x84E7 +#define GL_CONSTANT_ARB 0x8576 +#define GL_PRIMARY_COLOR_ARB 0x8577 +#define GL_PREVIOUS_ARB 0x8578 +#endif /* GL_ARB_texture_env_combine */ + +#ifndef GL_ARB_texture_env_crossbar +#define GL_ARB_texture_env_crossbar 1 +#endif /* GL_ARB_texture_env_crossbar */ + +#ifndef GL_ARB_texture_env_dot3 +#define GL_ARB_texture_env_dot3 1 +#define GL_DOT3_RGB_ARB 0x86AE +#define GL_DOT3_RGBA_ARB 0x86AF +#endif /* GL_ARB_texture_env_dot3 */ + +#ifndef GL_ARB_texture_float +#define GL_ARB_texture_float 1 +#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 +#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 +#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 +#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 +#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 +#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 +#define GL_RGBA32F_ARB 0x8814 +#define GL_RGB32F_ARB 0x8815 +#define GL_ALPHA32F_ARB 0x8816 +#define GL_INTENSITY32F_ARB 0x8817 +#define GL_LUMINANCE32F_ARB 0x8818 +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define GL_RGBA16F_ARB 0x881A +#define GL_RGB16F_ARB 0x881B +#define GL_ALPHA16F_ARB 0x881C +#define GL_INTENSITY16F_ARB 0x881D +#define GL_LUMINANCE16F_ARB 0x881E +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#endif /* GL_ARB_texture_float */ + +#ifndef GL_ARB_texture_gather +#define GL_ARB_texture_gather 1 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F +#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F +#endif /* GL_ARB_texture_gather */ + +#ifndef GL_ARB_texture_mirror_clamp_to_edge +#define GL_ARB_texture_mirror_clamp_to_edge 1 +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ + +#ifndef GL_ARB_texture_mirrored_repeat +#define GL_ARB_texture_mirrored_repeat 1 +#define GL_MIRRORED_REPEAT_ARB 0x8370 +#endif /* GL_ARB_texture_mirrored_repeat */ + +#ifndef GL_ARB_texture_multisample +#define GL_ARB_texture_multisample 1 +#endif /* GL_ARB_texture_multisample */ + +#ifndef GL_ARB_texture_non_power_of_two +#define GL_ARB_texture_non_power_of_two 1 +#endif /* GL_ARB_texture_non_power_of_two */ + +#ifndef GL_ARB_texture_query_levels +#define GL_ARB_texture_query_levels 1 +#endif /* GL_ARB_texture_query_levels */ + +#ifndef GL_ARB_texture_query_lod +#define GL_ARB_texture_query_lod 1 +#endif /* GL_ARB_texture_query_lod */ + +#ifndef GL_ARB_texture_rectangle +#define GL_ARB_texture_rectangle 1 +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#endif /* GL_ARB_texture_rectangle */ + +#ifndef GL_ARB_texture_rg +#define GL_ARB_texture_rg 1 +#endif /* GL_ARB_texture_rg */ + +#ifndef GL_ARB_texture_rgb10_a2ui +#define GL_ARB_texture_rgb10_a2ui 1 +#endif /* GL_ARB_texture_rgb10_a2ui */ + +#ifndef GL_ARB_texture_stencil8 +#define GL_ARB_texture_stencil8 1 +#endif /* GL_ARB_texture_stencil8 */ + +#ifndef GL_ARB_texture_storage +#define GL_ARB_texture_storage 1 +#endif /* GL_ARB_texture_storage */ + +#ifndef GL_ARB_texture_storage_multisample +#define GL_ARB_texture_storage_multisample 1 +#endif /* GL_ARB_texture_storage_multisample */ + +#ifndef GL_ARB_texture_swizzle +#define GL_ARB_texture_swizzle 1 +#endif /* GL_ARB_texture_swizzle */ + +#ifndef GL_ARB_texture_view +#define GL_ARB_texture_view 1 +#endif /* GL_ARB_texture_view */ + +#ifndef GL_ARB_timer_query +#define GL_ARB_timer_query 1 +#endif /* GL_ARB_timer_query */ + +#ifndef GL_ARB_transform_feedback2 +#define GL_ARB_transform_feedback2 1 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#endif /* GL_ARB_transform_feedback2 */ + +#ifndef GL_ARB_transform_feedback3 +#define GL_ARB_transform_feedback3 1 +#endif /* GL_ARB_transform_feedback3 */ + +#ifndef GL_ARB_transform_feedback_instanced +#define GL_ARB_transform_feedback_instanced 1 +#endif /* GL_ARB_transform_feedback_instanced */ + +#ifndef GL_ARB_transpose_matrix +#define GL_ARB_transpose_matrix 1 +#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); +GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); +GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); +GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); +#endif +#endif /* GL_ARB_transpose_matrix */ + +#ifndef GL_ARB_uniform_buffer_object +#define GL_ARB_uniform_buffer_object 1 +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#endif /* GL_ARB_uniform_buffer_object */ + +#ifndef GL_ARB_vertex_array_bgra +#define GL_ARB_vertex_array_bgra 1 +#endif /* GL_ARB_vertex_array_bgra */ + +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +#endif /* GL_ARB_vertex_array_object */ + +#ifndef GL_ARB_vertex_attrib_64bit +#define GL_ARB_vertex_attrib_64bit 1 +#endif /* GL_ARB_vertex_attrib_64bit */ + +#ifndef GL_ARB_vertex_attrib_binding +#define GL_ARB_vertex_attrib_binding 1 +#endif /* GL_ARB_vertex_attrib_binding */ + +#ifndef GL_ARB_vertex_blend +#define GL_ARB_vertex_blend 1 +#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 +#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 +#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 +#define GL_VERTEX_BLEND_ARB 0x86A7 +#define GL_CURRENT_WEIGHT_ARB 0x86A8 +#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 +#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA +#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB +#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC +#define GL_WEIGHT_ARRAY_ARB 0x86AD +#define GL_MODELVIEW0_ARB 0x1700 +#define GL_MODELVIEW1_ARB 0x850A +#define GL_MODELVIEW2_ARB 0x8722 +#define GL_MODELVIEW3_ARB 0x8723 +#define GL_MODELVIEW4_ARB 0x8724 +#define GL_MODELVIEW5_ARB 0x8725 +#define GL_MODELVIEW6_ARB 0x8726 +#define GL_MODELVIEW7_ARB 0x8727 +#define GL_MODELVIEW8_ARB 0x8728 +#define GL_MODELVIEW9_ARB 0x8729 +#define GL_MODELVIEW10_ARB 0x872A +#define GL_MODELVIEW11_ARB 0x872B +#define GL_MODELVIEW12_ARB 0x872C +#define GL_MODELVIEW13_ARB 0x872D +#define GL_MODELVIEW14_ARB 0x872E +#define GL_MODELVIEW15_ARB 0x872F +#define GL_MODELVIEW16_ARB 0x8730 +#define GL_MODELVIEW17_ARB 0x8731 +#define GL_MODELVIEW18_ARB 0x8732 +#define GL_MODELVIEW19_ARB 0x8733 +#define GL_MODELVIEW20_ARB 0x8734 +#define GL_MODELVIEW21_ARB 0x8735 +#define GL_MODELVIEW22_ARB 0x8736 +#define GL_MODELVIEW23_ARB 0x8737 +#define GL_MODELVIEW24_ARB 0x8738 +#define GL_MODELVIEW25_ARB 0x8739 +#define GL_MODELVIEW26_ARB 0x873A +#define GL_MODELVIEW27_ARB 0x873B +#define GL_MODELVIEW28_ARB 0x873C +#define GL_MODELVIEW29_ARB 0x873D +#define GL_MODELVIEW30_ARB 0x873E +#define GL_MODELVIEW31_ARB 0x873F +typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); +typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); +typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); +typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); +typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); +typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); +typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); +GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); +GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); +GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); +GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); +GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); +GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); +GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); +GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glVertexBlendARB (GLint count); +#endif +#endif /* GL_ARB_vertex_blend */ + +#ifndef GL_ARB_vertex_buffer_object +#define GL_ARB_vertex_buffer_object 1 +typedef ptrdiff_t GLsizeiptrARB; +typedef ptrdiff_t GLintptrARB; +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_READ_WRITE_ARB 0x88BA +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_DYNAMIC_COPY_ARB 0x88EA +typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); +GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); +GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); +GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); +GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_ARB_vertex_buffer_object */ + +#ifndef GL_ARB_vertex_program +#define GL_ARB_vertex_program 1 +#define GL_COLOR_SUM_ARB 0x8458 +#define GL_VERTEX_PROGRAM_ARB 0x8620 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); +GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); +GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer); +#endif +#endif /* GL_ARB_vertex_program */ + +#ifndef GL_ARB_vertex_shader +#define GL_ARB_vertex_shader 1 +#define GL_VERTEX_SHADER_ARB 0x8B31 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); +GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); +#endif +#endif /* GL_ARB_vertex_shader */ + +#ifndef GL_ARB_vertex_type_10f_11f_11f_rev +#define GL_ARB_vertex_type_10f_11f_11f_rev 1 +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ + +#ifndef GL_ARB_vertex_type_2_10_10_10_rev +#define GL_ARB_vertex_type_2_10_10_10_rev 1 +#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ + +#ifndef GL_ARB_viewport_array +#define GL_ARB_viewport_array 1 +#endif /* GL_ARB_viewport_array */ + +#ifndef GL_ARB_window_pos +#define GL_ARB_window_pos 1 +typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); +GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); +GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); +GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); +#endif +#endif /* GL_ARB_window_pos */ + +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +#endif /* GL_KHR_debug */ + +#ifndef GL_KHR_texture_compression_astc_hdr +#define GL_KHR_texture_compression_astc_hdr 1 +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif /* GL_KHR_texture_compression_astc_hdr */ + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_KHR_texture_compression_astc_ldr 1 +#endif /* GL_KHR_texture_compression_astc_ldr */ + +#ifndef GL_OES_byte_coordinates +#define GL_OES_byte_coordinates 1 +typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s); +typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t); +typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r); +typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q); +typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x); +typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y); +typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z); +typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s); +GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t); +GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r); +GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); +GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glTexCoord1bOES (GLbyte s); +GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t); +GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r); +GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q); +GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex2bOES (GLbyte x); +GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y); +GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z); +GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords); +#endif +#endif /* GL_OES_byte_coordinates */ + +#ifndef GL_OES_compressed_paletted_texture +#define GL_OES_compressed_paletted_texture 1 +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif /* GL_OES_compressed_paletted_texture */ + +#ifndef GL_OES_fixed_point +#define GL_OES_fixed_point 1 +typedef GLint GLfixed; +#define GL_FIXED_OES 0x140C +typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref); +typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth); +typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation); +typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation); +typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width); +typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz); +typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size); +typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units); +typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert); +typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value); +typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); +typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue); +typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components); +typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u); +typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v); +typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v); +typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values); +typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component); +typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); +typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); +typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2); +typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token); +typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values); +typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities); +typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y); +typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w); +typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); +typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2); +typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s); +typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t); +typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r); +typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x); +typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y); +typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref); +GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glClearDepthxOES (GLfixed depth); +GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation); +GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f); +GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation); +GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glLineWidthxOES (GLfixed width); +GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz); +GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glPointSizexOES (GLfixed size); +GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units); +GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glSampleCoverageOES (GLfixed value, GLboolean invert); +GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value); +GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); +GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue); +GLAPI void APIENTRY glColor3xvOES (const GLfixed *components); +GLAPI void APIENTRY glColor4xvOES (const GLfixed *components); +GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u); +GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords); +GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v); +GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer); +GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v); +GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values); +GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glIndexxOES (GLfixed component); +GLAPI void APIENTRY glIndexxvOES (const GLfixed *component); +GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); +GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); +GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2); +GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); +GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s); +GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t); +GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r); +GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glPassThroughxOES (GLfixed token); +GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values); +GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param); +GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor); +GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities); +GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y); +GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w); +GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); +GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2); +GLAPI void APIENTRY glTexCoord1xOES (GLfixed s); +GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t); +GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r); +GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glVertex2xOES (GLfixed x); +GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y); +GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords); +#endif +#endif /* GL_OES_fixed_point */ + +#ifndef GL_OES_query_matrix +#define GL_OES_query_matrix 1 +typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent); +#endif +#endif /* GL_OES_query_matrix */ + +#ifndef GL_OES_read_format +#define GL_OES_read_format 1 +#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B +#endif /* GL_OES_read_format */ + +#ifndef GL_OES_single_precision +#define GL_OES_single_precision 1 +typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth); +typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation); +typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f); +typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation); +typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearDepthfOES (GLclampf depth); +GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation); +GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f); +GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation); +GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +#endif +#endif /* GL_OES_single_precision */ + +#ifndef GL_3DFX_multisample +#define GL_3DFX_multisample 1 +#define GL_MULTISAMPLE_3DFX 0x86B2 +#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 +#define GL_SAMPLES_3DFX 0x86B4 +#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 +#endif /* GL_3DFX_multisample */ + +#ifndef GL_3DFX_tbuffer +#define GL_3DFX_tbuffer 1 +typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); +#endif +#endif /* GL_3DFX_tbuffer */ + +#ifndef GL_3DFX_texture_compression_FXT1 +#define GL_3DFX_texture_compression_FXT1 1 +#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 +#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 +#endif /* GL_3DFX_texture_compression_FXT1 */ + +#ifndef GL_AMD_blend_minmax_factor +#define GL_AMD_blend_minmax_factor 1 +#define GL_FACTOR_MIN_AMD 0x901C +#define GL_FACTOR_MAX_AMD 0x901D +#endif /* GL_AMD_blend_minmax_factor */ + +#ifndef GL_AMD_conservative_depth +#define GL_AMD_conservative_depth 1 +#endif /* GL_AMD_conservative_depth */ + +#ifndef GL_AMD_debug_output +#define GL_AMD_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 +#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 +#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 +#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A +#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B +#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C +#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D +#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E +#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F +#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 +typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); +#endif +#endif /* GL_AMD_debug_output */ + +#ifndef GL_AMD_depth_clamp_separate +#define GL_AMD_depth_clamp_separate 1 +#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E +#define GL_DEPTH_CLAMP_FAR_AMD 0x901F +#endif /* GL_AMD_depth_clamp_separate */ + +#ifndef GL_AMD_draw_buffers_blend +#define GL_AMD_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +#endif +#endif /* GL_AMD_draw_buffers_blend */ + +#ifndef GL_AMD_gcn_shader +#define GL_AMD_gcn_shader 1 +#endif /* GL_AMD_gcn_shader */ + +#ifndef GL_AMD_gpu_shader_int64 +#define GL_AMD_gpu_shader_int64 1 +typedef int64_t GLint64EXT; +#define GL_INT64_NV 0x140E +#define GL_UNSIGNED_INT64_NV 0x140F +#define GL_INT8_NV 0x8FE0 +#define GL_INT8_VEC2_NV 0x8FE1 +#define GL_INT8_VEC3_NV 0x8FE2 +#define GL_INT8_VEC4_NV 0x8FE3 +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 +#define GL_INT64_VEC2_NV 0x8FE9 +#define GL_INT64_VEC3_NV 0x8FEA +#define GL_INT64_VEC4_NV 0x8FEB +#define GL_UNSIGNED_INT8_NV 0x8FEC +#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define GL_UNSIGNED_INT16_NV 0x8FF0 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB +typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); +GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); +GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); +GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); +GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); +GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); +GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_AMD_gpu_shader_int64 */ + +#ifndef GL_AMD_interleaved_elements +#define GL_AMD_interleaved_elements 1 +#define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 +#define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 +typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param); +#endif +#endif /* GL_AMD_interleaved_elements */ + +#ifndef GL_AMD_multi_draw_indirect +#define GL_AMD_multi_draw_indirect 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); +#endif +#endif /* GL_AMD_multi_draw_indirect */ + +#ifndef GL_AMD_name_gen_delete +#define GL_AMD_name_gen_delete 1 +#define GL_DATA_BUFFER_AMD 0x9151 +#define GL_PERFORMANCE_MONITOR_AMD 0x9152 +#define GL_QUERY_OBJECT_AMD 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 +#define GL_SAMPLER_OBJECT_AMD 0x9155 +typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); +typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); +typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); +GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); +GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); +#endif +#endif /* GL_AMD_name_gen_delete */ + +#ifndef GL_AMD_occlusion_query_event +#define GL_AMD_occlusion_query_event 1 +#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F +#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001 +#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002 +#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004 +#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008 +#define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF +typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param); +#endif +#endif /* GL_AMD_occlusion_query_event */ + +#ifndef GL_AMD_performance_monitor +#define GL_AMD_performance_monitor 1 +#define GL_COUNTER_TYPE_AMD 0x8BC0 +#define GL_COUNTER_RANGE_AMD 0x8BC1 +#define GL_UNSIGNED_INT64_AMD 0x8BC2 +#define GL_PERCENTAGE_AMD 0x8BC3 +#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define GL_PERFMON_RESULT_AMD 0x8BC6 +typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); +typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); +typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); +typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); +GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); +GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); +GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); +GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); +GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); +GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif +#endif /* GL_AMD_performance_monitor */ + +#ifndef GL_AMD_pinned_memory +#define GL_AMD_pinned_memory 1 +#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 +#endif /* GL_AMD_pinned_memory */ + +#ifndef GL_AMD_query_buffer_object +#define GL_AMD_query_buffer_object 1 +#define GL_QUERY_BUFFER_AMD 0x9192 +#define GL_QUERY_BUFFER_BINDING_AMD 0x9193 +#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 +#endif /* GL_AMD_query_buffer_object */ + +#ifndef GL_AMD_sample_positions +#define GL_AMD_sample_positions 1 +#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F +typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); +#endif +#endif /* GL_AMD_sample_positions */ + +#ifndef GL_AMD_seamless_cubemap_per_texture +#define GL_AMD_seamless_cubemap_per_texture 1 +#endif /* GL_AMD_seamless_cubemap_per_texture */ + +#ifndef GL_AMD_shader_atomic_counter_ops +#define GL_AMD_shader_atomic_counter_ops 1 +#endif /* GL_AMD_shader_atomic_counter_ops */ + +#ifndef GL_AMD_shader_stencil_export +#define GL_AMD_shader_stencil_export 1 +#endif /* GL_AMD_shader_stencil_export */ + +#ifndef GL_AMD_shader_trinary_minmax +#define GL_AMD_shader_trinary_minmax 1 +#endif /* GL_AMD_shader_trinary_minmax */ + +#ifndef GL_AMD_sparse_texture +#define GL_AMD_sparse_texture 1 +#define GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A +#define GL_MIN_SPARSE_LEVEL_AMD 0x919B +#define GL_MIN_LOD_WARNING_AMD 0x919C +#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 +typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +#endif +#endif /* GL_AMD_sparse_texture */ + +#ifndef GL_AMD_stencil_operation_extended +#define GL_AMD_stencil_operation_extended 1 +#define GL_SET_AMD 0x874A +#define GL_REPLACE_VALUE_AMD 0x874B +#define GL_STENCIL_OP_VALUE_AMD 0x874C +#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D +typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); +#endif +#endif /* GL_AMD_stencil_operation_extended */ + +#ifndef GL_AMD_texture_texture4 +#define GL_AMD_texture_texture4 1 +#endif /* GL_AMD_texture_texture4 */ + +#ifndef GL_AMD_transform_feedback3_lines_triangles +#define GL_AMD_transform_feedback3_lines_triangles 1 +#endif /* GL_AMD_transform_feedback3_lines_triangles */ + +#ifndef GL_AMD_transform_feedback4 +#define GL_AMD_transform_feedback4 1 +#define GL_STREAM_RASTERIZATION_AMD 0x91A0 +#endif /* GL_AMD_transform_feedback4 */ + +#ifndef GL_AMD_vertex_shader_layer +#define GL_AMD_vertex_shader_layer 1 +#endif /* GL_AMD_vertex_shader_layer */ + +#ifndef GL_AMD_vertex_shader_tessellator +#define GL_AMD_vertex_shader_tessellator 1 +#define GL_SAMPLER_BUFFER_AMD 0x9001 +#define GL_INT_SAMPLER_BUFFER_AMD 0x9002 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 +#define GL_TESSELLATION_MODE_AMD 0x9004 +#define GL_TESSELLATION_FACTOR_AMD 0x9005 +#define GL_DISCRETE_AMD 0x9006 +#define GL_CONTINUOUS_AMD 0x9007 +typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); +GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); +#endif +#endif /* GL_AMD_vertex_shader_tessellator */ + +#ifndef GL_AMD_vertex_shader_viewport_index +#define GL_AMD_vertex_shader_viewport_index 1 +#endif /* GL_AMD_vertex_shader_viewport_index */ + +#ifndef GL_APPLE_aux_depth_stencil +#define GL_APPLE_aux_depth_stencil 1 +#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 +#endif /* GL_APPLE_aux_depth_stencil */ + +#ifndef GL_APPLE_client_storage +#define GL_APPLE_client_storage 1 +#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 +#endif /* GL_APPLE_client_storage */ + +#ifndef GL_APPLE_element_array +#define GL_APPLE_element_array 1 +#define GL_ELEMENT_ARRAY_APPLE 0x8A0C +#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D +#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E +typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer); +GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#endif +#endif /* GL_APPLE_element_array */ + +#ifndef GL_APPLE_fence +#define GL_APPLE_fence 1 +#define GL_DRAW_PIXELS_APPLE 0x8A0A +#define GL_FENCE_APPLE 0x8A0B +typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); +typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); +typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); +GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); +GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); +GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); +GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); +#endif +#endif /* GL_APPLE_fence */ + +#ifndef GL_APPLE_float_pixels +#define GL_APPLE_float_pixels 1 +#define GL_HALF_APPLE 0x140B +#define GL_RGBA_FLOAT32_APPLE 0x8814 +#define GL_RGB_FLOAT32_APPLE 0x8815 +#define GL_ALPHA_FLOAT32_APPLE 0x8816 +#define GL_INTENSITY_FLOAT32_APPLE 0x8817 +#define GL_LUMINANCE_FLOAT32_APPLE 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 +#define GL_RGBA_FLOAT16_APPLE 0x881A +#define GL_RGB_FLOAT16_APPLE 0x881B +#define GL_ALPHA_FLOAT16_APPLE 0x881C +#define GL_INTENSITY_FLOAT16_APPLE 0x881D +#define GL_LUMINANCE_FLOAT16_APPLE 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F +#define GL_COLOR_FLOAT_APPLE 0x8A0F +#endif /* GL_APPLE_float_pixels */ + +#ifndef GL_APPLE_flush_buffer_range +#define GL_APPLE_flush_buffer_range 1 +#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 +#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 +typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); +#endif +#endif /* GL_APPLE_flush_buffer_range */ + +#ifndef GL_APPLE_object_purgeable +#define GL_APPLE_object_purgeable 1 +#define GL_BUFFER_OBJECT_APPLE 0x85B3 +#define GL_RELEASED_APPLE 0x8A19 +#define GL_VOLATILE_APPLE 0x8A1A +#define GL_RETAINED_APPLE 0x8A1B +#define GL_UNDEFINED_APPLE 0x8A1C +#define GL_PURGEABLE_APPLE 0x8A1D +typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); +typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); +GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); +GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); +#endif +#endif /* GL_APPLE_object_purgeable */ + +#ifndef GL_APPLE_rgb_422 +#define GL_APPLE_rgb_422 1 +#define GL_RGB_422_APPLE 0x8A1F +#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#define GL_RGB_RAW_422_APPLE 0x8A51 +#endif /* GL_APPLE_rgb_422 */ + +#ifndef GL_APPLE_row_bytes +#define GL_APPLE_row_bytes 1 +#define GL_PACK_ROW_BYTES_APPLE 0x8A15 +#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 +#endif /* GL_APPLE_row_bytes */ + +#ifndef GL_APPLE_specular_vector +#define GL_APPLE_specular_vector 1 +#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 +#endif /* GL_APPLE_specular_vector */ + +#ifndef GL_APPLE_texture_range +#define GL_APPLE_texture_range 1 +#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 +#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 +#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC +#define GL_STORAGE_PRIVATE_APPLE 0x85BD +#define GL_STORAGE_CACHED_APPLE 0x85BE +#define GL_STORAGE_SHARED_APPLE 0x85BF +typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer); +GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_APPLE_texture_range */ + +#ifndef GL_APPLE_transform_hint +#define GL_APPLE_transform_hint 1 +#define GL_TRANSFORM_HINT_APPLE 0x85B1 +#endif /* GL_APPLE_transform_hint */ + +#ifndef GL_APPLE_vertex_array_object +#define GL_APPLE_vertex_array_object 1 +#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); +GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); +#endif +#endif /* GL_APPLE_vertex_array_object */ + +#ifndef GL_APPLE_vertex_array_range +#define GL_APPLE_vertex_array_range 1 +#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E +#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F +#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 +#define GL_STORAGE_CLIENT_APPLE 0x85B4 +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); +typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer); +GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer); +GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); +#endif +#endif /* GL_APPLE_vertex_array_range */ + +#ifndef GL_APPLE_vertex_program_evaluators +#define GL_APPLE_vertex_program_evaluators 1 +#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 +#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 +#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 +#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 +#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 +#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 +#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 +#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 +#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 +#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); +typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); +GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); +GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); +GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +#endif +#endif /* GL_APPLE_vertex_program_evaluators */ + +#ifndef GL_APPLE_ycbcr_422 +#define GL_APPLE_ycbcr_422 1 +#define GL_YCBCR_422_APPLE 0x85B9 +#endif /* GL_APPLE_ycbcr_422 */ + +#ifndef GL_ATI_draw_buffers +#define GL_ATI_draw_buffers 1 +#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 +#define GL_DRAW_BUFFER0_ATI 0x8825 +#define GL_DRAW_BUFFER1_ATI 0x8826 +#define GL_DRAW_BUFFER2_ATI 0x8827 +#define GL_DRAW_BUFFER3_ATI 0x8828 +#define GL_DRAW_BUFFER4_ATI 0x8829 +#define GL_DRAW_BUFFER5_ATI 0x882A +#define GL_DRAW_BUFFER6_ATI 0x882B +#define GL_DRAW_BUFFER7_ATI 0x882C +#define GL_DRAW_BUFFER8_ATI 0x882D +#define GL_DRAW_BUFFER9_ATI 0x882E +#define GL_DRAW_BUFFER10_ATI 0x882F +#define GL_DRAW_BUFFER11_ATI 0x8830 +#define GL_DRAW_BUFFER12_ATI 0x8831 +#define GL_DRAW_BUFFER13_ATI 0x8832 +#define GL_DRAW_BUFFER14_ATI 0x8833 +#define GL_DRAW_BUFFER15_ATI 0x8834 +typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); +#endif +#endif /* GL_ATI_draw_buffers */ + +#ifndef GL_ATI_element_array +#define GL_ATI_element_array 1 +#define GL_ELEMENT_ARRAY_ATI 0x8768 +#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 +#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A +typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer); +GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); +GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); +#endif +#endif /* GL_ATI_element_array */ + +#ifndef GL_ATI_envmap_bumpmap +#define GL_ATI_envmap_bumpmap 1 +#define GL_BUMP_ROT_MATRIX_ATI 0x8775 +#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 +#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 +#define GL_BUMP_TEX_UNITS_ATI 0x8778 +#define GL_DUDV_ATI 0x8779 +#define GL_DU8DV8_ATI 0x877A +#define GL_BUMP_ENVMAP_ATI 0x877B +#define GL_BUMP_TARGET_ATI 0x877C +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); +GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); +GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); +#endif +#endif /* GL_ATI_envmap_bumpmap */ + +#ifndef GL_ATI_fragment_shader +#define GL_ATI_fragment_shader 1 +#define GL_FRAGMENT_SHADER_ATI 0x8920 +#define GL_REG_0_ATI 0x8921 +#define GL_REG_1_ATI 0x8922 +#define GL_REG_2_ATI 0x8923 +#define GL_REG_3_ATI 0x8924 +#define GL_REG_4_ATI 0x8925 +#define GL_REG_5_ATI 0x8926 +#define GL_REG_6_ATI 0x8927 +#define GL_REG_7_ATI 0x8928 +#define GL_REG_8_ATI 0x8929 +#define GL_REG_9_ATI 0x892A +#define GL_REG_10_ATI 0x892B +#define GL_REG_11_ATI 0x892C +#define GL_REG_12_ATI 0x892D +#define GL_REG_13_ATI 0x892E +#define GL_REG_14_ATI 0x892F +#define GL_REG_15_ATI 0x8930 +#define GL_REG_16_ATI 0x8931 +#define GL_REG_17_ATI 0x8932 +#define GL_REG_18_ATI 0x8933 +#define GL_REG_19_ATI 0x8934 +#define GL_REG_20_ATI 0x8935 +#define GL_REG_21_ATI 0x8936 +#define GL_REG_22_ATI 0x8937 +#define GL_REG_23_ATI 0x8938 +#define GL_REG_24_ATI 0x8939 +#define GL_REG_25_ATI 0x893A +#define GL_REG_26_ATI 0x893B +#define GL_REG_27_ATI 0x893C +#define GL_REG_28_ATI 0x893D +#define GL_REG_29_ATI 0x893E +#define GL_REG_30_ATI 0x893F +#define GL_REG_31_ATI 0x8940 +#define GL_CON_0_ATI 0x8941 +#define GL_CON_1_ATI 0x8942 +#define GL_CON_2_ATI 0x8943 +#define GL_CON_3_ATI 0x8944 +#define GL_CON_4_ATI 0x8945 +#define GL_CON_5_ATI 0x8946 +#define GL_CON_6_ATI 0x8947 +#define GL_CON_7_ATI 0x8948 +#define GL_CON_8_ATI 0x8949 +#define GL_CON_9_ATI 0x894A +#define GL_CON_10_ATI 0x894B +#define GL_CON_11_ATI 0x894C +#define GL_CON_12_ATI 0x894D +#define GL_CON_13_ATI 0x894E +#define GL_CON_14_ATI 0x894F +#define GL_CON_15_ATI 0x8950 +#define GL_CON_16_ATI 0x8951 +#define GL_CON_17_ATI 0x8952 +#define GL_CON_18_ATI 0x8953 +#define GL_CON_19_ATI 0x8954 +#define GL_CON_20_ATI 0x8955 +#define GL_CON_21_ATI 0x8956 +#define GL_CON_22_ATI 0x8957 +#define GL_CON_23_ATI 0x8958 +#define GL_CON_24_ATI 0x8959 +#define GL_CON_25_ATI 0x895A +#define GL_CON_26_ATI 0x895B +#define GL_CON_27_ATI 0x895C +#define GL_CON_28_ATI 0x895D +#define GL_CON_29_ATI 0x895E +#define GL_CON_30_ATI 0x895F +#define GL_CON_31_ATI 0x8960 +#define GL_MOV_ATI 0x8961 +#define GL_ADD_ATI 0x8963 +#define GL_MUL_ATI 0x8964 +#define GL_SUB_ATI 0x8965 +#define GL_DOT3_ATI 0x8966 +#define GL_DOT4_ATI 0x8967 +#define GL_MAD_ATI 0x8968 +#define GL_LERP_ATI 0x8969 +#define GL_CND_ATI 0x896A +#define GL_CND0_ATI 0x896B +#define GL_DOT2_ADD_ATI 0x896C +#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D +#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E +#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F +#define GL_NUM_PASSES_ATI 0x8970 +#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 +#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 +#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 +#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 +#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 +#define GL_SWIZZLE_STR_ATI 0x8976 +#define GL_SWIZZLE_STQ_ATI 0x8977 +#define GL_SWIZZLE_STR_DR_ATI 0x8978 +#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 +#define GL_SWIZZLE_STRQ_ATI 0x897A +#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B +#define GL_RED_BIT_ATI 0x00000001 +#define GL_GREEN_BIT_ATI 0x00000002 +#define GL_BLUE_BIT_ATI 0x00000004 +#define GL_2X_BIT_ATI 0x00000001 +#define GL_4X_BIT_ATI 0x00000002 +#define GL_8X_BIT_ATI 0x00000004 +#define GL_HALF_BIT_ATI 0x00000008 +#define GL_QUARTER_BIT_ATI 0x00000010 +#define GL_EIGHTH_BIT_ATI 0x00000020 +#define GL_SATURATE_BIT_ATI 0x00000040 +#define GL_COMP_BIT_ATI 0x00000002 +#define GL_NEGATE_BIT_ATI 0x00000004 +#define GL_BIAS_BIT_ATI 0x00000008 +typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); +typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); +typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); +GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); +GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); +GLAPI void APIENTRY glBeginFragmentShaderATI (void); +GLAPI void APIENTRY glEndFragmentShaderATI (void); +GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); +GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); +GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); +#endif +#endif /* GL_ATI_fragment_shader */ + +#ifndef GL_ATI_map_object_buffer +#define GL_ATI_map_object_buffer 1 +typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); +#endif +#endif /* GL_ATI_map_object_buffer */ + +#ifndef GL_ATI_meminfo +#define GL_ATI_meminfo 1 +#define GL_VBO_FREE_MEMORY_ATI 0x87FB +#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC +#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD +#endif /* GL_ATI_meminfo */ + +#ifndef GL_ATI_pixel_format_float +#define GL_ATI_pixel_format_float 1 +#define GL_RGBA_FLOAT_MODE_ATI 0x8820 +#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 +#endif /* GL_ATI_pixel_format_float */ + +#ifndef GL_ATI_pn_triangles +#define GL_ATI_pn_triangles 1 +#define GL_PN_TRIANGLES_ATI 0x87F0 +#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 +#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 +#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 +#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 +#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 +#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 +#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 +#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 +typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); +GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); +#endif +#endif /* GL_ATI_pn_triangles */ + +#ifndef GL_ATI_separate_stencil +#define GL_ATI_separate_stencil 1 +#define GL_STENCIL_BACK_FUNC_ATI 0x8800 +#define GL_STENCIL_BACK_FAIL_ATI 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#endif +#endif /* GL_ATI_separate_stencil */ + +#ifndef GL_ATI_text_fragment_shader +#define GL_ATI_text_fragment_shader 1 +#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 +#endif /* GL_ATI_text_fragment_shader */ + +#ifndef GL_ATI_texture_env_combine3 +#define GL_ATI_texture_env_combine3 1 +#define GL_MODULATE_ADD_ATI 0x8744 +#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 +#define GL_MODULATE_SUBTRACT_ATI 0x8746 +#endif /* GL_ATI_texture_env_combine3 */ + +#ifndef GL_ATI_texture_float +#define GL_ATI_texture_float 1 +#define GL_RGBA_FLOAT32_ATI 0x8814 +#define GL_RGB_FLOAT32_ATI 0x8815 +#define GL_ALPHA_FLOAT32_ATI 0x8816 +#define GL_INTENSITY_FLOAT32_ATI 0x8817 +#define GL_LUMINANCE_FLOAT32_ATI 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 +#define GL_RGBA_FLOAT16_ATI 0x881A +#define GL_RGB_FLOAT16_ATI 0x881B +#define GL_ALPHA_FLOAT16_ATI 0x881C +#define GL_INTENSITY_FLOAT16_ATI 0x881D +#define GL_LUMINANCE_FLOAT16_ATI 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F +#endif /* GL_ATI_texture_float */ + +#ifndef GL_ATI_texture_mirror_once +#define GL_ATI_texture_mirror_once 1 +#define GL_MIRROR_CLAMP_ATI 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 +#endif /* GL_ATI_texture_mirror_once */ + +#ifndef GL_ATI_vertex_array_object +#define GL_ATI_vertex_array_object 1 +#define GL_STATIC_ATI 0x8760 +#define GL_DYNAMIC_ATI 0x8761 +#define GL_PRESERVE_ATI 0x8762 +#define GL_DISCARD_ATI 0x8763 +#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 +#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 +#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 +#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 +typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage); +typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage); +GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); +GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); +GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); +#endif +#endif /* GL_ATI_vertex_array_object */ + +#ifndef GL_ATI_vertex_attrib_array_object +#define GL_ATI_vertex_attrib_array_object 1 +typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_ATI_vertex_attrib_array_object */ + +#ifndef GL_ATI_vertex_streams +#define GL_ATI_vertex_streams 1 +#define GL_MAX_VERTEX_STREAMS_ATI 0x876B +#define GL_VERTEX_STREAM0_ATI 0x876C +#define GL_VERTEX_STREAM1_ATI 0x876D +#define GL_VERTEX_STREAM2_ATI 0x876E +#define GL_VERTEX_STREAM3_ATI 0x876F +#define GL_VERTEX_STREAM4_ATI 0x8770 +#define GL_VERTEX_STREAM5_ATI 0x8771 +#define GL_VERTEX_STREAM6_ATI 0x8772 +#define GL_VERTEX_STREAM7_ATI 0x8773 +#define GL_VERTEX_SOURCE_ATI 0x8774 +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); +GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); +GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); +GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); +GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); +GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); +GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); +GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); +GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); +GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); +#endif +#endif /* GL_ATI_vertex_streams */ + +#ifndef GL_EXT_422_pixels +#define GL_EXT_422_pixels 1 +#define GL_422_EXT 0x80CC +#define GL_422_REV_EXT 0x80CD +#define GL_422_AVERAGE_EXT 0x80CE +#define GL_422_REV_AVERAGE_EXT 0x80CF +#endif /* GL_EXT_422_pixels */ + +#ifndef GL_EXT_abgr +#define GL_EXT_abgr 1 +#define GL_ABGR_EXT 0x8000 +#endif /* GL_EXT_abgr */ + +#ifndef GL_EXT_bgra +#define GL_EXT_bgra 1 +#define GL_BGR_EXT 0x80E0 +#define GL_BGRA_EXT 0x80E1 +#endif /* GL_EXT_bgra */ + +#ifndef GL_EXT_bindable_uniform +#define GL_EXT_bindable_uniform 1 +#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 +#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 +#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 +#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED +#define GL_UNIFORM_BUFFER_EXT 0x8DEE +#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF +typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); +typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); +typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); +GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); +GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); +#endif +#endif /* GL_EXT_bindable_uniform */ + +#ifndef GL_EXT_blend_color +#define GL_EXT_blend_color 1 +#define GL_CONSTANT_COLOR_EXT 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define GL_CONSTANT_ALPHA_EXT 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define GL_BLEND_COLOR_EXT 0x8005 +typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +#endif +#endif /* GL_EXT_blend_color */ + +#ifndef GL_EXT_blend_equation_separate +#define GL_EXT_blend_equation_separate 1 +#define GL_BLEND_EQUATION_RGB_EXT 0x8009 +#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); +#endif +#endif /* GL_EXT_blend_equation_separate */ + +#ifndef GL_EXT_blend_func_separate +#define GL_EXT_blend_func_separate 1 +#define GL_BLEND_DST_RGB_EXT 0x80C8 +#define GL_BLEND_SRC_RGB_EXT 0x80C9 +#define GL_BLEND_DST_ALPHA_EXT 0x80CA +#define GL_BLEND_SRC_ALPHA_EXT 0x80CB +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif +#endif /* GL_EXT_blend_func_separate */ + +#ifndef GL_EXT_blend_logic_op +#define GL_EXT_blend_logic_op 1 +#endif /* GL_EXT_blend_logic_op */ + +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 +#define GL_FUNC_ADD_EXT 0x8006 +#define GL_BLEND_EQUATION_EXT 0x8009 +typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); +#endif +#endif /* GL_EXT_blend_minmax */ + +#ifndef GL_EXT_blend_subtract +#define GL_EXT_blend_subtract 1 +#define GL_FUNC_SUBTRACT_EXT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B +#endif /* GL_EXT_blend_subtract */ + +#ifndef GL_EXT_clip_volume_hint +#define GL_EXT_clip_volume_hint 1 +#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 +#endif /* GL_EXT_clip_volume_hint */ + +#ifndef GL_EXT_cmyka +#define GL_EXT_cmyka 1 +#define GL_CMYK_EXT 0x800C +#define GL_CMYKA_EXT 0x800D +#define GL_PACK_CMYK_HINT_EXT 0x800E +#define GL_UNPACK_CMYK_HINT_EXT 0x800F +#endif /* GL_EXT_cmyka */ + +#ifndef GL_EXT_color_subtable +#define GL_EXT_color_subtable 1 +typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#endif +#endif /* GL_EXT_color_subtable */ + +#ifndef GL_EXT_compiled_vertex_array +#define GL_EXT_compiled_vertex_array 1 +#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 +#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 +typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); +GLAPI void APIENTRY glUnlockArraysEXT (void); +#endif +#endif /* GL_EXT_compiled_vertex_array */ + +#ifndef GL_EXT_convolution +#define GL_EXT_convolution 1 +#define GL_CONVOLUTION_1D_EXT 0x8010 +#define GL_CONVOLUTION_2D_EXT 0x8011 +#define GL_SEPARABLE_2D_EXT 0x8012 +#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 +#define GL_REDUCE_EXT 0x8016 +#define GL_CONVOLUTION_FORMAT_EXT 0x8017 +#define GL_CONVOLUTION_WIDTH_EXT 0x8018 +#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); +GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); +GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image); +GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +#endif +#endif /* GL_EXT_convolution */ + +#ifndef GL_EXT_coordinate_frame +#define GL_EXT_coordinate_frame 1 +#define GL_TANGENT_ARRAY_EXT 0x8439 +#define GL_BINORMAL_ARRAY_EXT 0x843A +#define GL_CURRENT_TANGENT_EXT 0x843B +#define GL_CURRENT_BINORMAL_EXT 0x843C +#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E +#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F +#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 +#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 +#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 +#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 +#define GL_MAP1_TANGENT_EXT 0x8444 +#define GL_MAP2_TANGENT_EXT 0x8445 +#define GL_MAP1_BINORMAL_EXT 0x8446 +#define GL_MAP2_BINORMAL_EXT 0x8447 +typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); +typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); +typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); +typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); +typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); +typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); +typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); +typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); +typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); +typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); +typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); +GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); +GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); +GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); +GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); +GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); +GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); +GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); +GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); +GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); +GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); +GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); +GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); +GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); +GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_coordinate_frame */ + +#ifndef GL_EXT_copy_texture +#define GL_EXT_copy_texture 1 +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_EXT_copy_texture */ + +#ifndef GL_EXT_cull_vertex +#define GL_EXT_cull_vertex 1 +#define GL_CULL_VERTEX_EXT 0x81AA +#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB +#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC +typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); +GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_cull_vertex */ + +#ifndef GL_EXT_debug_label +#define GL_EXT_debug_label 1 +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_EXT_debug_label */ + +#ifndef GL_EXT_debug_marker +#define GL_EXT_debug_marker 1 +typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); +GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); +GLAPI void APIENTRY glPopGroupMarkerEXT (void); +#endif +#endif /* GL_EXT_debug_marker */ + +#ifndef GL_EXT_depth_bounds_test +#define GL_EXT_depth_bounds_test 1 +#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 +#define GL_DEPTH_BOUNDS_EXT 0x8891 +typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); +#endif +#endif /* GL_EXT_depth_bounds_test */ + +#ifndef GL_EXT_direct_state_access +#define GL_EXT_direct_state_access 1 +#define GL_PROGRAM_MATRIX_EXT 0x8E2D +#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E +#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F +typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); +typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data); +typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); +typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); +typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); +GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); +GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); +GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); +GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); +GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); +GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); +GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data); +GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); +GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); +GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img); +GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img); +GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); +GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); +GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params); +GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); +GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); +GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params); +GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); +GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string); +GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); +GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); +GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array); +GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); +GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param); +GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param); +GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); +GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor); +#endif +#endif /* GL_EXT_direct_state_access */ + +#ifndef GL_EXT_draw_buffers2 +#define GL_EXT_draw_buffers2 1 +typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +#endif +#endif /* GL_EXT_draw_buffers2 */ + +#ifndef GL_EXT_draw_instanced +#define GL_EXT_draw_instanced 1 +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#endif +#endif /* GL_EXT_draw_instanced */ + +#ifndef GL_EXT_draw_range_elements +#define GL_EXT_draw_range_elements 1 +#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 +#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +#endif +#endif /* GL_EXT_draw_range_elements */ + +#ifndef GL_EXT_fog_coord +#define GL_EXT_fog_coord 1 +#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 +#define GL_FOG_COORDINATE_EXT 0x8451 +#define GL_FRAGMENT_DEPTH_EXT 0x8452 +#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 +#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 +typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); +GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); +GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); +GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); +GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_fog_coord */ + +#ifndef GL_EXT_framebuffer_blit +#define GL_EXT_framebuffer_blit 1 +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* GL_EXT_framebuffer_blit */ + +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +#endif /* GL_EXT_framebuffer_multisample */ + +#ifndef GL_EXT_framebuffer_multisample_blit_scaled +#define GL_EXT_framebuffer_multisample_blit_scaled 1 +#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA +#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB +#endif /* GL_EXT_framebuffer_multisample_blit_scaled */ + +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); +#endif +#endif /* GL_EXT_framebuffer_object */ + +#ifndef GL_EXT_framebuffer_sRGB +#define GL_EXT_framebuffer_sRGB 1 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#endif /* GL_EXT_framebuffer_sRGB */ + +#ifndef GL_EXT_geometry_shader4 +#define GL_EXT_geometry_shader4 1 +#define GL_GEOMETRY_SHADER_EXT 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE +#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +#define GL_LINES_ADJACENCY_EXT 0x000A +#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); +#endif +#endif /* GL_EXT_geometry_shader4 */ + +#ifndef GL_EXT_gpu_program_parameters +#define GL_EXT_gpu_program_parameters 1 +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#endif +#endif /* GL_EXT_gpu_program_parameters */ + +#ifndef GL_EXT_gpu_shader4 +#define GL_EXT_gpu_shader4 1 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define GL_INT_SAMPLER_2D_EXT 0x8DCA +#define GL_INT_SAMPLER_3D_EXT 0x8DCB +#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 +typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); +#endif +#endif /* GL_EXT_gpu_shader4 */ + +#ifndef GL_EXT_histogram +#define GL_EXT_histogram 1 +#define GL_HISTOGRAM_EXT 0x8024 +#define GL_PROXY_HISTOGRAM_EXT 0x8025 +#define GL_HISTOGRAM_WIDTH_EXT 0x8026 +#define GL_HISTOGRAM_FORMAT_EXT 0x8027 +#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C +#define GL_HISTOGRAM_SINK_EXT 0x802D +#define GL_MINMAX_EXT 0x802E +#define GL_MINMAX_FORMAT_EXT 0x802F +#define GL_MINMAX_SINK_EXT 0x8030 +#define GL_TABLE_TOO_LARGE_EXT 0x8031 +typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glResetHistogramEXT (GLenum target); +GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); +#endif +#endif /* GL_EXT_histogram */ + +#ifndef GL_EXT_index_array_formats +#define GL_EXT_index_array_formats 1 +#define GL_IUI_V2F_EXT 0x81AD +#define GL_IUI_V3F_EXT 0x81AE +#define GL_IUI_N3F_V2F_EXT 0x81AF +#define GL_IUI_N3F_V3F_EXT 0x81B0 +#define GL_T2F_IUI_V2F_EXT 0x81B1 +#define GL_T2F_IUI_V3F_EXT 0x81B2 +#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 +#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 +#endif /* GL_EXT_index_array_formats */ + +#ifndef GL_EXT_index_func +#define GL_EXT_index_func 1 +#define GL_INDEX_TEST_EXT 0x81B5 +#define GL_INDEX_TEST_FUNC_EXT 0x81B6 +#define GL_INDEX_TEST_REF_EXT 0x81B7 +typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); +#endif +#endif /* GL_EXT_index_func */ + +#ifndef GL_EXT_index_material +#define GL_EXT_index_material 1 +#define GL_INDEX_MATERIAL_EXT 0x81B8 +#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 +#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA +typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); +#endif +#endif /* GL_EXT_index_material */ + +#ifndef GL_EXT_index_texture +#define GL_EXT_index_texture 1 +#endif /* GL_EXT_index_texture */ + +#ifndef GL_EXT_light_texture +#define GL_EXT_light_texture 1 +#define GL_FRAGMENT_MATERIAL_EXT 0x8349 +#define GL_FRAGMENT_NORMAL_EXT 0x834A +#define GL_FRAGMENT_COLOR_EXT 0x834C +#define GL_ATTENUATION_EXT 0x834D +#define GL_SHADOW_ATTENUATION_EXT 0x834E +#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F +#define GL_TEXTURE_LIGHT_EXT 0x8350 +#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 +#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 +typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); +GLAPI void APIENTRY glTextureLightEXT (GLenum pname); +GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); +#endif +#endif /* GL_EXT_light_texture */ + +#ifndef GL_EXT_misc_attribute +#define GL_EXT_misc_attribute 1 +#endif /* GL_EXT_misc_attribute */ + +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); +#endif +#endif /* GL_EXT_multi_draw_arrays */ + +#ifndef GL_EXT_multisample +#define GL_EXT_multisample 1 +#define GL_MULTISAMPLE_EXT 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define GL_SAMPLE_MASK_EXT 0x80A0 +#define GL_1PASS_EXT 0x80A1 +#define GL_2PASS_0_EXT 0x80A2 +#define GL_2PASS_1_EXT 0x80A3 +#define GL_4PASS_0_EXT 0x80A4 +#define GL_4PASS_1_EXT 0x80A5 +#define GL_4PASS_2_EXT 0x80A6 +#define GL_4PASS_3_EXT 0x80A7 +#define GL_SAMPLE_BUFFERS_EXT 0x80A8 +#define GL_SAMPLES_EXT 0x80A9 +#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA +#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB +#define GL_SAMPLE_PATTERN_EXT 0x80AC +#define GL_MULTISAMPLE_BIT_EXT 0x20000000 +typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); +#endif +#endif /* GL_EXT_multisample */ + +#ifndef GL_EXT_packed_depth_stencil +#define GL_EXT_packed_depth_stencil 1 +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif /* GL_EXT_packed_depth_stencil */ + +#ifndef GL_EXT_packed_float +#define GL_EXT_packed_float 1 +#define GL_R11F_G11F_B10F_EXT 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B +#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C +#endif /* GL_EXT_packed_float */ + +#ifndef GL_EXT_packed_pixels +#define GL_EXT_packed_pixels 1 +#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 +#endif /* GL_EXT_packed_pixels */ + +#ifndef GL_EXT_paletted_texture +#define GL_EXT_paletted_texture 1 +#define GL_COLOR_INDEX1_EXT 0x80E2 +#define GL_COLOR_INDEX2_EXT 0x80E3 +#define GL_COLOR_INDEX4_EXT 0x80E4 +#define GL_COLOR_INDEX8_EXT 0x80E5 +#define GL_COLOR_INDEX12_EXT 0x80E6 +#define GL_COLOR_INDEX16_EXT 0x80E7 +#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED +typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data); +GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_paletted_texture */ + +#ifndef GL_EXT_pixel_buffer_object +#define GL_EXT_pixel_buffer_object 1 +#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF +#endif /* GL_EXT_pixel_buffer_object */ + +#ifndef GL_EXT_pixel_transform +#define GL_EXT_pixel_transform 1 +#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 +#define GL_PIXEL_MAG_FILTER_EXT 0x8331 +#define GL_PIXEL_MIN_FILTER_EXT 0x8332 +#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 +#define GL_CUBIC_EXT 0x8334 +#define GL_AVERAGE_EXT 0x8335 +#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 +#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 +#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_pixel_transform */ + +#ifndef GL_EXT_pixel_transform_color_table +#define GL_EXT_pixel_transform_color_table 1 +#endif /* GL_EXT_pixel_transform_color_table */ + +#ifndef GL_EXT_point_parameters +#define GL_EXT_point_parameters 1 +#define GL_POINT_SIZE_MIN_EXT 0x8126 +#define GL_POINT_SIZE_MAX_EXT 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define GL_DISTANCE_ATTENUATION_EXT 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_EXT_point_parameters */ + +#ifndef GL_EXT_polygon_offset +#define GL_EXT_polygon_offset 1 +#define GL_POLYGON_OFFSET_EXT 0x8037 +#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 +#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 +typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); +#endif +#endif /* GL_EXT_polygon_offset */ + +#ifndef GL_EXT_provoking_vertex +#define GL_EXT_provoking_vertex 1 +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D +#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E +#define GL_PROVOKING_VERTEX_EXT 0x8E4F +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); +#endif +#endif /* GL_EXT_provoking_vertex */ + +#ifndef GL_EXT_rescale_normal +#define GL_EXT_rescale_normal 1 +#define GL_RESCALE_NORMAL_EXT 0x803A +#endif /* GL_EXT_rescale_normal */ + +#ifndef GL_EXT_secondary_color +#define GL_EXT_secondary_color 1 +#define GL_COLOR_SUM_EXT 0x8458 +#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D +#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); +GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); +GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); +GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); +GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); +GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); +GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); +GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); +GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); +GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); +GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); +GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); +GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); +GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_secondary_color */ + +#ifndef GL_EXT_separate_shader_objects +#define GL_EXT_separate_shader_objects 1 +#define GL_ACTIVE_PROGRAM_EXT 0x8B8D +typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); +typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); +GLAPI void APIENTRY glActiveProgramEXT (GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); +#endif +#endif /* GL_EXT_separate_shader_objects */ + +#ifndef GL_EXT_separate_specular_color +#define GL_EXT_separate_specular_color 1 +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif /* GL_EXT_separate_specular_color */ + +#ifndef GL_EXT_shader_image_load_formatted +#define GL_EXT_shader_image_load_formatted 1 +#endif /* GL_EXT_shader_image_load_formatted */ + +#ifndef GL_EXT_shader_image_load_store +#define GL_EXT_shader_image_load_store 1 +#define GL_MAX_IMAGE_UNITS_EXT 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 +#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A +#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B +#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C +#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D +#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E +#define GL_IMAGE_1D_EXT 0x904C +#define GL_IMAGE_2D_EXT 0x904D +#define GL_IMAGE_3D_EXT 0x904E +#define GL_IMAGE_2D_RECT_EXT 0x904F +#define GL_IMAGE_CUBE_EXT 0x9050 +#define GL_IMAGE_BUFFER_EXT 0x9051 +#define GL_IMAGE_1D_ARRAY_EXT 0x9052 +#define GL_IMAGE_2D_ARRAY_EXT 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 +#define GL_INT_IMAGE_1D_EXT 0x9057 +#define GL_INT_IMAGE_2D_EXT 0x9058 +#define GL_INT_IMAGE_3D_EXT 0x9059 +#define GL_INT_IMAGE_2D_RECT_EXT 0x905A +#define GL_INT_IMAGE_CUBE_EXT 0x905B +#define GL_INT_IMAGE_BUFFER_EXT 0x905C +#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D +#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C +#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D +#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 +#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 +#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); +typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); +GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); +#endif +#endif /* GL_EXT_shader_image_load_store */ + +#ifndef GL_EXT_shader_integer_mix +#define GL_EXT_shader_integer_mix 1 +#endif /* GL_EXT_shader_integer_mix */ + +#ifndef GL_EXT_shadow_funcs +#define GL_EXT_shadow_funcs 1 +#endif /* GL_EXT_shadow_funcs */ + +#ifndef GL_EXT_shared_texture_palette +#define GL_EXT_shared_texture_palette 1 +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif /* GL_EXT_shared_texture_palette */ + +#ifndef GL_EXT_stencil_clear_tag +#define GL_EXT_stencil_clear_tag 1 +#define GL_STENCIL_TAG_BITS_EXT 0x88F2 +#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 +typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); +#endif +#endif /* GL_EXT_stencil_clear_tag */ + +#ifndef GL_EXT_stencil_two_side +#define GL_EXT_stencil_two_side 1 +#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 +#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 +typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); +#endif +#endif /* GL_EXT_stencil_two_side */ + +#ifndef GL_EXT_stencil_wrap +#define GL_EXT_stencil_wrap 1 +#define GL_INCR_WRAP_EXT 0x8507 +#define GL_DECR_WRAP_EXT 0x8508 +#endif /* GL_EXT_stencil_wrap */ + +#ifndef GL_EXT_subtexture +#define GL_EXT_subtexture 1 +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +#endif +#endif /* GL_EXT_subtexture */ + +#ifndef GL_EXT_texture +#define GL_EXT_texture 1 +#define GL_ALPHA4_EXT 0x803B +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA12_EXT 0x803D +#define GL_ALPHA16_EXT 0x803E +#define GL_LUMINANCE4_EXT 0x803F +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE12_EXT 0x8041 +#define GL_LUMINANCE16_EXT 0x8042 +#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 +#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 +#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 +#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 +#define GL_INTENSITY_EXT 0x8049 +#define GL_INTENSITY4_EXT 0x804A +#define GL_INTENSITY8_EXT 0x804B +#define GL_INTENSITY12_EXT 0x804C +#define GL_INTENSITY16_EXT 0x804D +#define GL_RGB2_EXT 0x804E +#define GL_RGB4_EXT 0x804F +#define GL_RGB5_EXT 0x8050 +#define GL_RGB8_EXT 0x8051 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB12_EXT 0x8053 +#define GL_RGB16_EXT 0x8054 +#define GL_RGBA2_EXT 0x8055 +#define GL_RGBA4_EXT 0x8056 +#define GL_RGB5_A1_EXT 0x8057 +#define GL_RGBA8_EXT 0x8058 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGBA12_EXT 0x805A +#define GL_RGBA16_EXT 0x805B +#define GL_TEXTURE_RED_SIZE_EXT 0x805C +#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D +#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E +#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 +#define GL_REPLACE_EXT 0x8062 +#define GL_PROXY_TEXTURE_1D_EXT 0x8063 +#define GL_PROXY_TEXTURE_2D_EXT 0x8064 +#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 +#endif /* GL_EXT_texture */ + +#ifndef GL_EXT_texture3D +#define GL_EXT_texture3D 1 +#define GL_PACK_SKIP_IMAGES_EXT 0x806B +#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C +#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D +#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E +#define GL_TEXTURE_3D_EXT 0x806F +#define GL_PROXY_TEXTURE_3D_EXT 0x8070 +#define GL_TEXTURE_DEPTH_EXT 0x8071 +#define GL_TEXTURE_WRAP_R_EXT 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 +typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +#endif +#endif /* GL_EXT_texture3D */ + +#ifndef GL_EXT_texture_array +#define GL_EXT_texture_array 1 +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +#endif /* GL_EXT_texture_array */ + +#ifndef GL_EXT_texture_buffer_object +#define GL_EXT_texture_buffer_object 1 +#define GL_TEXTURE_BUFFER_EXT 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E +typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); +#endif +#endif /* GL_EXT_texture_buffer_object */ + +#ifndef GL_EXT_texture_compression_latc +#define GL_EXT_texture_compression_latc 1 +#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 +#endif /* GL_EXT_texture_compression_latc */ + +#ifndef GL_EXT_texture_compression_rgtc +#define GL_EXT_texture_compression_rgtc 1 +#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#endif /* GL_EXT_texture_compression_rgtc */ + +#ifndef GL_EXT_texture_compression_s3tc +#define GL_EXT_texture_compression_s3tc 1 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif /* GL_EXT_texture_compression_s3tc */ + +#ifndef GL_EXT_texture_cube_map +#define GL_EXT_texture_cube_map 1 +#define GL_NORMAL_MAP_EXT 0x8511 +#define GL_REFLECTION_MAP_EXT 0x8512 +#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#endif /* GL_EXT_texture_cube_map */ + +#ifndef GL_EXT_texture_env_add +#define GL_EXT_texture_env_add 1 +#endif /* GL_EXT_texture_env_add */ + +#ifndef GL_EXT_texture_env_combine +#define GL_EXT_texture_env_combine 1 +#define GL_COMBINE_EXT 0x8570 +#define GL_COMBINE_RGB_EXT 0x8571 +#define GL_COMBINE_ALPHA_EXT 0x8572 +#define GL_RGB_SCALE_EXT 0x8573 +#define GL_ADD_SIGNED_EXT 0x8574 +#define GL_INTERPOLATE_EXT 0x8575 +#define GL_CONSTANT_EXT 0x8576 +#define GL_PRIMARY_COLOR_EXT 0x8577 +#define GL_PREVIOUS_EXT 0x8578 +#define GL_SOURCE0_RGB_EXT 0x8580 +#define GL_SOURCE1_RGB_EXT 0x8581 +#define GL_SOURCE2_RGB_EXT 0x8582 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +#define GL_SOURCE2_ALPHA_EXT 0x858A +#define GL_OPERAND0_RGB_EXT 0x8590 +#define GL_OPERAND1_RGB_EXT 0x8591 +#define GL_OPERAND2_RGB_EXT 0x8592 +#define GL_OPERAND0_ALPHA_EXT 0x8598 +#define GL_OPERAND1_ALPHA_EXT 0x8599 +#define GL_OPERAND2_ALPHA_EXT 0x859A +#endif /* GL_EXT_texture_env_combine */ + +#ifndef GL_EXT_texture_env_dot3 +#define GL_EXT_texture_env_dot3 1 +#define GL_DOT3_RGB_EXT 0x8740 +#define GL_DOT3_RGBA_EXT 0x8741 +#endif /* GL_EXT_texture_env_dot3 */ + +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif /* GL_EXT_texture_filter_anisotropic */ + +#ifndef GL_EXT_texture_integer +#define GL_EXT_texture_integer 1 +#define GL_RGBA32UI_EXT 0x8D70 +#define GL_RGB32UI_EXT 0x8D71 +#define GL_ALPHA32UI_EXT 0x8D72 +#define GL_INTENSITY32UI_EXT 0x8D73 +#define GL_LUMINANCE32UI_EXT 0x8D74 +#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 +#define GL_RGBA16UI_EXT 0x8D76 +#define GL_RGB16UI_EXT 0x8D77 +#define GL_ALPHA16UI_EXT 0x8D78 +#define GL_INTENSITY16UI_EXT 0x8D79 +#define GL_LUMINANCE16UI_EXT 0x8D7A +#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B +#define GL_RGBA8UI_EXT 0x8D7C +#define GL_RGB8UI_EXT 0x8D7D +#define GL_ALPHA8UI_EXT 0x8D7E +#define GL_INTENSITY8UI_EXT 0x8D7F +#define GL_LUMINANCE8UI_EXT 0x8D80 +#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 +#define GL_RGBA32I_EXT 0x8D82 +#define GL_RGB32I_EXT 0x8D83 +#define GL_ALPHA32I_EXT 0x8D84 +#define GL_INTENSITY32I_EXT 0x8D85 +#define GL_LUMINANCE32I_EXT 0x8D86 +#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 +#define GL_RGBA16I_EXT 0x8D88 +#define GL_RGB16I_EXT 0x8D89 +#define GL_ALPHA16I_EXT 0x8D8A +#define GL_INTENSITY16I_EXT 0x8D8B +#define GL_LUMINANCE16I_EXT 0x8D8C +#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D +#define GL_RGBA8I_EXT 0x8D8E +#define GL_RGB8I_EXT 0x8D8F +#define GL_ALPHA8I_EXT 0x8D90 +#define GL_INTENSITY8I_EXT 0x8D91 +#define GL_LUMINANCE8I_EXT 0x8D92 +#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 +#define GL_RED_INTEGER_EXT 0x8D94 +#define GL_GREEN_INTEGER_EXT 0x8D95 +#define GL_BLUE_INTEGER_EXT 0x8D96 +#define GL_ALPHA_INTEGER_EXT 0x8D97 +#define GL_RGB_INTEGER_EXT 0x8D98 +#define GL_RGBA_INTEGER_EXT 0x8D99 +#define GL_BGR_INTEGER_EXT 0x8D9A +#define GL_BGRA_INTEGER_EXT 0x8D9B +#define GL_LUMINANCE_INTEGER_EXT 0x8D9C +#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D +#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); +typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); +GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#endif +#endif /* GL_EXT_texture_integer */ + +#ifndef GL_EXT_texture_lod_bias +#define GL_EXT_texture_lod_bias 1 +#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD +#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 +#endif /* GL_EXT_texture_lod_bias */ + +#ifndef GL_EXT_texture_mirror_clamp +#define GL_EXT_texture_mirror_clamp 1 +#define GL_MIRROR_CLAMP_EXT 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 +#endif /* GL_EXT_texture_mirror_clamp */ + +#ifndef GL_EXT_texture_object +#define GL_EXT_texture_object 1 +#define GL_TEXTURE_PRIORITY_EXT 0x8066 +#define GL_TEXTURE_RESIDENT_EXT 0x8067 +#define GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define GL_TEXTURE_2D_BINDING_EXT 0x8069 +#define GL_TEXTURE_3D_BINDING_EXT 0x806A +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); +GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); +GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); +GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); +GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); +GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#endif +#endif /* GL_EXT_texture_object */ + +#ifndef GL_EXT_texture_perturb_normal +#define GL_EXT_texture_perturb_normal 1 +#define GL_PERTURB_EXT 0x85AE +#define GL_TEXTURE_NORMAL_EXT 0x85AF +typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); +#endif +#endif /* GL_EXT_texture_perturb_normal */ + +#ifndef GL_EXT_texture_sRGB +#define GL_EXT_texture_sRGB 1 +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif /* GL_EXT_texture_sRGB */ + +#ifndef GL_EXT_texture_sRGB_decode +#define GL_EXT_texture_sRGB_decode 1 +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define GL_DECODE_EXT 0x8A49 +#define GL_SKIP_DECODE_EXT 0x8A4A +#endif /* GL_EXT_texture_sRGB_decode */ + +#ifndef GL_EXT_texture_shared_exponent +#define GL_EXT_texture_shared_exponent 1 +#define GL_RGB9_E5_EXT 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E +#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F +#endif /* GL_EXT_texture_shared_exponent */ + +#ifndef GL_EXT_texture_snorm +#define GL_EXT_texture_snorm 1 +#define GL_ALPHA_SNORM 0x9010 +#define GL_LUMINANCE_SNORM 0x9011 +#define GL_LUMINANCE_ALPHA_SNORM 0x9012 +#define GL_INTENSITY_SNORM 0x9013 +#define GL_ALPHA8_SNORM 0x9014 +#define GL_LUMINANCE8_SNORM 0x9015 +#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 +#define GL_INTENSITY8_SNORM 0x9017 +#define GL_ALPHA16_SNORM 0x9018 +#define GL_LUMINANCE16_SNORM 0x9019 +#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A +#define GL_INTENSITY16_SNORM 0x901B +#define GL_RED_SNORM 0x8F90 +#define GL_RG_SNORM 0x8F91 +#define GL_RGB_SNORM 0x8F92 +#define GL_RGBA_SNORM 0x8F93 +#endif /* GL_EXT_texture_snorm */ + +#ifndef GL_EXT_texture_swizzle +#define GL_EXT_texture_swizzle 1 +#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 +#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 +#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 +#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 +#endif /* GL_EXT_texture_swizzle */ + +#ifndef GL_EXT_timer_query +#define GL_EXT_timer_query 1 +#define GL_TIME_ELAPSED_EXT 0x88BF +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params); +#endif +#endif /* GL_EXT_timer_query */ + +#ifndef GL_EXT_transform_feedback +#define GL_EXT_transform_feedback 1 +#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F +#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C +#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D +#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 +#define GL_RASTERIZER_DISCARD_EXT 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedbackEXT (void); +GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +#endif +#endif /* GL_EXT_transform_feedback */ + +#ifndef GL_EXT_vertex_array +#define GL_EXT_vertex_array 1 +#define GL_VERTEX_ARRAY_EXT 0x8074 +#define GL_NORMAL_ARRAY_EXT 0x8075 +#define GL_COLOR_ARRAY_EXT 0x8076 +#define GL_INDEX_ARRAY_EXT 0x8077 +#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 +typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); +typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); +typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params); +typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glArrayElementEXT (GLint i); +GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); +GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params); +GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +#endif +#endif /* GL_EXT_vertex_array */ + +#ifndef GL_EXT_vertex_array_bgra +#define GL_EXT_vertex_array_bgra 1 +#endif /* GL_EXT_vertex_array_bgra */ + +#ifndef GL_EXT_vertex_attrib_64bit +#define GL_EXT_vertex_attrib_64bit 1 +#define GL_DOUBLE_VEC2_EXT 0x8FFC +#define GL_DOUBLE_VEC3_EXT 0x8FFD +#define GL_DOUBLE_VEC4_EXT 0x8FFE +#define GL_DOUBLE_MAT2_EXT 0x8F46 +#define GL_DOUBLE_MAT3_EXT 0x8F47 +#define GL_DOUBLE_MAT4_EXT 0x8F48 +#define GL_DOUBLE_MAT2x3_EXT 0x8F49 +#define GL_DOUBLE_MAT2x4_EXT 0x8F4A +#define GL_DOUBLE_MAT3x2_EXT 0x8F4B +#define GL_DOUBLE_MAT3x4_EXT 0x8F4C +#define GL_DOUBLE_MAT4x2_EXT 0x8F4D +#define GL_DOUBLE_MAT4x3_EXT 0x8F4E +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); +#endif +#endif /* GL_EXT_vertex_attrib_64bit */ + +#ifndef GL_EXT_vertex_shader +#define GL_EXT_vertex_shader 1 +#define GL_VERTEX_SHADER_EXT 0x8780 +#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 +#define GL_OP_INDEX_EXT 0x8782 +#define GL_OP_NEGATE_EXT 0x8783 +#define GL_OP_DOT3_EXT 0x8784 +#define GL_OP_DOT4_EXT 0x8785 +#define GL_OP_MUL_EXT 0x8786 +#define GL_OP_ADD_EXT 0x8787 +#define GL_OP_MADD_EXT 0x8788 +#define GL_OP_FRAC_EXT 0x8789 +#define GL_OP_MAX_EXT 0x878A +#define GL_OP_MIN_EXT 0x878B +#define GL_OP_SET_GE_EXT 0x878C +#define GL_OP_SET_LT_EXT 0x878D +#define GL_OP_CLAMP_EXT 0x878E +#define GL_OP_FLOOR_EXT 0x878F +#define GL_OP_ROUND_EXT 0x8790 +#define GL_OP_EXP_BASE_2_EXT 0x8791 +#define GL_OP_LOG_BASE_2_EXT 0x8792 +#define GL_OP_POWER_EXT 0x8793 +#define GL_OP_RECIP_EXT 0x8794 +#define GL_OP_RECIP_SQRT_EXT 0x8795 +#define GL_OP_SUB_EXT 0x8796 +#define GL_OP_CROSS_PRODUCT_EXT 0x8797 +#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 +#define GL_OP_MOV_EXT 0x8799 +#define GL_OUTPUT_VERTEX_EXT 0x879A +#define GL_OUTPUT_COLOR0_EXT 0x879B +#define GL_OUTPUT_COLOR1_EXT 0x879C +#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D +#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E +#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F +#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 +#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 +#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 +#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 +#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 +#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 +#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 +#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 +#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 +#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 +#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA +#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB +#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC +#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD +#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE +#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF +#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 +#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 +#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 +#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 +#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 +#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 +#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 +#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 +#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 +#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 +#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA +#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB +#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC +#define GL_OUTPUT_FOG_EXT 0x87BD +#define GL_SCALAR_EXT 0x87BE +#define GL_VECTOR_EXT 0x87BF +#define GL_MATRIX_EXT 0x87C0 +#define GL_VARIANT_EXT 0x87C1 +#define GL_INVARIANT_EXT 0x87C2 +#define GL_LOCAL_CONSTANT_EXT 0x87C3 +#define GL_LOCAL_EXT 0x87C4 +#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 +#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 +#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 +#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 +#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE +#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF +#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 +#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 +#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 +#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 +#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 +#define GL_X_EXT 0x87D5 +#define GL_Y_EXT 0x87D6 +#define GL_Z_EXT 0x87D7 +#define GL_W_EXT 0x87D8 +#define GL_NEGATIVE_X_EXT 0x87D9 +#define GL_NEGATIVE_Y_EXT 0x87DA +#define GL_NEGATIVE_Z_EXT 0x87DB +#define GL_NEGATIVE_W_EXT 0x87DC +#define GL_ZERO_EXT 0x87DD +#define GL_ONE_EXT 0x87DE +#define GL_NEGATIVE_ONE_EXT 0x87DF +#define GL_NORMALIZED_RANGE_EXT 0x87E0 +#define GL_FULL_RANGE_EXT 0x87E1 +#define GL_CURRENT_VERTEX_EXT 0x87E2 +#define GL_MVP_MATRIX_EXT 0x87E3 +#define GL_VARIANT_VALUE_EXT 0x87E4 +#define GL_VARIANT_DATATYPE_EXT 0x87E5 +#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 +#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 +#define GL_VARIANT_ARRAY_EXT 0x87E8 +#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 +#define GL_INVARIANT_VALUE_EXT 0x87EA +#define GL_INVARIANT_DATATYPE_EXT 0x87EB +#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC +#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED +typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); +typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); +typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr); +typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr); +typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); +typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); +typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); +typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); +typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); +typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); +typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); +typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); +typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr); +typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); +typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); +typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data); +typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVertexShaderEXT (void); +GLAPI void APIENTRY glEndVertexShaderEXT (void); +GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); +GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); +GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); +GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); +GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); +GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); +GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr); +GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr); +GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); +GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); +GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); +GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); +GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); +GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); +GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); +GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); +GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr); +GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); +GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); +GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); +GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); +GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); +GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); +GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); +GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); +GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data); +GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +#endif +#endif /* GL_EXT_vertex_shader */ + +#ifndef GL_EXT_vertex_weighting +#define GL_EXT_vertex_weighting 1 +#define GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 +#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 +#define GL_MODELVIEW0_MATRIX_EXT 0x0BA6 +#define GL_MODELVIEW1_MATRIX_EXT 0x8506 +#define GL_VERTEX_WEIGHTING_EXT 0x8509 +#define GL_MODELVIEW0_EXT 0x1700 +#define GL_MODELVIEW1_EXT 0x850A +#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B +#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C +#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D +#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E +#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F +#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); +GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); +GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_vertex_weighting */ + +#ifndef GL_EXT_x11_sync_object +#define GL_EXT_x11_sync_object 1 +#define GL_SYNC_X11_FENCE_EXT 0x90E1 +typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); +#endif +#endif /* GL_EXT_x11_sync_object */ + +#ifndef GL_GREMEDY_frame_terminator +#define GL_GREMEDY_frame_terminator 1 +typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); +#endif +#endif /* GL_GREMEDY_frame_terminator */ + +#ifndef GL_GREMEDY_string_marker +#define GL_GREMEDY_string_marker 1 +typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string); +#endif +#endif /* GL_GREMEDY_string_marker */ + +#ifndef GL_HP_convolution_border_modes +#define GL_HP_convolution_border_modes 1 +#define GL_IGNORE_BORDER_HP 0x8150 +#define GL_CONSTANT_BORDER_HP 0x8151 +#define GL_REPLICATE_BORDER_HP 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 +#endif /* GL_HP_convolution_border_modes */ + +#ifndef GL_HP_image_transform +#define GL_HP_image_transform 1 +#define GL_IMAGE_SCALE_X_HP 0x8155 +#define GL_IMAGE_SCALE_Y_HP 0x8156 +#define GL_IMAGE_TRANSLATE_X_HP 0x8157 +#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 +#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 +#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A +#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B +#define GL_IMAGE_MAG_FILTER_HP 0x815C +#define GL_IMAGE_MIN_FILTER_HP 0x815D +#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E +#define GL_CUBIC_HP 0x815F +#define GL_AVERAGE_HP 0x8160 +#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 +#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 +#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_HP_image_transform */ + +#ifndef GL_HP_occlusion_test +#define GL_HP_occlusion_test 1 +#define GL_OCCLUSION_TEST_HP 0x8165 +#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 +#endif /* GL_HP_occlusion_test */ + +#ifndef GL_HP_texture_lighting +#define GL_HP_texture_lighting 1 +#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 +#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 +#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 +#endif /* GL_HP_texture_lighting */ + +#ifndef GL_IBM_cull_vertex +#define GL_IBM_cull_vertex 1 +#define GL_CULL_VERTEX_IBM 103050 +#endif /* GL_IBM_cull_vertex */ + +#ifndef GL_IBM_multimode_draw_arrays +#define GL_IBM_multimode_draw_arrays 1 +typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); +#endif +#endif /* GL_IBM_multimode_draw_arrays */ + +#ifndef GL_IBM_rasterpos_clip +#define GL_IBM_rasterpos_clip 1 +#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 +#endif /* GL_IBM_rasterpos_clip */ + +#ifndef GL_IBM_static_data +#define GL_IBM_static_data 1 +#define GL_ALL_STATIC_DATA_IBM 103060 +#define GL_STATIC_VERTEX_ARRAY_IBM 103061 +typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target); +#endif +#endif /* GL_IBM_static_data */ + +#ifndef GL_IBM_texture_mirrored_repeat +#define GL_IBM_texture_mirrored_repeat 1 +#define GL_MIRRORED_REPEAT_IBM 0x8370 +#endif /* GL_IBM_texture_mirrored_repeat */ + +#ifndef GL_IBM_vertex_array_lists +#define GL_IBM_vertex_array_lists 1 +#define GL_VERTEX_ARRAY_LIST_IBM 103070 +#define GL_NORMAL_ARRAY_LIST_IBM 103071 +#define GL_COLOR_ARRAY_LIST_IBM 103072 +#define GL_INDEX_ARRAY_LIST_IBM 103073 +#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 +#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 +#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 +#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 +#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 +#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 +#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 +#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 +#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 +#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 +#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 +#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 +typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride); +GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +#endif +#endif /* GL_IBM_vertex_array_lists */ + +#ifndef GL_INGR_blend_func_separate +#define GL_INGR_blend_func_separate 1 +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif +#endif /* GL_INGR_blend_func_separate */ + +#ifndef GL_INGR_color_clamp +#define GL_INGR_color_clamp 1 +#define GL_RED_MIN_CLAMP_INGR 0x8560 +#define GL_GREEN_MIN_CLAMP_INGR 0x8561 +#define GL_BLUE_MIN_CLAMP_INGR 0x8562 +#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 +#define GL_RED_MAX_CLAMP_INGR 0x8564 +#define GL_GREEN_MAX_CLAMP_INGR 0x8565 +#define GL_BLUE_MAX_CLAMP_INGR 0x8566 +#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 +#endif /* GL_INGR_color_clamp */ + +#ifndef GL_INGR_interlace_read +#define GL_INGR_interlace_read 1 +#define GL_INTERLACE_READ_INGR 0x8568 +#endif /* GL_INGR_interlace_read */ + +#ifndef GL_INTEL_fragment_shader_ordering +#define GL_INTEL_fragment_shader_ordering 1 +#endif /* GL_INTEL_fragment_shader_ordering */ + +#ifndef GL_INTEL_map_texture +#define GL_INTEL_map_texture 1 +#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF +#define GL_LAYOUT_DEFAULT_INTEL 0 +#define GL_LAYOUT_LINEAR_INTEL 1 +#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 +typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); +typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture); +GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level); +GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); +#endif +#endif /* GL_INTEL_map_texture */ + +#ifndef GL_INTEL_parallel_arrays +#define GL_INTEL_parallel_arrays 1 +#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 +#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 +#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 +#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 +#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 +typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer); +GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer); +GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer); +GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer); +#endif +#endif /* GL_INTEL_parallel_arrays */ + +#ifndef GL_INTEL_performance_query +#define GL_INTEL_performance_query 1 +#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 +#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 +#define GL_PERFQUERY_WAIT_INTEL 0x83FB +#define GL_PERFQUERY_FLUSH_INTEL 0x83FA +#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 +#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 +#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 +#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 +#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 +#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 +#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 +#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 +#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 +#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA +#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB +#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC +#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD +#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE +#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF +#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 +typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); +typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); +typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); +typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); +typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); +typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); +typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); +GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); +GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); +GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); +GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); +GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); +GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +#endif +#endif /* GL_INTEL_performance_query */ + +#ifndef GL_MESAX_texture_stack +#define GL_MESAX_texture_stack 1 +#define GL_TEXTURE_1D_STACK_MESAX 0x8759 +#define GL_TEXTURE_2D_STACK_MESAX 0x875A +#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B +#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C +#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D +#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E +#endif /* GL_MESAX_texture_stack */ + +#ifndef GL_MESA_pack_invert +#define GL_MESA_pack_invert 1 +#define GL_PACK_INVERT_MESA 0x8758 +#endif /* GL_MESA_pack_invert */ + +#ifndef GL_MESA_resize_buffers +#define GL_MESA_resize_buffers 1 +typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glResizeBuffersMESA (void); +#endif +#endif /* GL_MESA_resize_buffers */ + +#ifndef GL_MESA_window_pos +#define GL_MESA_window_pos 1 +typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); +GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); +GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); +#endif +#endif /* GL_MESA_window_pos */ + +#ifndef GL_MESA_ycbcr_texture +#define GL_MESA_ycbcr_texture 1 +#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB +#define GL_YCBCR_MESA 0x8757 +#endif /* GL_MESA_ycbcr_texture */ + +#ifndef GL_NVX_conditional_render +#define GL_NVX_conditional_render 1 +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id); +GLAPI void APIENTRY glEndConditionalRenderNVX (void); +#endif +#endif /* GL_NVX_conditional_render */ + +#ifndef GL_NVX_gpu_memory_info +#define GL_NVX_gpu_memory_info 1 +#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#endif /* GL_NVX_gpu_memory_info */ + +#ifndef GL_NV_bindless_multi_draw_indirect +#define GL_NV_bindless_multi_draw_indirect 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +#endif +#endif /* GL_NV_bindless_multi_draw_indirect */ + +#ifndef GL_NV_bindless_texture +#define GL_NV_bindless_texture 1 +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); +#endif +#endif /* GL_NV_bindless_texture */ + +#ifndef GL_NV_blend_equation_advanced +#define GL_NV_blend_equation_advanced 1 +#define GL_BLEND_OVERLAP_NV 0x9281 +#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_BLUE_NV 0x1905 +#define GL_COLORBURN_NV 0x929A +#define GL_COLORDODGE_NV 0x9299 +#define GL_CONJOINT_NV 0x9284 +#define GL_CONTRAST_NV 0x92A1 +#define GL_DARKEN_NV 0x9297 +#define GL_DIFFERENCE_NV 0x929E +#define GL_DISJOINT_NV 0x9283 +#define GL_DST_ATOP_NV 0x928F +#define GL_DST_IN_NV 0x928B +#define GL_DST_NV 0x9287 +#define GL_DST_OUT_NV 0x928D +#define GL_DST_OVER_NV 0x9289 +#define GL_EXCLUSION_NV 0x92A0 +#define GL_GREEN_NV 0x1904 +#define GL_HARDLIGHT_NV 0x929B +#define GL_HARDMIX_NV 0x92A9 +#define GL_HSL_COLOR_NV 0x92AF +#define GL_HSL_HUE_NV 0x92AD +#define GL_HSL_LUMINOSITY_NV 0x92B0 +#define GL_HSL_SATURATION_NV 0x92AE +#define GL_INVERT_OVG_NV 0x92B4 +#define GL_INVERT_RGB_NV 0x92A3 +#define GL_LIGHTEN_NV 0x9298 +#define GL_LINEARBURN_NV 0x92A5 +#define GL_LINEARDODGE_NV 0x92A4 +#define GL_LINEARLIGHT_NV 0x92A7 +#define GL_MINUS_CLAMPED_NV 0x92B3 +#define GL_MINUS_NV 0x929F +#define GL_MULTIPLY_NV 0x9294 +#define GL_OVERLAY_NV 0x9296 +#define GL_PINLIGHT_NV 0x92A8 +#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define GL_PLUS_CLAMPED_NV 0x92B1 +#define GL_PLUS_DARKER_NV 0x9292 +#define GL_PLUS_NV 0x9291 +#define GL_RED_NV 0x1903 +#define GL_SCREEN_NV 0x9295 +#define GL_SOFTLIGHT_NV 0x929C +#define GL_SRC_ATOP_NV 0x928E +#define GL_SRC_IN_NV 0x928A +#define GL_SRC_NV 0x9286 +#define GL_SRC_OUT_NV 0x928C +#define GL_SRC_OVER_NV 0x9288 +#define GL_UNCORRELATED_NV 0x9282 +#define GL_VIVIDLIGHT_NV 0x92A6 +#define GL_XOR_NV 0x1506 +typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value); +GLAPI void APIENTRY glBlendBarrierNV (void); +#endif +#endif /* GL_NV_blend_equation_advanced */ + +#ifndef GL_NV_blend_equation_advanced_coherent +#define GL_NV_blend_equation_advanced_coherent 1 +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#endif /* GL_NV_blend_equation_advanced_coherent */ + +#ifndef GL_NV_blend_square +#define GL_NV_blend_square 1 +#endif /* GL_NV_blend_square */ + +#ifndef GL_NV_compute_program5 +#define GL_NV_compute_program5 1 +#define GL_COMPUTE_PROGRAM_NV 0x90FB +#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC +#endif /* GL_NV_compute_program5 */ + +#ifndef GL_NV_conditional_render +#define GL_NV_conditional_render 1 +#define GL_QUERY_WAIT_NV 0x8E13 +#define GL_QUERY_NO_WAIT_NV 0x8E14 +#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRenderNV (void); +#endif +#endif /* GL_NV_conditional_render */ + +#ifndef GL_NV_copy_depth_to_color +#define GL_NV_copy_depth_to_color 1 +#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E +#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F +#endif /* GL_NV_copy_depth_to_color */ + +#ifndef GL_NV_copy_image +#define GL_NV_copy_image 1 +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* GL_NV_copy_image */ + +#ifndef GL_NV_deep_texture3D +#define GL_NV_deep_texture3D 1 +#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0 +#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1 +#endif /* GL_NV_deep_texture3D */ + +#ifndef GL_NV_depth_buffer_float +#define GL_NV_depth_buffer_float 1 +#define GL_DEPTH_COMPONENT32F_NV 0x8DAB +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD +#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF +typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); +typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); +GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); +#endif +#endif /* GL_NV_depth_buffer_float */ + +#ifndef GL_NV_depth_clamp +#define GL_NV_depth_clamp 1 +#define GL_DEPTH_CLAMP_NV 0x864F +#endif /* GL_NV_depth_clamp */ + +#ifndef GL_NV_draw_texture +#define GL_NV_draw_texture 1 +typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +#endif +#endif /* GL_NV_draw_texture */ + +#ifndef GL_NV_evaluators +#define GL_NV_evaluators 1 +#define GL_EVAL_2D_NV 0x86C0 +#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 +#define GL_MAP_TESSELLATION_NV 0x86C2 +#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 +#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 +#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 +#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 +#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 +#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 +#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 +#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA +#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB +#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC +#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD +#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE +#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF +#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 +#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 +#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 +#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 +#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 +#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 +#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 +#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 +typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); +typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); +GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); +GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); +#endif +#endif /* GL_NV_evaluators */ + +#ifndef GL_NV_explicit_multisample +#define GL_NV_explicit_multisample 1 +#define GL_SAMPLE_POSITION_NV 0x8E50 +#define GL_SAMPLE_MASK_NV 0x8E51 +#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 +#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 +#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 +#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 +#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 +#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 +#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 +#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); +GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); +#endif +#endif /* GL_NV_explicit_multisample */ + +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#define GL_ALL_COMPLETED_NV 0x84F2 +#define GL_FENCE_STATUS_NV 0x84F3 +#define GL_FENCE_CONDITION_NV 0x84F4 +typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); +GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); +GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); +GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); +GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); +GLAPI void APIENTRY glFinishFenceNV (GLuint fence); +GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); +#endif +#endif /* GL_NV_fence */ + +#ifndef GL_NV_float_buffer +#define GL_NV_float_buffer 1 +#define GL_FLOAT_R_NV 0x8880 +#define GL_FLOAT_RG_NV 0x8881 +#define GL_FLOAT_RGB_NV 0x8882 +#define GL_FLOAT_RGBA_NV 0x8883 +#define GL_FLOAT_R16_NV 0x8884 +#define GL_FLOAT_R32_NV 0x8885 +#define GL_FLOAT_RG16_NV 0x8886 +#define GL_FLOAT_RG32_NV 0x8887 +#define GL_FLOAT_RGB16_NV 0x8888 +#define GL_FLOAT_RGB32_NV 0x8889 +#define GL_FLOAT_RGBA16_NV 0x888A +#define GL_FLOAT_RGBA32_NV 0x888B +#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C +#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D +#define GL_FLOAT_RGBA_MODE_NV 0x888E +#endif /* GL_NV_float_buffer */ + +#ifndef GL_NV_fog_distance +#define GL_NV_fog_distance 1 +#define GL_FOG_DISTANCE_MODE_NV 0x855A +#define GL_EYE_RADIAL_NV 0x855B +#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C +#endif /* GL_NV_fog_distance */ + +#ifndef GL_NV_fragment_program +#define GL_NV_fragment_program 1 +#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 +#define GL_FRAGMENT_PROGRAM_NV 0x8870 +#define GL_MAX_TEXTURE_COORDS_NV 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 +#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 +#define GL_PROGRAM_ERROR_STRING_NV 0x8874 +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#endif +#endif /* GL_NV_fragment_program */ + +#ifndef GL_NV_fragment_program2 +#define GL_NV_fragment_program2 1 +#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 +#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 +#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 +#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 +#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 +#endif /* GL_NV_fragment_program2 */ + +#ifndef GL_NV_fragment_program4 +#define GL_NV_fragment_program4 1 +#endif /* GL_NV_fragment_program4 */ + +#ifndef GL_NV_fragment_program_option +#define GL_NV_fragment_program_option 1 +#endif /* GL_NV_fragment_program_option */ + +#ifndef GL_NV_framebuffer_multisample_coverage +#define GL_NV_framebuffer_multisample_coverage 1 +#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB +#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 +#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 +#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +#endif /* GL_NV_framebuffer_multisample_coverage */ + +#ifndef GL_NV_geometry_program4 +#define GL_NV_geometry_program4 1 +#define GL_GEOMETRY_PROGRAM_NV 0x8C26 +#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 +#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 +typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); +GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif +#endif /* GL_NV_geometry_program4 */ + +#ifndef GL_NV_geometry_shader4 +#define GL_NV_geometry_shader4 1 +#endif /* GL_NV_geometry_shader4 */ + +#ifndef GL_NV_gpu_program4 +#define GL_NV_gpu_program4 1 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 +#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 +#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 +#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 +#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 +#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 +#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); +GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); +#endif +#endif /* GL_NV_gpu_program4 */ + +#ifndef GL_NV_gpu_program5 +#define GL_NV_gpu_program5 1 +#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C +#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F +#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 +#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 +typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); +#endif +#endif /* GL_NV_gpu_program5 */ + +#ifndef GL_NV_gpu_program5_mem_extended +#define GL_NV_gpu_program5_mem_extended 1 +#endif /* GL_NV_gpu_program5_mem_extended */ + +#ifndef GL_NV_gpu_shader5 +#define GL_NV_gpu_shader5 1 +#endif /* GL_NV_gpu_shader5 */ + +#ifndef GL_NV_half_float +#define GL_NV_half_float 1 +typedef unsigned short GLhalfNV; +#define GL_HALF_FLOAT_NV 0x140B +typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); +typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); +typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); +GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); +GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); +GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); +GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); +GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); +GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); +GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); +GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); +GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); +GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); +GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); +GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); +GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +#endif +#endif /* GL_NV_half_float */ + +#ifndef GL_NV_light_max_exponent +#define GL_NV_light_max_exponent 1 +#define GL_MAX_SHININESS_NV 0x8504 +#define GL_MAX_SPOT_EXPONENT_NV 0x8505 +#endif /* GL_NV_light_max_exponent */ + +#ifndef GL_NV_multisample_coverage +#define GL_NV_multisample_coverage 1 +#define GL_COLOR_SAMPLES_NV 0x8E20 +#endif /* GL_NV_multisample_coverage */ + +#ifndef GL_NV_multisample_filter_hint +#define GL_NV_multisample_filter_hint 1 +#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 +#endif /* GL_NV_multisample_filter_hint */ + +#ifndef GL_NV_occlusion_query +#define GL_NV_occlusion_query 1 +#define GL_PIXEL_COUNTER_BITS_NV 0x8864 +#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 +#define GL_PIXEL_COUNT_NV 0x8866 +#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 +typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); +GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); +GLAPI void APIENTRY glEndOcclusionQueryNV (void); +GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); +#endif +#endif /* GL_NV_occlusion_query */ + +#ifndef GL_NV_packed_depth_stencil +#define GL_NV_packed_depth_stencil 1 +#define GL_DEPTH_STENCIL_NV 0x84F9 +#define GL_UNSIGNED_INT_24_8_NV 0x84FA +#endif /* GL_NV_packed_depth_stencil */ + +#ifndef GL_NV_parameter_buffer_object +#define GL_NV_parameter_buffer_object 1 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 +#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 +#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 +#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); +#endif +#endif /* GL_NV_parameter_buffer_object */ + +#ifndef GL_NV_parameter_buffer_object2 +#define GL_NV_parameter_buffer_object2 1 +#endif /* GL_NV_parameter_buffer_object2 */ + +#ifndef GL_NV_path_rendering +#define GL_NV_path_rendering 1 +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); +typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); +typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); +typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); +typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); +typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); +typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); +typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); +typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); +typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); +typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); +typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); +typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); +typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); +typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); +typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); +GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); +GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); +GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); +GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); +GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); +GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); +GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); +GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); +GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); +GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); +GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); +GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); +GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); +GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); +GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); +GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); +GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); +GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); +GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); +GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); +GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); +GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); +GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +#endif +#endif /* GL_NV_path_rendering */ + +#ifndef GL_NV_pixel_data_range +#define GL_NV_pixel_data_range 1 +#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 +#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 +#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A +#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B +#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C +#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D +typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer); +typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer); +GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); +#endif +#endif /* GL_NV_pixel_data_range */ + +#ifndef GL_NV_point_sprite +#define GL_NV_point_sprite 1 +#define GL_POINT_SPRITE_NV 0x8861 +#define GL_COORD_REPLACE_NV 0x8862 +#define GL_POINT_SPRITE_R_MODE_NV 0x8863 +typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); +#endif +#endif /* GL_NV_point_sprite */ + +#ifndef GL_NV_present_video +#define GL_NV_present_video 1 +#define GL_FRAME_NV 0x8E26 +#define GL_FIELDS_NV 0x8E27 +#define GL_CURRENT_TIME_NV 0x8E28 +#define GL_NUM_FILL_STREAMS_NV 0x8E29 +#define GL_PRESENT_TIME_NV 0x8E2A +#define GL_PRESENT_DURATION_NV 0x8E2B +typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); +typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); +typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); +GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); +GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); +GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); +GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_NV_present_video */ + +#ifndef GL_NV_primitive_restart +#define GL_NV_primitive_restart 1 +#define GL_PRIMITIVE_RESTART_NV 0x8558 +#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPrimitiveRestartNV (void); +GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); +#endif +#endif /* GL_NV_primitive_restart */ + +#ifndef GL_NV_register_combiners +#define GL_NV_register_combiners 1 +#define GL_REGISTER_COMBINERS_NV 0x8522 +#define GL_VARIABLE_A_NV 0x8523 +#define GL_VARIABLE_B_NV 0x8524 +#define GL_VARIABLE_C_NV 0x8525 +#define GL_VARIABLE_D_NV 0x8526 +#define GL_VARIABLE_E_NV 0x8527 +#define GL_VARIABLE_F_NV 0x8528 +#define GL_VARIABLE_G_NV 0x8529 +#define GL_CONSTANT_COLOR0_NV 0x852A +#define GL_CONSTANT_COLOR1_NV 0x852B +#define GL_SPARE0_NV 0x852E +#define GL_SPARE1_NV 0x852F +#define GL_DISCARD_NV 0x8530 +#define GL_E_TIMES_F_NV 0x8531 +#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 +#define GL_UNSIGNED_IDENTITY_NV 0x8536 +#define GL_UNSIGNED_INVERT_NV 0x8537 +#define GL_EXPAND_NORMAL_NV 0x8538 +#define GL_EXPAND_NEGATE_NV 0x8539 +#define GL_HALF_BIAS_NORMAL_NV 0x853A +#define GL_HALF_BIAS_NEGATE_NV 0x853B +#define GL_SIGNED_IDENTITY_NV 0x853C +#define GL_SIGNED_NEGATE_NV 0x853D +#define GL_SCALE_BY_TWO_NV 0x853E +#define GL_SCALE_BY_FOUR_NV 0x853F +#define GL_SCALE_BY_ONE_HALF_NV 0x8540 +#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 +#define GL_COMBINER_INPUT_NV 0x8542 +#define GL_COMBINER_MAPPING_NV 0x8543 +#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 +#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 +#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 +#define GL_COMBINER_MUX_SUM_NV 0x8547 +#define GL_COMBINER_SCALE_NV 0x8548 +#define GL_COMBINER_BIAS_NV 0x8549 +#define GL_COMBINER_AB_OUTPUT_NV 0x854A +#define GL_COMBINER_CD_OUTPUT_NV 0x854B +#define GL_COMBINER_SUM_OUTPUT_NV 0x854C +#define GL_MAX_GENERAL_COMBINERS_NV 0x854D +#define GL_NUM_GENERAL_COMBINERS_NV 0x854E +#define GL_COLOR_SUM_CLAMP_NV 0x854F +#define GL_COMBINER0_NV 0x8550 +#define GL_COMBINER1_NV 0x8551 +#define GL_COMBINER2_NV 0x8552 +#define GL_COMBINER3_NV 0x8553 +#define GL_COMBINER4_NV 0x8554 +#define GL_COMBINER5_NV 0x8555 +#define GL_COMBINER6_NV 0x8556 +#define GL_COMBINER7_NV 0x8557 +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); +GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); +GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); +#endif +#endif /* GL_NV_register_combiners */ + +#ifndef GL_NV_register_combiners2 +#define GL_NV_register_combiners2 1 +#define GL_PER_STAGE_CONSTANTS_NV 0x8535 +typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); +#endif +#endif /* GL_NV_register_combiners2 */ + +#ifndef GL_NV_shader_atomic_counters +#define GL_NV_shader_atomic_counters 1 +#endif /* GL_NV_shader_atomic_counters */ + +#ifndef GL_NV_shader_atomic_float +#define GL_NV_shader_atomic_float 1 +#endif /* GL_NV_shader_atomic_float */ + +#ifndef GL_NV_shader_buffer_load +#define GL_NV_shader_buffer_load 1 +#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D +#define GL_GPU_ADDRESS_NV 0x8F34 +#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 +typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); +typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); +typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); +typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); +typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); +typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); +typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); +typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); +GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); +GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); +GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); +GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); +GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); +GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); +GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); +GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); +GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_NV_shader_buffer_load */ + +#ifndef GL_NV_shader_buffer_store +#define GL_NV_shader_buffer_store 1 +#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 +#endif /* GL_NV_shader_buffer_store */ + +#ifndef GL_NV_shader_storage_buffer_object +#define GL_NV_shader_storage_buffer_object 1 +#endif /* GL_NV_shader_storage_buffer_object */ + +#ifndef GL_NV_shader_thread_group +#define GL_NV_shader_thread_group 1 +#define GL_WARP_SIZE_NV 0x9339 +#define GL_WARPS_PER_SM_NV 0x933A +#define GL_SM_COUNT_NV 0x933B +#endif /* GL_NV_shader_thread_group */ + +#ifndef GL_NV_shader_thread_shuffle +#define GL_NV_shader_thread_shuffle 1 +#endif /* GL_NV_shader_thread_shuffle */ + +#ifndef GL_NV_tessellation_program5 +#define GL_NV_tessellation_program5 1 +#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 +#define GL_TESS_CONTROL_PROGRAM_NV 0x891E +#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F +#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 +#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 +#endif /* GL_NV_tessellation_program5 */ + +#ifndef GL_NV_texgen_emboss +#define GL_NV_texgen_emboss 1 +#define GL_EMBOSS_LIGHT_NV 0x855D +#define GL_EMBOSS_CONSTANT_NV 0x855E +#define GL_EMBOSS_MAP_NV 0x855F +#endif /* GL_NV_texgen_emboss */ + +#ifndef GL_NV_texgen_reflection +#define GL_NV_texgen_reflection 1 +#define GL_NORMAL_MAP_NV 0x8511 +#define GL_REFLECTION_MAP_NV 0x8512 +#endif /* GL_NV_texgen_reflection */ + +#ifndef GL_NV_texture_barrier +#define GL_NV_texture_barrier 1 +typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureBarrierNV (void); +#endif +#endif /* GL_NV_texture_barrier */ + +#ifndef GL_NV_texture_compression_vtc +#define GL_NV_texture_compression_vtc 1 +#endif /* GL_NV_texture_compression_vtc */ + +#ifndef GL_NV_texture_env_combine4 +#define GL_NV_texture_env_combine4 1 +#define GL_COMBINE4_NV 0x8503 +#define GL_SOURCE3_RGB_NV 0x8583 +#define GL_SOURCE3_ALPHA_NV 0x858B +#define GL_OPERAND3_RGB_NV 0x8593 +#define GL_OPERAND3_ALPHA_NV 0x859B +#endif /* GL_NV_texture_env_combine4 */ + +#ifndef GL_NV_texture_expand_normal +#define GL_NV_texture_expand_normal 1 +#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F +#endif /* GL_NV_texture_expand_normal */ + +#ifndef GL_NV_texture_multisample +#define GL_NV_texture_multisample 1 +#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 +#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +#endif +#endif /* GL_NV_texture_multisample */ + +#ifndef GL_NV_texture_rectangle +#define GL_NV_texture_rectangle 1 +#define GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#endif /* GL_NV_texture_rectangle */ + +#ifndef GL_NV_texture_shader +#define GL_NV_texture_shader 1 +#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C +#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D +#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E +#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 +#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA +#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB +#define GL_DSDT_MAG_INTENSITY_NV 0x86DC +#define GL_SHADER_CONSISTENT_NV 0x86DD +#define GL_TEXTURE_SHADER_NV 0x86DE +#define GL_SHADER_OPERATION_NV 0x86DF +#define GL_CULL_MODES_NV 0x86E0 +#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 +#define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3 +#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 +#define GL_CONST_EYE_NV 0x86E5 +#define GL_PASS_THROUGH_NV 0x86E6 +#define GL_CULL_FRAGMENT_NV 0x86E7 +#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 +#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 +#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA +#define GL_DOT_PRODUCT_NV 0x86EC +#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED +#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE +#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 +#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 +#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 +#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 +#define GL_HILO_NV 0x86F4 +#define GL_DSDT_NV 0x86F5 +#define GL_DSDT_MAG_NV 0x86F6 +#define GL_DSDT_MAG_VIB_NV 0x86F7 +#define GL_HILO16_NV 0x86F8 +#define GL_SIGNED_HILO_NV 0x86F9 +#define GL_SIGNED_HILO16_NV 0x86FA +#define GL_SIGNED_RGBA_NV 0x86FB +#define GL_SIGNED_RGBA8_NV 0x86FC +#define GL_SIGNED_RGB_NV 0x86FE +#define GL_SIGNED_RGB8_NV 0x86FF +#define GL_SIGNED_LUMINANCE_NV 0x8701 +#define GL_SIGNED_LUMINANCE8_NV 0x8702 +#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 +#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 +#define GL_SIGNED_ALPHA_NV 0x8705 +#define GL_SIGNED_ALPHA8_NV 0x8706 +#define GL_SIGNED_INTENSITY_NV 0x8707 +#define GL_SIGNED_INTENSITY8_NV 0x8708 +#define GL_DSDT8_NV 0x8709 +#define GL_DSDT8_MAG8_NV 0x870A +#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B +#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C +#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D +#define GL_HI_SCALE_NV 0x870E +#define GL_LO_SCALE_NV 0x870F +#define GL_DS_SCALE_NV 0x8710 +#define GL_DT_SCALE_NV 0x8711 +#define GL_MAGNITUDE_SCALE_NV 0x8712 +#define GL_VIBRANCE_SCALE_NV 0x8713 +#define GL_HI_BIAS_NV 0x8714 +#define GL_LO_BIAS_NV 0x8715 +#define GL_DS_BIAS_NV 0x8716 +#define GL_DT_BIAS_NV 0x8717 +#define GL_MAGNITUDE_BIAS_NV 0x8718 +#define GL_VIBRANCE_BIAS_NV 0x8719 +#define GL_TEXTURE_BORDER_VALUES_NV 0x871A +#define GL_TEXTURE_HI_SIZE_NV 0x871B +#define GL_TEXTURE_LO_SIZE_NV 0x871C +#define GL_TEXTURE_DS_SIZE_NV 0x871D +#define GL_TEXTURE_DT_SIZE_NV 0x871E +#define GL_TEXTURE_MAG_SIZE_NV 0x871F +#endif /* GL_NV_texture_shader */ + +#ifndef GL_NV_texture_shader2 +#define GL_NV_texture_shader2 1 +#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF +#endif /* GL_NV_texture_shader2 */ + +#ifndef GL_NV_texture_shader3 +#define GL_NV_texture_shader3 1 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 +#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 +#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 +#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 +#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 +#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A +#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B +#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C +#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D +#define GL_HILO8_NV 0x885E +#define GL_SIGNED_HILO8_NV 0x885F +#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 +#endif /* GL_NV_texture_shader3 */ + +#ifndef GL_NV_transform_feedback +#define GL_NV_transform_feedback 1 +#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 +#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 +#define GL_TEXTURE_COORD_NV 0x8C79 +#define GL_CLIP_DISTANCE_NV 0x8C7A +#define GL_VERTEX_ID_NV 0x8C7B +#define GL_PRIMITIVE_ID_NV 0x8C7C +#define GL_GENERIC_ATTRIB_NV 0x8C7D +#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 +#define GL_ACTIVE_VARYINGS_NV 0x8C81 +#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 +#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 +#define GL_PRIMITIVES_GENERATED_NV 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 +#define GL_RASTERIZER_DISCARD_NV 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B +#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C +#define GL_SEPARATE_ATTRIBS_NV 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F +#define GL_LAYER_NV 0x8DAA +#define GL_NEXT_BUFFER_NV -2 +#define GL_SKIP_COMPONENTS4_NV -3 +#define GL_SKIP_COMPONENTS3_NV -4 +#define GL_SKIP_COMPONENTS2_NV -5 +#define GL_SKIP_COMPONENTS1_NV -6 +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedbackNV (void); +GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); +GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); +GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); +GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); +#endif +#endif /* GL_NV_transform_feedback */ + +#ifndef GL_NV_transform_feedback2 +#define GL_NV_transform_feedback2 1 +#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedbackNV (void); +GLAPI void APIENTRY glResumeTransformFeedbackNV (void); +GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); +#endif +#endif /* GL_NV_transform_feedback2 */ + +#ifndef GL_NV_vdpau_interop +#define GL_NV_vdpau_interop 1 +typedef GLintptr GLvdpauSurfaceNV; +#define GL_SURFACE_STATE_NV 0x86EB +#define GL_SURFACE_REGISTERED_NV 0x86FD +#define GL_SURFACE_MAPPED_NV 0x8700 +#define GL_WRITE_DISCARD_NV 0x88BE +typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress); +typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); +typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); +typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress); +GLAPI void APIENTRY glVDPAUFiniNV (void); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); +GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); +GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); +#endif +#endif /* GL_NV_vdpau_interop */ + +#ifndef GL_NV_vertex_array_range +#define GL_NV_vertex_array_range 1 +#define GL_VERTEX_ARRAY_RANGE_NV 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E +#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F +#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 +#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); +GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer); +#endif +#endif /* GL_NV_vertex_array_range */ + +#ifndef GL_NV_vertex_array_range2 +#define GL_NV_vertex_array_range2 1 +#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 +#endif /* GL_NV_vertex_array_range2 */ + +#ifndef GL_NV_vertex_attrib_integer_64bit +#define GL_NV_vertex_attrib_integer_64bit 1 +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); +GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); +GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +#endif +#endif /* GL_NV_vertex_attrib_integer_64bit */ + +#ifndef GL_NV_vertex_buffer_unified_memory +#define GL_NV_vertex_buffer_unified_memory 1 +#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E +#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F +#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 +#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 +#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 +#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 +#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 +#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 +#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 +#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 +#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 +#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 +#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A +#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B +#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C +#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D +#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E +#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F +#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 +#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 +#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 +#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 +#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 +#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 +#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 +typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); +GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); +#endif +#endif /* GL_NV_vertex_buffer_unified_memory */ + +#ifndef GL_NV_vertex_program +#define GL_NV_vertex_program 1 +#define GL_VERTEX_PROGRAM_NV 0x8620 +#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 +#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 +#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 +#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 +#define GL_CURRENT_ATTRIB_NV 0x8626 +#define GL_PROGRAM_LENGTH_NV 0x8627 +#define GL_PROGRAM_STRING_NV 0x8628 +#define GL_MODELVIEW_PROJECTION_NV 0x8629 +#define GL_IDENTITY_NV 0x862A +#define GL_INVERSE_NV 0x862B +#define GL_TRANSPOSE_NV 0x862C +#define GL_INVERSE_TRANSPOSE_NV 0x862D +#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E +#define GL_MAX_TRACK_MATRICES_NV 0x862F +#define GL_MATRIX0_NV 0x8630 +#define GL_MATRIX1_NV 0x8631 +#define GL_MATRIX2_NV 0x8632 +#define GL_MATRIX3_NV 0x8633 +#define GL_MATRIX4_NV 0x8634 +#define GL_MATRIX5_NV 0x8635 +#define GL_MATRIX6_NV 0x8636 +#define GL_MATRIX7_NV 0x8637 +#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 +#define GL_CURRENT_MATRIX_NV 0x8641 +#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 +#define GL_PROGRAM_PARAMETER_NV 0x8644 +#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 +#define GL_PROGRAM_TARGET_NV 0x8646 +#define GL_PROGRAM_RESIDENT_NV 0x8647 +#define GL_TRACK_MATRIX_NV 0x8648 +#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 +#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A +#define GL_PROGRAM_ERROR_POSITION_NV 0x864B +#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 +#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 +#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 +#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 +#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 +#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 +#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 +#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 +#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 +#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 +#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A +#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B +#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C +#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D +#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E +#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F +#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 +#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 +#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 +#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 +#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 +#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 +#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 +#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 +#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 +#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 +#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A +#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B +#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C +#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D +#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E +#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F +#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 +#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 +#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 +#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 +#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 +#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 +#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 +#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 +#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 +#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 +#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A +#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B +#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C +#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D +#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E +#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F +typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); +typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); +typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); +GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); +GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); +GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); +GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer); +GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); +GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); +GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); +GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); +GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); +#endif +#endif /* GL_NV_vertex_program */ + +#ifndef GL_NV_vertex_program1_1 +#define GL_NV_vertex_program1_1 1 +#endif /* GL_NV_vertex_program1_1 */ + +#ifndef GL_NV_vertex_program2 +#define GL_NV_vertex_program2 1 +#endif /* GL_NV_vertex_program2 */ + +#ifndef GL_NV_vertex_program2_option +#define GL_NV_vertex_program2_option 1 +#endif /* GL_NV_vertex_program2_option */ + +#ifndef GL_NV_vertex_program3 +#define GL_NV_vertex_program3 1 +#endif /* GL_NV_vertex_program3 */ + +#ifndef GL_NV_vertex_program4 +#define GL_NV_vertex_program4 1 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); +#endif +#endif /* GL_NV_vertex_program4 */ + +#ifndef GL_NV_video_capture +#define GL_NV_video_capture 1 +#define GL_VIDEO_BUFFER_NV 0x9020 +#define GL_VIDEO_BUFFER_BINDING_NV 0x9021 +#define GL_FIELD_UPPER_NV 0x9022 +#define GL_FIELD_LOWER_NV 0x9023 +#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 +#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 +#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 +#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 +#define GL_VIDEO_BUFFER_PITCH_NV 0x9028 +#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 +#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A +#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B +#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C +#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D +#define GL_PARTIAL_SUCCESS_NV 0x902E +#define GL_SUCCESS_NV 0x902F +#define GL_FAILURE_NV 0x9030 +#define GL_YCBYCR8_422_NV 0x9031 +#define GL_YCBAYCR8A_4224_NV 0x9032 +#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 +#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 +#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 +#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 +#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 +#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 +#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 +#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A +#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B +#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C +typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); +typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); +typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); +typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); +GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); +GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); +GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); +GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); +GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); +GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); +GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); +#endif +#endif /* GL_NV_video_capture */ + +#ifndef GL_OML_interlace +#define GL_OML_interlace 1 +#define GL_INTERLACE_OML 0x8980 +#define GL_INTERLACE_READ_OML 0x8981 +#endif /* GL_OML_interlace */ + +#ifndef GL_OML_resample +#define GL_OML_resample 1 +#define GL_PACK_RESAMPLE_OML 0x8984 +#define GL_UNPACK_RESAMPLE_OML 0x8985 +#define GL_RESAMPLE_REPLICATE_OML 0x8986 +#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 +#define GL_RESAMPLE_AVERAGE_OML 0x8988 +#define GL_RESAMPLE_DECIMATE_OML 0x8989 +#endif /* GL_OML_resample */ + +#ifndef GL_OML_subsample +#define GL_OML_subsample 1 +#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 +#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 +#endif /* GL_OML_subsample */ + +#ifndef GL_PGI_misc_hints +#define GL_PGI_misc_hints 1 +#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 +#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD +#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE +#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 +#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 +#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 +#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C +#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D +#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E +#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F +#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 +#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 +#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 +#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 +#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 +#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 +#define GL_CLIP_NEAR_HINT_PGI 0x1A220 +#define GL_CLIP_FAR_HINT_PGI 0x1A221 +#define GL_WIDE_LINE_HINT_PGI 0x1A222 +#define GL_BACK_NORMALS_HINT_PGI 0x1A223 +typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); +#endif +#endif /* GL_PGI_misc_hints */ + +#ifndef GL_PGI_vertex_hints +#define GL_PGI_vertex_hints 1 +#define GL_VERTEX_DATA_HINT_PGI 0x1A22A +#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B +#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C +#define GL_MAX_VERTEX_HINT_PGI 0x1A22D +#define GL_COLOR3_BIT_PGI 0x00010000 +#define GL_COLOR4_BIT_PGI 0x00020000 +#define GL_EDGEFLAG_BIT_PGI 0x00040000 +#define GL_INDEX_BIT_PGI 0x00080000 +#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 +#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 +#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 +#define GL_MAT_EMISSION_BIT_PGI 0x00800000 +#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 +#define GL_MAT_SHININESS_BIT_PGI 0x02000000 +#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 +#define GL_NORMAL_BIT_PGI 0x08000000 +#define GL_TEXCOORD1_BIT_PGI 0x10000000 +#define GL_TEXCOORD2_BIT_PGI 0x20000000 +#define GL_TEXCOORD3_BIT_PGI 0x40000000 +#define GL_TEXCOORD4_BIT_PGI 0x80000000 +#define GL_VERTEX23_BIT_PGI 0x00000004 +#define GL_VERTEX4_BIT_PGI 0x00000008 +#endif /* GL_PGI_vertex_hints */ + +#ifndef GL_REND_screen_coordinates +#define GL_REND_screen_coordinates 1 +#define GL_SCREEN_COORDINATES_REND 0x8490 +#define GL_INVERTED_SCREEN_W_REND 0x8491 +#endif /* GL_REND_screen_coordinates */ + +#ifndef GL_S3_s3tc +#define GL_S3_s3tc 1 +#define GL_RGB_S3TC 0x83A0 +#define GL_RGB4_S3TC 0x83A1 +#define GL_RGBA_S3TC 0x83A2 +#define GL_RGBA4_S3TC 0x83A3 +#define GL_RGBA_DXT5_S3TC 0x83A4 +#define GL_RGBA4_DXT5_S3TC 0x83A5 +#endif /* GL_S3_s3tc */ + +#ifndef GL_SGIS_detail_texture +#define GL_SGIS_detail_texture 1 +#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 +#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 +#define GL_LINEAR_DETAIL_SGIS 0x8097 +#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 +#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 +#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A +#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B +#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C +typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); +#endif +#endif /* GL_SGIS_detail_texture */ + +#ifndef GL_SGIS_fog_function +#define GL_SGIS_fog_function 1 +#define GL_FOG_FUNC_SGIS 0x812A +#define GL_FOG_FUNC_POINTS_SGIS 0x812B +#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C +typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); +#endif +#endif /* GL_SGIS_fog_function */ + +#ifndef GL_SGIS_generate_mipmap +#define GL_SGIS_generate_mipmap 1 +#define GL_GENERATE_MIPMAP_SGIS 0x8191 +#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 +#endif /* GL_SGIS_generate_mipmap */ + +#ifndef GL_SGIS_multisample +#define GL_SGIS_multisample 1 +#define GL_MULTISAMPLE_SGIS 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F +#define GL_SAMPLE_MASK_SGIS 0x80A0 +#define GL_1PASS_SGIS 0x80A1 +#define GL_2PASS_0_SGIS 0x80A2 +#define GL_2PASS_1_SGIS 0x80A3 +#define GL_4PASS_0_SGIS 0x80A4 +#define GL_4PASS_1_SGIS 0x80A5 +#define GL_4PASS_2_SGIS 0x80A6 +#define GL_4PASS_3_SGIS 0x80A7 +#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 +#define GL_SAMPLES_SGIS 0x80A9 +#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA +#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB +#define GL_SAMPLE_PATTERN_SGIS 0x80AC +typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); +#endif +#endif /* GL_SGIS_multisample */ + +#ifndef GL_SGIS_pixel_texture +#define GL_SGIS_pixel_texture 1 +#define GL_PIXEL_TEXTURE_SGIS 0x8353 +#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 +#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 +#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); +GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); +GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); +GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); +#endif +#endif /* GL_SGIS_pixel_texture */ + +#ifndef GL_SGIS_point_line_texgen +#define GL_SGIS_point_line_texgen 1 +#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 +#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 +#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 +#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 +#define GL_EYE_POINT_SGIS 0x81F4 +#define GL_OBJECT_POINT_SGIS 0x81F5 +#define GL_EYE_LINE_SGIS 0x81F6 +#define GL_OBJECT_LINE_SGIS 0x81F7 +#endif /* GL_SGIS_point_line_texgen */ + +#ifndef GL_SGIS_point_parameters +#define GL_SGIS_point_parameters 1 +#define GL_POINT_SIZE_MIN_SGIS 0x8126 +#define GL_POINT_SIZE_MAX_SGIS 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 +#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_SGIS_point_parameters */ + +#ifndef GL_SGIS_sharpen_texture +#define GL_SGIS_sharpen_texture 1 +#define GL_LINEAR_SHARPEN_SGIS 0x80AD +#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE +#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF +#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 +typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); +#endif +#endif /* GL_SGIS_sharpen_texture */ + +#ifndef GL_SGIS_texture4D +#define GL_SGIS_texture4D 1 +#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 +#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 +#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 +#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 +#define GL_TEXTURE_4D_SGIS 0x8134 +#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 +#define GL_TEXTURE_4DSIZE_SGIS 0x8136 +#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 +#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 +#define GL_TEXTURE_4D_BINDING_SGIS 0x814F +typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); +#endif +#endif /* GL_SGIS_texture4D */ + +#ifndef GL_SGIS_texture_border_clamp +#define GL_SGIS_texture_border_clamp 1 +#define GL_CLAMP_TO_BORDER_SGIS 0x812D +#endif /* GL_SGIS_texture_border_clamp */ + +#ifndef GL_SGIS_texture_color_mask +#define GL_SGIS_texture_color_mask 1 +#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF +typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#endif +#endif /* GL_SGIS_texture_color_mask */ + +#ifndef GL_SGIS_texture_edge_clamp +#define GL_SGIS_texture_edge_clamp 1 +#define GL_CLAMP_TO_EDGE_SGIS 0x812F +#endif /* GL_SGIS_texture_edge_clamp */ + +#ifndef GL_SGIS_texture_filter4 +#define GL_SGIS_texture_filter4 1 +#define GL_FILTER4_SGIS 0x8146 +#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 +typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); +typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); +GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#endif +#endif /* GL_SGIS_texture_filter4 */ + +#ifndef GL_SGIS_texture_lod +#define GL_SGIS_texture_lod 1 +#define GL_TEXTURE_MIN_LOD_SGIS 0x813A +#define GL_TEXTURE_MAX_LOD_SGIS 0x813B +#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C +#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D +#endif /* GL_SGIS_texture_lod */ + +#ifndef GL_SGIS_texture_select +#define GL_SGIS_texture_select 1 +#define GL_DUAL_ALPHA4_SGIS 0x8110 +#define GL_DUAL_ALPHA8_SGIS 0x8111 +#define GL_DUAL_ALPHA12_SGIS 0x8112 +#define GL_DUAL_ALPHA16_SGIS 0x8113 +#define GL_DUAL_LUMINANCE4_SGIS 0x8114 +#define GL_DUAL_LUMINANCE8_SGIS 0x8115 +#define GL_DUAL_LUMINANCE12_SGIS 0x8116 +#define GL_DUAL_LUMINANCE16_SGIS 0x8117 +#define GL_DUAL_INTENSITY4_SGIS 0x8118 +#define GL_DUAL_INTENSITY8_SGIS 0x8119 +#define GL_DUAL_INTENSITY12_SGIS 0x811A +#define GL_DUAL_INTENSITY16_SGIS 0x811B +#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C +#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D +#define GL_QUAD_ALPHA4_SGIS 0x811E +#define GL_QUAD_ALPHA8_SGIS 0x811F +#define GL_QUAD_LUMINANCE4_SGIS 0x8120 +#define GL_QUAD_LUMINANCE8_SGIS 0x8121 +#define GL_QUAD_INTENSITY4_SGIS 0x8122 +#define GL_QUAD_INTENSITY8_SGIS 0x8123 +#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 +#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 +#endif /* GL_SGIS_texture_select */ + +#ifndef GL_SGIX_async +#define GL_SGIX_async 1 +#define GL_ASYNC_MARKER_SGIX 0x8329 +typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); +typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); +typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); +typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); +GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); +GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); +GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); +GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); +GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); +#endif +#endif /* GL_SGIX_async */ + +#ifndef GL_SGIX_async_histogram +#define GL_SGIX_async_histogram 1 +#define GL_ASYNC_HISTOGRAM_SGIX 0x832C +#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D +#endif /* GL_SGIX_async_histogram */ + +#ifndef GL_SGIX_async_pixel +#define GL_SGIX_async_pixel 1 +#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C +#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D +#define GL_ASYNC_READ_PIXELS_SGIX 0x835E +#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F +#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 +#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 +#endif /* GL_SGIX_async_pixel */ + +#ifndef GL_SGIX_blend_alpha_minmax +#define GL_SGIX_blend_alpha_minmax 1 +#define GL_ALPHA_MIN_SGIX 0x8320 +#define GL_ALPHA_MAX_SGIX 0x8321 +#endif /* GL_SGIX_blend_alpha_minmax */ + +#ifndef GL_SGIX_calligraphic_fragment +#define GL_SGIX_calligraphic_fragment 1 +#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 +#endif /* GL_SGIX_calligraphic_fragment */ + +#ifndef GL_SGIX_clipmap +#define GL_SGIX_clipmap 1 +#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 +#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 +#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 +#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 +#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 +#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 +#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 +#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 +#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 +#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D +#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E +#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F +#endif /* GL_SGIX_clipmap */ + +#ifndef GL_SGIX_convolution_accuracy +#define GL_SGIX_convolution_accuracy 1 +#define GL_CONVOLUTION_HINT_SGIX 0x8316 +#endif /* GL_SGIX_convolution_accuracy */ + +#ifndef GL_SGIX_depth_pass_instrument +#define GL_SGIX_depth_pass_instrument 1 +#endif /* GL_SGIX_depth_pass_instrument */ + +#ifndef GL_SGIX_depth_texture +#define GL_SGIX_depth_texture 1 +#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 +#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 +#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 +#endif /* GL_SGIX_depth_texture */ + +#ifndef GL_SGIX_flush_raster +#define GL_SGIX_flush_raster 1 +typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushRasterSGIX (void); +#endif +#endif /* GL_SGIX_flush_raster */ + +#ifndef GL_SGIX_fog_offset +#define GL_SGIX_fog_offset 1 +#define GL_FOG_OFFSET_SGIX 0x8198 +#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 +#endif /* GL_SGIX_fog_offset */ + +#ifndef GL_SGIX_fragment_lighting +#define GL_SGIX_fragment_lighting 1 +#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 +#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 +#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 +#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 +#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 +#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 +#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 +#define GL_LIGHT_ENV_MODE_SGIX 0x8407 +#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 +#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 +#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A +#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B +#define GL_FRAGMENT_LIGHT0_SGIX 0x840C +#define GL_FRAGMENT_LIGHT1_SGIX 0x840D +#define GL_FRAGMENT_LIGHT2_SGIX 0x840E +#define GL_FRAGMENT_LIGHT3_SGIX 0x840F +#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 +#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 +#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 +#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 +typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); +GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); +GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); +GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); +GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); +GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); +#endif +#endif /* GL_SGIX_fragment_lighting */ + +#ifndef GL_SGIX_framezoom +#define GL_SGIX_framezoom 1 +#define GL_FRAMEZOOM_SGIX 0x818B +#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C +#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D +typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); +#endif +#endif /* GL_SGIX_framezoom */ + +#ifndef GL_SGIX_igloo_interface +#define GL_SGIX_igloo_interface 1 +typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params); +#endif +#endif /* GL_SGIX_igloo_interface */ + +#ifndef GL_SGIX_instruments +#define GL_SGIX_instruments 1 +#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 +#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 +typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); +typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); +typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); +typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); +GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); +GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); +GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); +GLAPI void APIENTRY glStartInstrumentsSGIX (void); +GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); +#endif +#endif /* GL_SGIX_instruments */ + +#ifndef GL_SGIX_interlace +#define GL_SGIX_interlace 1 +#define GL_INTERLACE_SGIX 0x8094 +#endif /* GL_SGIX_interlace */ + +#ifndef GL_SGIX_ir_instrument1 +#define GL_SGIX_ir_instrument1 1 +#define GL_IR_INSTRUMENT1_SGIX 0x817F +#endif /* GL_SGIX_ir_instrument1 */ + +#ifndef GL_SGIX_list_priority +#define GL_SGIX_list_priority 1 +#define GL_LIST_PRIORITY_SGIX 0x8182 +typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); +GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); +GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); +GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); +#endif +#endif /* GL_SGIX_list_priority */ + +#ifndef GL_SGIX_pixel_texture +#define GL_SGIX_pixel_texture 1 +#define GL_PIXEL_TEX_GEN_SGIX 0x8139 +#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B +typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); +#endif +#endif /* GL_SGIX_pixel_texture */ + +#ifndef GL_SGIX_pixel_tiles +#define GL_SGIX_pixel_tiles 1 +#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E +#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F +#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 +#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 +#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 +#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 +#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 +#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 +#endif /* GL_SGIX_pixel_tiles */ + +#ifndef GL_SGIX_polynomial_ffd +#define GL_SGIX_polynomial_ffd 1 +#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 +#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 +#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 +#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 +#define GL_DEFORMATIONS_MASK_SGIX 0x8196 +#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); +GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); +#endif +#endif /* GL_SGIX_polynomial_ffd */ + +#ifndef GL_SGIX_reference_plane +#define GL_SGIX_reference_plane 1 +#define GL_REFERENCE_PLANE_SGIX 0x817D +#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E +typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); +#endif +#endif /* GL_SGIX_reference_plane */ + +#ifndef GL_SGIX_resample +#define GL_SGIX_resample 1 +#define GL_PACK_RESAMPLE_SGIX 0x842C +#define GL_UNPACK_RESAMPLE_SGIX 0x842D +#define GL_RESAMPLE_REPLICATE_SGIX 0x842E +#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F +#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 +#endif /* GL_SGIX_resample */ + +#ifndef GL_SGIX_scalebias_hint +#define GL_SGIX_scalebias_hint 1 +#define GL_SCALEBIAS_HINT_SGIX 0x8322 +#endif /* GL_SGIX_scalebias_hint */ + +#ifndef GL_SGIX_shadow +#define GL_SGIX_shadow 1 +#define GL_TEXTURE_COMPARE_SGIX 0x819A +#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B +#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C +#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D +#endif /* GL_SGIX_shadow */ + +#ifndef GL_SGIX_shadow_ambient +#define GL_SGIX_shadow_ambient 1 +#define GL_SHADOW_AMBIENT_SGIX 0x80BF +#endif /* GL_SGIX_shadow_ambient */ + +#ifndef GL_SGIX_sprite +#define GL_SGIX_sprite 1 +#define GL_SPRITE_SGIX 0x8148 +#define GL_SPRITE_MODE_SGIX 0x8149 +#define GL_SPRITE_AXIS_SGIX 0x814A +#define GL_SPRITE_TRANSLATION_SGIX 0x814B +#define GL_SPRITE_AXIAL_SGIX 0x814C +#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D +#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); +GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); +GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); +#endif +#endif /* GL_SGIX_sprite */ + +#ifndef GL_SGIX_subsample +#define GL_SGIX_subsample 1 +#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 +#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 +#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 +#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 +#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 +#endif /* GL_SGIX_subsample */ + +#ifndef GL_SGIX_tag_sample_buffer +#define GL_SGIX_tag_sample_buffer 1 +typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTagSampleBufferSGIX (void); +#endif +#endif /* GL_SGIX_tag_sample_buffer */ + +#ifndef GL_SGIX_texture_add_env +#define GL_SGIX_texture_add_env 1 +#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE +#endif /* GL_SGIX_texture_add_env */ + +#ifndef GL_SGIX_texture_coordinate_clamp +#define GL_SGIX_texture_coordinate_clamp 1 +#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 +#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A +#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B +#endif /* GL_SGIX_texture_coordinate_clamp */ + +#ifndef GL_SGIX_texture_lod_bias +#define GL_SGIX_texture_lod_bias 1 +#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E +#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F +#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 +#endif /* GL_SGIX_texture_lod_bias */ + +#ifndef GL_SGIX_texture_multi_buffer +#define GL_SGIX_texture_multi_buffer 1 +#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E +#endif /* GL_SGIX_texture_multi_buffer */ + +#ifndef GL_SGIX_texture_scale_bias +#define GL_SGIX_texture_scale_bias 1 +#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 +#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A +#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B +#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C +#endif /* GL_SGIX_texture_scale_bias */ + +#ifndef GL_SGIX_vertex_preclip +#define GL_SGIX_vertex_preclip 1 +#define GL_VERTEX_PRECLIP_SGIX 0x83EE +#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF +#endif /* GL_SGIX_vertex_preclip */ + +#ifndef GL_SGIX_ycrcb +#define GL_SGIX_ycrcb 1 +#define GL_YCRCB_422_SGIX 0x81BB +#define GL_YCRCB_444_SGIX 0x81BC +#endif /* GL_SGIX_ycrcb */ + +#ifndef GL_SGIX_ycrcb_subsample +#define GL_SGIX_ycrcb_subsample 1 +#endif /* GL_SGIX_ycrcb_subsample */ + +#ifndef GL_SGIX_ycrcba +#define GL_SGIX_ycrcba 1 +#define GL_YCRCB_SGIX 0x8318 +#define GL_YCRCBA_SGIX 0x8319 +#endif /* GL_SGIX_ycrcba */ + +#ifndef GL_SGI_color_matrix +#define GL_SGI_color_matrix 1 +#define GL_COLOR_MATRIX_SGI 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB +#endif /* GL_SGI_color_matrix */ + +#ifndef GL_SGI_color_table +#define GL_SGI_color_table 1 +#define GL_COLOR_TABLE_SGI 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 +#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 +#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 +#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 +#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 +#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF +typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table); +GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); +#endif +#endif /* GL_SGI_color_table */ + +#ifndef GL_SGI_texture_color_table +#define GL_SGI_texture_color_table 1 +#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC +#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD +#endif /* GL_SGI_texture_color_table */ + +#ifndef GL_SUNX_constant_data +#define GL_SUNX_constant_data 1 +#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 +#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 +typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFinishTextureSUNX (void); +#endif +#endif /* GL_SUNX_constant_data */ + +#ifndef GL_SUN_convolution_border_modes +#define GL_SUN_convolution_border_modes 1 +#define GL_WRAP_BORDER_SUN 0x81D4 +#endif /* GL_SUN_convolution_border_modes */ + +#ifndef GL_SUN_global_alpha +#define GL_SUN_global_alpha 1 +#define GL_GLOBAL_ALPHA_SUN 0x81D9 +#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); +GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); +GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); +GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); +GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); +GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); +GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); +GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); +#endif +#endif /* GL_SUN_global_alpha */ + +#ifndef GL_SUN_mesh_array +#define GL_SUN_mesh_array 1 +#define GL_QUAD_MESH_SUN 0x8614 +#define GL_TRIANGLE_MESH_SUN 0x8615 +typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); +#endif +#endif /* GL_SUN_mesh_array */ + +#ifndef GL_SUN_slice_accum +#define GL_SUN_slice_accum 1 +#define GL_SLICE_ACCUM_SUN 0x85CC +#endif /* GL_SUN_slice_accum */ + +#ifndef GL_SUN_triangle_list +#define GL_SUN_triangle_list 1 +#define GL_RESTART_SUN 0x0001 +#define GL_REPLACE_MIDDLE_SUN 0x0002 +#define GL_REPLACE_OLDEST_SUN 0x0003 +#define GL_TRIANGLE_LIST_SUN 0x81D7 +#define GL_REPLACEMENT_CODE_SUN 0x81D8 +#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 +#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 +#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 +#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 +#define GL_R1UI_V3F_SUN 0x85C4 +#define GL_R1UI_C4UB_V3F_SUN 0x85C5 +#define GL_R1UI_C3F_V3F_SUN 0x85C6 +#define GL_R1UI_N3F_V3F_SUN 0x85C7 +#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 +#define GL_R1UI_T2F_V3F_SUN 0x85C9 +#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA +#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); +GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); +GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); +GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); +GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); +GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); +GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer); +#endif +#endif /* GL_SUN_triangle_list */ + +#ifndef GL_SUN_vertex +#define GL_SUN_vertex 1 +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#endif +#endif /* GL_SUN_vertex */ + +#ifndef GL_WIN_phong_shading +#define GL_WIN_phong_shading 1 +#define GL_PHONG_WIN 0x80EA +#define GL_PHONG_HINT_WIN 0x80EB +#endif /* GL_WIN_phong_shading */ + +#ifndef GL_WIN_specular_fog +#define GL_WIN_specular_fog 1 +#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC +#endif /* GL_WIN_specular_fog */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/renderdoc/driver/gl/official/glxext.h b/renderdoc/driver/gl/official/glxext.h new file mode 100644 index 0000000000..7437d148c0 --- /dev/null +++ b/renderdoc/driver/gl/official/glxext.h @@ -0,0 +1,889 @@ +#ifndef __glxext_h_ +#define __glxext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2014 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision: 26290 $ on $Date: 2014-04-16 05:35:38 -0700 (Wed, 16 Apr 2014) $ +*/ + +#define GLX_GLXEXT_VERSION 20140416 + +/* Generated C header for: + * API: glx + * Versions considered: .* + * Versions emitted: 1\.[3-9] + * Default extensions included: glx + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GLX_VERSION_1_3 +#define GLX_VERSION_1_3 1 +typedef XID GLXContextID; +typedef struct __GLXFBConfigRec *GLXFBConfig; +typedef XID GLXWindow; +typedef XID GLXPbuffer; +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_PIXMAP_BIT 0x00000002 +#define GLX_PBUFFER_BIT 0x00000004 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_COLOR_INDEX_BIT 0x00000002 +#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 +#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 +#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 +#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 +#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 +#define GLX_AUX_BUFFERS_BIT 0x00000010 +#define GLX_DEPTH_BUFFER_BIT 0x00000020 +#define GLX_STENCIL_BUFFER_BIT 0x00000040 +#define GLX_ACCUM_BUFFER_BIT 0x00000080 +#define GLX_CONFIG_CAVEAT 0x20 +#define GLX_X_VISUAL_TYPE 0x22 +#define GLX_TRANSPARENT_TYPE 0x23 +#define GLX_TRANSPARENT_INDEX_VALUE 0x24 +#define GLX_TRANSPARENT_RED_VALUE 0x25 +#define GLX_TRANSPARENT_GREEN_VALUE 0x26 +#define GLX_TRANSPARENT_BLUE_VALUE 0x27 +#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 +#define GLX_DONT_CARE 0xFFFFFFFF +#define GLX_NONE 0x8000 +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_PSEUDO_COLOR 0x8004 +#define GLX_STATIC_COLOR 0x8005 +#define GLX_GRAY_SCALE 0x8006 +#define GLX_STATIC_GRAY 0x8007 +#define GLX_TRANSPARENT_RGB 0x8008 +#define GLX_TRANSPARENT_INDEX 0x8009 +#define GLX_VISUAL_ID 0x800B +#define GLX_SCREEN 0x800C +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_X_RENDERABLE 0x8012 +#define GLX_FBCONFIG_ID 0x8013 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_COLOR_INDEX_TYPE 0x8015 +#define GLX_MAX_PBUFFER_WIDTH 0x8016 +#define GLX_MAX_PBUFFER_HEIGHT 0x8017 +#define GLX_MAX_PBUFFER_PIXELS 0x8018 +#define GLX_PRESERVED_CONTENTS 0x801B +#define GLX_LARGEST_PBUFFER 0x801C +#define GLX_WIDTH 0x801D +#define GLX_HEIGHT 0x801E +#define GLX_EVENT_MASK 0x801F +#define GLX_DAMAGED 0x8020 +#define GLX_SAVED 0x8021 +#define GLX_WINDOW 0x8022 +#define GLX_PBUFFER 0x8023 +#define GLX_PBUFFER_HEIGHT 0x8040 +#define GLX_PBUFFER_WIDTH 0x8041 +typedef GLXFBConfig *( *PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements); +typedef GLXFBConfig *( *PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); +typedef int ( *PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value); +typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config); +typedef GLXWindow ( *PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); +typedef void ( *PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win); +typedef GLXPixmap ( *PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); +typedef void ( *PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap); +typedef GLXPbuffer ( *PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list); +typedef void ( *PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf); +typedef void ( *PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); +typedef GLXContext ( *PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); +typedef Bool ( *PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLEPROC) (void); +typedef int ( *PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value); +typedef void ( *PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask); +typedef void ( *PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXFBConfig *glXGetFBConfigs (Display *dpy, int screen, int *nelements); +GLXFBConfig *glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements); +int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value); +XVisualInfo *glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config); +GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); +void glXDestroyWindow (Display *dpy, GLXWindow win); +GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); +void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap); +GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list); +void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf); +void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); +GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); +Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +GLXDrawable glXGetCurrentReadDrawable (void); +int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value); +void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask); +void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask); +#endif +#endif /* GLX_VERSION_1_3 */ + +#ifndef GLX_VERSION_1_4 +#define GLX_VERSION_1_4 1 +typedef void ( *__GLXextFuncPtr)(void); +#define GLX_SAMPLE_BUFFERS 100000 +#define GLX_SAMPLES 100001 +typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName); +#ifdef GLX_GLXEXT_PROTOTYPES +__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName); +#endif +#endif /* GLX_VERSION_1_4 */ + +#ifndef GLX_ARB_create_context +#define GLX_ARB_create_context 1 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +typedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); +#endif +#endif /* GLX_ARB_create_context */ + +#ifndef GLX_ARB_create_context_profile +#define GLX_ARB_create_context_profile 1 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif /* GLX_ARB_create_context_profile */ + +#ifndef GLX_ARB_create_context_robustness +#define GLX_ARB_create_context_robustness 1 +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* GLX_ARB_create_context_robustness */ + +#ifndef GLX_ARB_fbconfig_float +#define GLX_ARB_fbconfig_float 1 +#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 +#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 +#endif /* GLX_ARB_fbconfig_float */ + +#ifndef GLX_ARB_framebuffer_sRGB +#define GLX_ARB_framebuffer_sRGB 1 +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif /* GLX_ARB_framebuffer_sRGB */ + +#ifndef GLX_ARB_get_proc_address +#define GLX_ARB_get_proc_address 1 +typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); +#ifdef GLX_GLXEXT_PROTOTYPES +__GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName); +#endif +#endif /* GLX_ARB_get_proc_address */ + +#ifndef GLX_ARB_multisample +#define GLX_ARB_multisample 1 +#define GLX_SAMPLE_BUFFERS_ARB 100000 +#define GLX_SAMPLES_ARB 100001 +#endif /* GLX_ARB_multisample */ + +#ifndef GLX_ARB_robustness_application_isolation +#define GLX_ARB_robustness_application_isolation 1 +#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* GLX_ARB_robustness_application_isolation */ + +#ifndef GLX_ARB_robustness_share_group_isolation +#define GLX_ARB_robustness_share_group_isolation 1 +#endif /* GLX_ARB_robustness_share_group_isolation */ + +#ifndef GLX_ARB_vertex_buffer_object +#define GLX_ARB_vertex_buffer_object 1 +#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095 +#endif /* GLX_ARB_vertex_buffer_object */ + +#ifndef GLX_3DFX_multisample +#define GLX_3DFX_multisample 1 +#define GLX_SAMPLE_BUFFERS_3DFX 0x8050 +#define GLX_SAMPLES_3DFX 0x8051 +#endif /* GLX_3DFX_multisample */ + +#ifndef GLX_AMD_gpu_association +#define GLX_AMD_gpu_association 1 +#define GLX_GPU_VENDOR_AMD 0x1F00 +#define GLX_GPU_RENDERER_STRING_AMD 0x1F01 +#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define GLX_GPU_RAM_AMD 0x21A3 +#define GLX_GPU_CLOCK_AMD 0x21A4 +#define GLX_GPU_NUM_PIPES_AMD 0x21A5 +#define GLX_GPU_NUM_SIMD_AMD 0x21A6 +#define GLX_GPU_NUM_RB_AMD 0x21A7 +#define GLX_GPU_NUM_SPI_AMD 0x21A8 +#endif /* GLX_AMD_gpu_association */ + +#ifndef GLX_EXT_buffer_age +#define GLX_EXT_buffer_age 1 +#define GLX_BACK_BUFFER_AGE_EXT 0x20F4 +#endif /* GLX_EXT_buffer_age */ + +#ifndef GLX_EXT_create_context_es2_profile +#define GLX_EXT_create_context_es2_profile 1 +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* GLX_EXT_create_context_es2_profile */ + +#ifndef GLX_EXT_create_context_es_profile +#define GLX_EXT_create_context_es_profile 1 +#define GLX_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* GLX_EXT_create_context_es_profile */ + +#ifndef GLX_EXT_fbconfig_packed_float +#define GLX_EXT_fbconfig_packed_float 1 +#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 +#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 +#endif /* GLX_EXT_fbconfig_packed_float */ + +#ifndef GLX_EXT_framebuffer_sRGB +#define GLX_EXT_framebuffer_sRGB 1 +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 +#endif /* GLX_EXT_framebuffer_sRGB */ + +#ifndef GLX_EXT_import_context +#define GLX_EXT_import_context 1 +#define GLX_SHARE_CONTEXT_EXT 0x800A +#define GLX_VISUAL_ID_EXT 0x800B +#define GLX_SCREEN_EXT 0x800C +typedef Display *( *PFNGLXGETCURRENTDISPLAYEXTPROC) (void); +typedef int ( *PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value); +typedef GLXContextID ( *PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context); +typedef GLXContext ( *PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID); +typedef void ( *PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context); +#ifdef GLX_GLXEXT_PROTOTYPES +Display *glXGetCurrentDisplayEXT (void); +int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value); +GLXContextID glXGetContextIDEXT (const GLXContext context); +GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID); +void glXFreeContextEXT (Display *dpy, GLXContext context); +#endif +#endif /* GLX_EXT_import_context */ + +#ifndef GLX_EXT_stereo_tree +#define GLX_EXT_stereo_tree 1 +typedef struct { + int type; + unsigned long serial; + Bool send_event; + Display *display; + int extension; + int evtype; + GLXDrawable window; + Bool stereo_tree; +} GLXStereoNotifyEventEXT; +#define GLX_STEREO_TREE_EXT 0x20F5 +#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001 +#define GLX_STEREO_NOTIFY_EXT 0x00000000 +#endif /* GLX_EXT_stereo_tree */ + +#ifndef GLX_EXT_swap_control +#define GLX_EXT_swap_control 1 +#define GLX_SWAP_INTERVAL_EXT 0x20F1 +#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 +typedef void ( *PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval); +#endif +#endif /* GLX_EXT_swap_control */ + +#ifndef GLX_EXT_swap_control_tear +#define GLX_EXT_swap_control_tear 1 +#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 +#endif /* GLX_EXT_swap_control_tear */ + +#ifndef GLX_EXT_texture_from_pixmap +#define GLX_EXT_texture_from_pixmap 1 +#define GLX_TEXTURE_1D_BIT_EXT 0x00000001 +#define GLX_TEXTURE_2D_BIT_EXT 0x00000002 +#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 +#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 +#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 +#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 +#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 +#define GLX_Y_INVERTED_EXT 0x20D4 +#define GLX_TEXTURE_FORMAT_EXT 0x20D5 +#define GLX_TEXTURE_TARGET_EXT 0x20D6 +#define GLX_MIPMAP_TEXTURE_EXT 0x20D7 +#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 +#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 +#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA +#define GLX_TEXTURE_1D_EXT 0x20DB +#define GLX_TEXTURE_2D_EXT 0x20DC +#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD +#define GLX_FRONT_LEFT_EXT 0x20DE +#define GLX_FRONT_RIGHT_EXT 0x20DF +#define GLX_BACK_LEFT_EXT 0x20E0 +#define GLX_BACK_RIGHT_EXT 0x20E1 +#define GLX_FRONT_EXT 0x20DE +#define GLX_BACK_EXT 0x20E0 +#define GLX_AUX0_EXT 0x20E2 +#define GLX_AUX1_EXT 0x20E3 +#define GLX_AUX2_EXT 0x20E4 +#define GLX_AUX3_EXT 0x20E5 +#define GLX_AUX4_EXT 0x20E6 +#define GLX_AUX5_EXT 0x20E7 +#define GLX_AUX6_EXT 0x20E8 +#define GLX_AUX7_EXT 0x20E9 +#define GLX_AUX8_EXT 0x20EA +#define GLX_AUX9_EXT 0x20EB +typedef void ( *PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); +typedef void ( *PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); +void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer); +#endif +#endif /* GLX_EXT_texture_from_pixmap */ + +#ifndef GLX_EXT_visual_info +#define GLX_EXT_visual_info 1 +#define GLX_X_VISUAL_TYPE_EXT 0x22 +#define GLX_TRANSPARENT_TYPE_EXT 0x23 +#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 +#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25 +#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 +#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 +#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 +#define GLX_NONE_EXT 0x8000 +#define GLX_TRUE_COLOR_EXT 0x8002 +#define GLX_DIRECT_COLOR_EXT 0x8003 +#define GLX_PSEUDO_COLOR_EXT 0x8004 +#define GLX_STATIC_COLOR_EXT 0x8005 +#define GLX_GRAY_SCALE_EXT 0x8006 +#define GLX_STATIC_GRAY_EXT 0x8007 +#define GLX_TRANSPARENT_RGB_EXT 0x8008 +#define GLX_TRANSPARENT_INDEX_EXT 0x8009 +#endif /* GLX_EXT_visual_info */ + +#ifndef GLX_EXT_visual_rating +#define GLX_EXT_visual_rating 1 +#define GLX_VISUAL_CAVEAT_EXT 0x20 +#define GLX_SLOW_VISUAL_EXT 0x8001 +#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D +#endif /* GLX_EXT_visual_rating */ + +#ifndef GLX_INTEL_swap_event +#define GLX_INTEL_swap_event 1 +#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000 +#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180 +#define GLX_COPY_COMPLETE_INTEL 0x8181 +#define GLX_FLIP_COMPLETE_INTEL 0x8182 +#endif /* GLX_INTEL_swap_event */ + +#ifndef GLX_MESA_agp_offset +#define GLX_MESA_agp_offset 1 +typedef unsigned int ( *PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer); +#ifdef GLX_GLXEXT_PROTOTYPES +unsigned int glXGetAGPOffsetMESA (const void *pointer); +#endif +#endif /* GLX_MESA_agp_offset */ + +#ifndef GLX_MESA_copy_sub_buffer +#define GLX_MESA_copy_sub_buffer 1 +typedef void ( *PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); +#endif +#endif /* GLX_MESA_copy_sub_buffer */ + +#ifndef GLX_MESA_pixmap_colormap +#define GLX_MESA_pixmap_colormap 1 +typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); +#endif +#endif /* GLX_MESA_pixmap_colormap */ + +#ifndef GLX_MESA_query_renderer +#define GLX_MESA_query_renderer 1 +#define GLX_RENDERER_VENDOR_ID_MESA 0x8183 +#define GLX_RENDERER_DEVICE_ID_MESA 0x8184 +#define GLX_RENDERER_VERSION_MESA 0x8185 +#define GLX_RENDERER_ACCELERATED_MESA 0x8186 +#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 +#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 +#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 +#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A +#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B +#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C +#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D +#define GLX_RENDERER_ID_MESA 0x818E +typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value); +typedef const char *( *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute); +typedef Bool ( *PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value); +typedef const char *( *PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXQueryCurrentRendererIntegerMESA (int attribute, unsigned int *value); +const char *glXQueryCurrentRendererStringMESA (int attribute); +Bool glXQueryRendererIntegerMESA (Display *dpy, int screen, int renderer, int attribute, unsigned int *value); +const char *glXQueryRendererStringMESA (Display *dpy, int screen, int renderer, int attribute); +#endif +#endif /* GLX_MESA_query_renderer */ + +#ifndef GLX_MESA_release_buffers +#define GLX_MESA_release_buffers 1 +typedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable); +#endif +#endif /* GLX_MESA_release_buffers */ + +#ifndef GLX_MESA_set_3dfx_mode +#define GLX_MESA_set_3dfx_mode 1 +#define GLX_3DFX_WINDOW_MODE_MESA 0x1 +#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 +typedef Bool ( *PFNGLXSET3DFXMODEMESAPROC) (int mode); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXSet3DfxModeMESA (int mode); +#endif +#endif /* GLX_MESA_set_3dfx_mode */ + +#ifndef GLX_NV_copy_image +#define GLX_NV_copy_image 1 +typedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* GLX_NV_copy_image */ + +#ifndef GLX_NV_delay_before_swap +#define GLX_NV_delay_before_swap 1 +typedef Bool ( *PFNGLXDELAYBEFORESWAPNVPROC) (Display *dpy, GLXDrawable drawable, GLfloat seconds); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXDelayBeforeSwapNV (Display *dpy, GLXDrawable drawable, GLfloat seconds); +#endif +#endif /* GLX_NV_delay_before_swap */ + +#ifndef GLX_NV_float_buffer +#define GLX_NV_float_buffer 1 +#define GLX_FLOAT_COMPONENTS_NV 0x20B0 +#endif /* GLX_NV_float_buffer */ + +#ifndef GLX_NV_multisample_coverage +#define GLX_NV_multisample_coverage 1 +#define GLX_COVERAGE_SAMPLES_NV 100001 +#define GLX_COLOR_SAMPLES_NV 0x20B3 +#endif /* GLX_NV_multisample_coverage */ + +#ifndef GLX_NV_present_video +#define GLX_NV_present_video 1 +#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0 +typedef unsigned int *( *PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements); +typedef int ( *PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); +#ifdef GLX_GLXEXT_PROTOTYPES +unsigned int *glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements); +int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); +#endif +#endif /* GLX_NV_present_video */ + +#ifndef GLX_NV_swap_group +#define GLX_NV_swap_group 1 +typedef Bool ( *PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group); +typedef Bool ( *PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier); +typedef Bool ( *PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); +typedef Bool ( *PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); +typedef Bool ( *PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count); +typedef Bool ( *PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group); +Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier); +Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); +Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); +Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count); +Bool glXResetFrameCountNV (Display *dpy, int screen); +#endif +#endif /* GLX_NV_swap_group */ + +#ifndef GLX_NV_video_capture +#define GLX_NV_video_capture 1 +typedef XID GLXVideoCaptureDeviceNV; +#define GLX_DEVICE_ID_NV 0x20CD +#define GLX_UNIQUE_ID_NV 0x20CE +#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +typedef int ( *PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); +typedef GLXVideoCaptureDeviceNV *( *PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements); +typedef void ( *PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); +typedef int ( *PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); +typedef void ( *PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); +GLXVideoCaptureDeviceNV *glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements); +void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); +int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); +void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); +#endif +#endif /* GLX_NV_video_capture */ + +#ifndef GLX_NV_video_output +#define GLX_NV_video_output 1 +typedef unsigned int GLXVideoDeviceNV; +#define GLX_VIDEO_OUT_COLOR_NV 0x20C3 +#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 +#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5 +#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define GLX_VIDEO_OUT_FRAME_NV 0x20C8 +#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 +#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA +#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB +#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC +typedef int ( *PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); +typedef int ( *PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); +typedef int ( *PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); +typedef int ( *PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf); +typedef int ( *PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); +typedef int ( *PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); +int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); +int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); +int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf); +int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); +int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#endif +#endif /* GLX_NV_video_output */ + +#ifndef GLX_OML_swap_method +#define GLX_OML_swap_method 1 +#define GLX_SWAP_METHOD_OML 0x8060 +#define GLX_SWAP_EXCHANGE_OML 0x8061 +#define GLX_SWAP_COPY_OML 0x8062 +#define GLX_SWAP_UNDEFINED_OML 0x8063 +#endif /* GLX_OML_swap_method */ + +#ifndef GLX_OML_sync_control +#define GLX_OML_sync_control 1 +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GLX_OML_sync_control extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef Bool ( *PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); +typedef Bool ( *PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); +typedef int64_t ( *PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); +typedef Bool ( *PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); +typedef Bool ( *PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); +Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); +int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); +Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); +Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); +#endif +#endif /* GLX_OML_sync_control */ + +#ifndef GLX_SGIS_blended_overlay +#define GLX_SGIS_blended_overlay 1 +#define GLX_BLENDED_RGBA_SGIS 0x8025 +#endif /* GLX_SGIS_blended_overlay */ + +#ifndef GLX_SGIS_multisample +#define GLX_SGIS_multisample 1 +#define GLX_SAMPLE_BUFFERS_SGIS 100000 +#define GLX_SAMPLES_SGIS 100001 +#endif /* GLX_SGIS_multisample */ + +#ifndef GLX_SGIS_shared_multisample +#define GLX_SGIS_shared_multisample 1 +#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 +#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 +#endif /* GLX_SGIS_shared_multisample */ + +#ifndef GLX_SGIX_dmbuffer +#define GLX_SGIX_dmbuffer 1 +typedef XID GLXPbufferSGIX; +#ifdef _DM_BUFFER_H_ +#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 +typedef Bool ( *PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); +#endif +#endif /* _DM_BUFFER_H_ */ +#endif /* GLX_SGIX_dmbuffer */ + +#ifndef GLX_SGIX_fbconfig +#define GLX_SGIX_fbconfig 1 +typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; +#define GLX_WINDOW_BIT_SGIX 0x00000001 +#define GLX_PIXMAP_BIT_SGIX 0x00000002 +#define GLX_RGBA_BIT_SGIX 0x00000001 +#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002 +#define GLX_DRAWABLE_TYPE_SGIX 0x8010 +#define GLX_RENDER_TYPE_SGIX 0x8011 +#define GLX_X_RENDERABLE_SGIX 0x8012 +#define GLX_FBCONFIG_ID_SGIX 0x8013 +#define GLX_RGBA_TYPE_SGIX 0x8014 +#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015 +typedef int ( *PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); +typedef GLXFBConfigSGIX *( *PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements); +typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); +typedef GLXContext ( *PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); +typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config); +typedef GLXFBConfigSGIX ( *PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); +GLXFBConfigSGIX *glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements); +GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); +GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); +XVisualInfo *glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config); +GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis); +#endif +#endif /* GLX_SGIX_fbconfig */ + +#ifndef GLX_SGIX_hyperpipe +#define GLX_SGIX_hyperpipe 1 +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int networkId; +} GLXHyperpipeNetworkSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int channel; + unsigned int participationType; + int timeSlice; +} GLXHyperpipeConfigSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int srcXOrigin, srcYOrigin, srcWidth, srcHeight; + int destXOrigin, destYOrigin, destWidth, destHeight; +} GLXPipeRect; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int XOrigin, YOrigin, maxHeight, maxWidth; +} GLXPipeRectLimits; +#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 +#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 +#define GLX_BAD_HYPERPIPE_SGIX 92 +#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 +#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 +#define GLX_PIPE_RECT_SGIX 0x00000001 +#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 +#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003 +#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 +#define GLX_HYPERPIPE_ID_SGIX 0x8030 +typedef GLXHyperpipeNetworkSGIX *( *PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes); +typedef int ( *PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); +typedef GLXHyperpipeConfigSGIX *( *PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes); +typedef int ( *PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId); +typedef int ( *PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId); +typedef int ( *PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); +typedef int ( *PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList); +typedef int ( *PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXHyperpipeNetworkSGIX *glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes); +int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); +GLXHyperpipeConfigSGIX *glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes); +int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId); +int glXBindHyperpipeSGIX (Display *dpy, int hpId); +int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); +int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList); +int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); +#endif +#endif /* GLX_SGIX_hyperpipe */ + +#ifndef GLX_SGIX_pbuffer +#define GLX_SGIX_pbuffer 1 +#define GLX_PBUFFER_BIT_SGIX 0x00000004 +#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 +#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 +#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 +#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 +#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 +#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 +#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 +#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 +#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 +#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 +#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 +#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 +#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 +#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 +#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A +#define GLX_PRESERVED_CONTENTS_SGIX 0x801B +#define GLX_LARGEST_PBUFFER_SGIX 0x801C +#define GLX_WIDTH_SGIX 0x801D +#define GLX_HEIGHT_SGIX 0x801E +#define GLX_EVENT_MASK_SGIX 0x801F +#define GLX_DAMAGED_SGIX 0x8020 +#define GLX_SAVED_SGIX 0x8021 +#define GLX_WINDOW_SGIX 0x8022 +#define GLX_PBUFFER_SGIX 0x8023 +typedef GLXPbufferSGIX ( *PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); +typedef void ( *PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf); +typedef int ( *PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); +typedef void ( *PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask); +typedef void ( *PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); +void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf); +int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); +void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask); +void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask); +#endif +#endif /* GLX_SGIX_pbuffer */ + +#ifndef GLX_SGIX_swap_barrier +#define GLX_SGIX_swap_barrier 1 +typedef void ( *PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier); +typedef Bool ( *PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier); +Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max); +#endif +#endif /* GLX_SGIX_swap_barrier */ + +#ifndef GLX_SGIX_swap_group +#define GLX_SGIX_swap_group 1 +typedef void ( *PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member); +#endif +#endif /* GLX_SGIX_swap_group */ + +#ifndef GLX_SGIX_video_resize +#define GLX_SGIX_video_resize 1 +#define GLX_SYNC_FRAME_SGIX 0x00000000 +#define GLX_SYNC_SWAP_SGIX 0x00000001 +typedef int ( *PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window); +typedef int ( *PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h); +typedef int ( *PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); +typedef int ( *PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); +typedef int ( *PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window); +int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h); +int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); +int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); +int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype); +#endif +#endif /* GLX_SGIX_video_resize */ + +#ifndef GLX_SGIX_video_source +#define GLX_SGIX_video_source 1 +typedef XID GLXVideoSourceSGIX; +#ifdef _VL_H +typedef GLXVideoSourceSGIX ( *PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); +typedef void ( *PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); +void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource); +#endif +#endif /* _VL_H */ +#endif /* GLX_SGIX_video_source */ + +#ifndef GLX_SGIX_visual_select_group +#define GLX_SGIX_visual_select_group 1 +#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 +#endif /* GLX_SGIX_visual_select_group */ + +#ifndef GLX_SGI_cushion +#define GLX_SGI_cushion 1 +typedef void ( *PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCushionSGI (Display *dpy, Window window, float cushion); +#endif +#endif /* GLX_SGI_cushion */ + +#ifndef GLX_SGI_make_current_read +#define GLX_SGI_make_current_read 1 +typedef Bool ( *PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +GLXDrawable glXGetCurrentReadDrawableSGI (void); +#endif +#endif /* GLX_SGI_make_current_read */ + +#ifndef GLX_SGI_swap_control +#define GLX_SGI_swap_control 1 +typedef int ( *PFNGLXSWAPINTERVALSGIPROC) (int interval); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXSwapIntervalSGI (int interval); +#endif +#endif /* GLX_SGI_swap_control */ + +#ifndef GLX_SGI_video_sync +#define GLX_SGI_video_sync 1 +typedef int ( *PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count); +typedef int ( *PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXGetVideoSyncSGI (unsigned int *count); +int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count); +#endif +#endif /* GLX_SGI_video_sync */ + +#ifndef GLX_SUN_get_transparent_index +#define GLX_SUN_get_transparent_index 1 +typedef Status ( *PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); +#ifdef GLX_GLXEXT_PROTOTYPES +Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); +#endif +#endif /* GLX_SUN_get_transparent_index */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/renderdoc/driver/gl/official/wglext.h b/renderdoc/driver/gl/official/wglext.h new file mode 100644 index 0000000000..e9648c37ce --- /dev/null +++ b/renderdoc/driver/gl/official/wglext.h @@ -0,0 +1,833 @@ +#ifndef __wglext_h_ +#define __wglext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2014 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision: 26290 $ on $Date: 2014-04-16 05:35:38 -0700 (Wed, 16 Apr 2014) $ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#define WGL_WGLEXT_VERSION 20140416 + +/* Generated C header for: + * API: wgl + * Versions considered: .* + * Versions emitted: _nomatch_^ + * Default extensions included: wgl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef WGL_ARB_buffer_region +#define WGL_ARB_buffer_region 1 +#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 +#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 +#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 +#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 +typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); +typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); +typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); +typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#ifdef WGL_WGLEXT_PROTOTYPES +HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType); +VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion); +BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height); +BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#endif +#endif /* WGL_ARB_buffer_region */ + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define ERROR_INVALID_VERSION_ARB 0x2095 +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); +#ifdef WGL_WGLEXT_PROTOTYPES +HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList); +#endif +#endif /* WGL_ARB_create_context */ + +#ifndef WGL_ARB_create_context_profile +#define WGL_ARB_create_context_profile 1 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif /* WGL_ARB_create_context_profile */ + +#ifndef WGL_ARB_create_context_robustness +#define WGL_ARB_create_context_robustness 1 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* WGL_ARB_create_context_robustness */ + +#ifndef WGL_ARB_extensions_string +#define WGL_ARB_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringARB (HDC hdc); +#endif +#endif /* WGL_ARB_extensions_string */ + +#ifndef WGL_ARB_framebuffer_sRGB +#define WGL_ARB_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#endif /* WGL_ARB_framebuffer_sRGB */ + +#ifndef WGL_ARB_make_current_read +#define WGL_ARB_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCARB (void); +#endif +#endif /* WGL_ARB_make_current_read */ + +#ifndef WGL_ARB_multisample +#define WGL_ARB_multisample 1 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif /* WGL_ARB_multisample */ + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 +DECLARE_HANDLE(HPBUFFERARB); +#define WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define WGL_PBUFFER_LARGEST_ARB 0x2033 +#define WGL_PBUFFER_WIDTH_ARB 0x2034 +#define WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define WGL_PBUFFER_LOST_ARB 0x2036 +typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer); +int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer); +BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_ARB_pbuffer */ + +#ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format 1 +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_ARB_pixel_format */ + +#ifndef WGL_ARB_pixel_format_float +#define WGL_ARB_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#endif /* WGL_ARB_pixel_format_float */ + +#ifndef WGL_ARB_render_texture +#define WGL_ARB_render_texture 1 +#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +#define WGL_TEXTURE_FORMAT_ARB 0x2072 +#define WGL_TEXTURE_TARGET_ARB 0x2073 +#define WGL_MIPMAP_TEXTURE_ARB 0x2074 +#define WGL_TEXTURE_RGB_ARB 0x2075 +#define WGL_TEXTURE_RGBA_ARB 0x2076 +#define WGL_NO_TEXTURE_ARB 0x2077 +#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +#define WGL_TEXTURE_1D_ARB 0x2079 +#define WGL_TEXTURE_2D_ARB 0x207A +#define WGL_MIPMAP_LEVEL_ARB 0x207B +#define WGL_CUBE_MAP_FACE_ARB 0x207C +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +#define WGL_FRONT_LEFT_ARB 0x2083 +#define WGL_FRONT_RIGHT_ARB 0x2084 +#define WGL_BACK_LEFT_ARB 0x2085 +#define WGL_BACK_RIGHT_ARB 0x2086 +#define WGL_AUX0_ARB 0x2087 +#define WGL_AUX1_ARB 0x2088 +#define WGL_AUX2_ARB 0x2089 +#define WGL_AUX3_ARB 0x208A +#define WGL_AUX4_ARB 0x208B +#define WGL_AUX5_ARB 0x208C +#define WGL_AUX6_ARB 0x208D +#define WGL_AUX7_ARB 0x208E +#define WGL_AUX8_ARB 0x208F +#define WGL_AUX9_ARB 0x2090 +typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList); +#endif +#endif /* WGL_ARB_render_texture */ + +#ifndef WGL_ARB_robustness_application_isolation +#define WGL_ARB_robustness_application_isolation 1 +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* WGL_ARB_robustness_application_isolation */ + +#ifndef WGL_ARB_robustness_share_group_isolation +#define WGL_ARB_robustness_share_group_isolation 1 +#endif /* WGL_ARB_robustness_share_group_isolation */ + +#ifndef WGL_3DFX_multisample +#define WGL_3DFX_multisample 1 +#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 +#define WGL_SAMPLES_3DFX 0x2061 +#endif /* WGL_3DFX_multisample */ + +#ifndef WGL_3DL_stereo_control +#define WGL_3DL_stereo_control 1 +#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 +typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState); +#endif +#endif /* WGL_3DL_stereo_control */ + +#ifndef WGL_AMD_gpu_association +#define WGL_AMD_gpu_association 1 +#define WGL_GPU_VENDOR_AMD 0x1F00 +#define WGL_GPU_RENDERER_STRING_AMD 0x1F01 +#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define WGL_GPU_RAM_AMD 0x21A3 +#define WGL_GPU_CLOCK_AMD 0x21A4 +#define WGL_GPU_NUM_PIPES_AMD 0x21A5 +#define WGL_GPU_NUM_SIMD_AMD 0x21A6 +#define WGL_GPU_NUM_RB_AMD 0x21A7 +#define WGL_GPU_NUM_SPI_AMD 0x21A8 +typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); +typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data); +typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); +typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); +typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); +typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef WGL_WGLEXT_PROTOTYPES +UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids); +INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data); +UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc); +HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id); +HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList); +BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc); +BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc); +HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void); +VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* WGL_AMD_gpu_association */ + +#ifndef WGL_ATI_pixel_format_float +#define WGL_ATI_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#endif /* WGL_ATI_pixel_format_float */ + +#ifndef WGL_EXT_create_context_es2_profile +#define WGL_EXT_create_context_es2_profile 1 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es2_profile */ + +#ifndef WGL_EXT_create_context_es_profile +#define WGL_EXT_create_context_es_profile 1 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es_profile */ + +#ifndef WGL_EXT_depth_float +#define WGL_EXT_depth_float 1 +#define WGL_DEPTH_FLOAT_EXT 0x2040 +#endif /* WGL_EXT_depth_float */ + +#ifndef WGL_EXT_display_color_table +#define WGL_EXT_display_color_table 1 +typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); +typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); +#ifdef WGL_WGLEXT_PROTOTYPES +GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id); +GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length); +GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id); +VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id); +#endif +#endif /* WGL_EXT_display_color_table */ + +#ifndef WGL_EXT_extensions_string +#define WGL_EXT_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringEXT (void); +#endif +#endif /* WGL_EXT_extensions_string */ + +#ifndef WGL_EXT_framebuffer_sRGB +#define WGL_EXT_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif /* WGL_EXT_framebuffer_sRGB */ + +#ifndef WGL_EXT_make_current_read +#define WGL_EXT_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCEXT (void); +#endif +#endif /* WGL_EXT_make_current_read */ + +#ifndef WGL_EXT_multisample +#define WGL_EXT_multisample 1 +#define WGL_SAMPLE_BUFFERS_EXT 0x2041 +#define WGL_SAMPLES_EXT 0x2042 +#endif /* WGL_EXT_multisample */ + +#ifndef WGL_EXT_pbuffer +#define WGL_EXT_pbuffer 1 +DECLARE_HANDLE(HPBUFFEREXT); +#define WGL_DRAW_TO_PBUFFER_EXT 0x202D +#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E +#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 +#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 +#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 +#define WGL_PBUFFER_LARGEST_EXT 0x2033 +#define WGL_PBUFFER_WIDTH_EXT 0x2034 +#define WGL_PBUFFER_HEIGHT_EXT 0x2035 +typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer); +int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer); +BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_EXT_pbuffer */ + +#ifndef WGL_EXT_pixel_format +#define WGL_EXT_pixel_format 1 +#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 +#define WGL_DRAW_TO_WINDOW_EXT 0x2001 +#define WGL_DRAW_TO_BITMAP_EXT 0x2002 +#define WGL_ACCELERATION_EXT 0x2003 +#define WGL_NEED_PALETTE_EXT 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 +#define WGL_SWAP_METHOD_EXT 0x2007 +#define WGL_NUMBER_OVERLAYS_EXT 0x2008 +#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 +#define WGL_TRANSPARENT_EXT 0x200A +#define WGL_TRANSPARENT_VALUE_EXT 0x200B +#define WGL_SHARE_DEPTH_EXT 0x200C +#define WGL_SHARE_STENCIL_EXT 0x200D +#define WGL_SHARE_ACCUM_EXT 0x200E +#define WGL_SUPPORT_GDI_EXT 0x200F +#define WGL_SUPPORT_OPENGL_EXT 0x2010 +#define WGL_DOUBLE_BUFFER_EXT 0x2011 +#define WGL_STEREO_EXT 0x2012 +#define WGL_PIXEL_TYPE_EXT 0x2013 +#define WGL_COLOR_BITS_EXT 0x2014 +#define WGL_RED_BITS_EXT 0x2015 +#define WGL_RED_SHIFT_EXT 0x2016 +#define WGL_GREEN_BITS_EXT 0x2017 +#define WGL_GREEN_SHIFT_EXT 0x2018 +#define WGL_BLUE_BITS_EXT 0x2019 +#define WGL_BLUE_SHIFT_EXT 0x201A +#define WGL_ALPHA_BITS_EXT 0x201B +#define WGL_ALPHA_SHIFT_EXT 0x201C +#define WGL_ACCUM_BITS_EXT 0x201D +#define WGL_ACCUM_RED_BITS_EXT 0x201E +#define WGL_ACCUM_GREEN_BITS_EXT 0x201F +#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 +#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 +#define WGL_DEPTH_BITS_EXT 0x2022 +#define WGL_STENCIL_BITS_EXT 0x2023 +#define WGL_AUX_BUFFERS_EXT 0x2024 +#define WGL_NO_ACCELERATION_EXT 0x2025 +#define WGL_GENERIC_ACCELERATION_EXT 0x2026 +#define WGL_FULL_ACCELERATION_EXT 0x2027 +#define WGL_SWAP_EXCHANGE_EXT 0x2028 +#define WGL_SWAP_COPY_EXT 0x2029 +#define WGL_SWAP_UNDEFINED_EXT 0x202A +#define WGL_TYPE_RGBA_EXT 0x202B +#define WGL_TYPE_COLORINDEX_EXT 0x202C +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_EXT_pixel_format */ + +#ifndef WGL_EXT_pixel_format_packed_float +#define WGL_EXT_pixel_format_packed_float 1 +#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#endif /* WGL_EXT_pixel_format_packed_float */ + +#ifndef WGL_EXT_swap_control +#define WGL_EXT_swap_control 1 +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSwapIntervalEXT (int interval); +int WINAPI wglGetSwapIntervalEXT (void); +#endif +#endif /* WGL_EXT_swap_control */ + +#ifndef WGL_EXT_swap_control_tear +#define WGL_EXT_swap_control_tear 1 +#endif /* WGL_EXT_swap_control_tear */ + +#ifndef WGL_I3D_digital_video_control +#define WGL_I3D_digital_video_control 1 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 +#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 +#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 +typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue); +#endif +#endif /* WGL_I3D_digital_video_control */ + +#ifndef WGL_I3D_gamma +#define WGL_I3D_gamma 1 +#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E +#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue); +BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#endif +#endif /* WGL_I3D_gamma */ + +#ifndef WGL_I3D_genlock +#define WGL_I3D_genlock 1 +#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 +#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 +#define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047 +#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 +#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 +#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A +#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B +#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C +typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); +typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); +typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableGenlockI3D (HDC hDC); +BOOL WINAPI wglDisableGenlockI3D (HDC hDC); +BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag); +BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource); +BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource); +BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge); +BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge); +BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate); +BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate); +BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay); +BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay); +BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#endif +#endif /* WGL_I3D_genlock */ + +#ifndef WGL_I3D_image_buffer +#define WGL_I3D_image_buffer 1 +#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 +typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); +typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); +typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); +#ifdef WGL_WGLEXT_PROTOTYPES +LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags); +BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress); +BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count); +#endif +#endif /* WGL_I3D_image_buffer */ + +#ifndef WGL_I3D_swap_frame_lock +#define WGL_I3D_swap_frame_lock 1 +typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableFrameLockI3D (void); +BOOL WINAPI wglDisableFrameLockI3D (void); +BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag); +BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag); +#endif +#endif /* WGL_I3D_swap_frame_lock */ + +#ifndef WGL_I3D_swap_frame_usage +#define WGL_I3D_swap_frame_usage 1 +typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); +typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetFrameUsageI3D (float *pUsage); +BOOL WINAPI wglBeginFrameTrackingI3D (void); +BOOL WINAPI wglEndFrameTrackingI3D (void); +BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif +#endif /* WGL_I3D_swap_frame_usage */ + +#ifndef WGL_NV_DX_interop +#define WGL_NV_DX_interop 1 +#define WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 +typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); +typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); +typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); +typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); +typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle); +HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice); +BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice); +HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject); +BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access); +BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +#endif +#endif /* WGL_NV_DX_interop */ + +#ifndef WGL_NV_DX_interop2 +#define WGL_NV_DX_interop2 1 +#endif /* WGL_NV_DX_interop2 */ + +#ifndef WGL_NV_copy_image +#define WGL_NV_copy_image 1 +typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* WGL_NV_copy_image */ + +#ifndef WGL_NV_delay_before_swap +#define WGL_NV_delay_before_swap 1 +typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds); +#endif +#endif /* WGL_NV_delay_before_swap */ + +#ifndef WGL_NV_float_buffer +#define WGL_NV_float_buffer 1 +#define WGL_FLOAT_COMPONENTS_NV 0x20B0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 +#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#endif /* WGL_NV_float_buffer */ + +#ifndef WGL_NV_gpu_affinity +#define WGL_NV_gpu_affinity 1 +DECLARE_HANDLE(HGPUNV); +struct _GPU_DEVICE { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD Flags; + RECT rcVirtualScreen; +}; +typedef struct _GPU_DEVICE *PGPU_DEVICE; +#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 +#define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 +typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); +typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); +typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu); +BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList); +BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +BOOL WINAPI wglDeleteDCNV (HDC hdc); +#endif +#endif /* WGL_NV_gpu_affinity */ + +#ifndef WGL_NV_multisample_coverage +#define WGL_NV_multisample_coverage 1 +#define WGL_COVERAGE_SAMPLES_NV 0x2042 +#define WGL_COLOR_SAMPLES_NV 0x20B9 +#endif /* WGL_NV_multisample_coverage */ + +#ifndef WGL_NV_present_video +#define WGL_NV_present_video 1 +DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); +#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 +typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); +BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue); +#endif +#endif /* WGL_NV_present_video */ + +#ifndef WGL_NV_render_depth_texture +#define WGL_NV_render_depth_texture 1 +#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +#define WGL_DEPTH_COMPONENT_NV 0x20A7 +#endif /* WGL_NV_render_depth_texture */ + +#ifndef WGL_NV_render_texture_rectangle +#define WGL_NV_render_texture_rectangle 1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 +#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 +#endif /* WGL_NV_render_texture_rectangle */ + +#ifndef WGL_NV_swap_group +#define WGL_NV_swap_group 1 +typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); +typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); +typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); +typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); +typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group); +BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier); +BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier); +BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count); +BOOL WINAPI wglResetFrameCountNV (HDC hDC); +#endif +#endif /* WGL_NV_swap_group */ + +#ifndef WGL_NV_vertex_array_range +#define WGL_NV_vertex_array_range 1 +typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); +#ifdef WGL_WGLEXT_PROTOTYPES +void *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +void WINAPI wglFreeMemoryNV (void *pointer); +#endif +#endif /* WGL_NV_vertex_array_range */ + +#ifndef WGL_NV_video_capture +#define WGL_NV_video_capture 1 +DECLARE_HANDLE(HVIDEOINPUTDEVICENV); +#define WGL_UNIQUE_ID_NV 0x20CE +#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#endif +#endif /* WGL_NV_video_capture */ + +#ifndef WGL_NV_video_output +#define WGL_NV_video_output 1 +DECLARE_HANDLE(HPVIDEODEV); +#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 +#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 +#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 +#define WGL_VIDEO_OUT_COLOR_NV 0x20C3 +#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 +#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 +#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define WGL_VIDEO_OUT_FRAME 0x20C8 +#define WGL_VIDEO_OUT_FIELD_1 0x20C9 +#define WGL_VIDEO_OUT_FIELD_2 0x20CA +#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB +#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC +typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); +typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice); +BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#endif +#endif /* WGL_NV_video_output */ + +#ifndef WGL_OML_sync_control +#define WGL_OML_sync_control 1 +typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); +typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator); +INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#endif +#endif /* WGL_OML_sync_control */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/renderdoc/hooks/d3d11_hooks.cpp b/renderdoc/hooks/d3d11_hooks.cpp new file mode 100644 index 0000000000..4db0669420 --- /dev/null +++ b/renderdoc/hooks/d3d11_hooks.cpp @@ -0,0 +1,353 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/d3d11/d3d11_device.h" + +#include "driver/dxgi/dxgi_wrapped.h" +#include "hooks.h" + +#define DLL_NAME "d3d11.dll" + +class D3D11Hook : LibraryHook +{ +public: + D3D11Hook() { LibraryHooks::GetInstance().RegisterHook(DLL_NAME, this); m_EnabledHooks = true; m_InsideCreate = false; } + + bool CreateHooks(const char *libName) + { + bool success = true; + + // require dxgi.dll hooked as well for proper operation + if(GetModuleHandleA("dxgi.dll") == NULL) + { + RDCWARN("Failed to load dxgi.dll - not inserting D3D11 hooks."); + return false; + } + + // also require d3dcompiler_??.dll + if(GetD3DCompiler() == NULL) + { + RDCERR("Failed to load d3dcompiler_??.dll - not inserting D3D11 hooks."); + return false; + } + + success &= CreateDevice.Initialize("D3D11CreateDevice", DLL_NAME, D3D11CreateDevice_hook); + success &= CreateDeviceAndSwapChain.Initialize("D3D11CreateDeviceAndSwapChain", DLL_NAME, D3D11CreateDeviceAndSwapChain_hook); + + if(!success) return false; + + // FRAPS compatibility. Save out the first 16 bytes (arbitrary number) of the 'real' function code. + // this should be + // jmp D3D11CreateDeviceAndSwapChain_hook + // push r12 <- this is where our trampoline jumps back to + // push r13 + // + // FRAPS stomps over this with its own hook that we detect and handle later. + void *hooked_func_ptr = GetProcAddress(GetModuleHandleA("d3d11.dll"), "D3D11CreateDeviceAndSwapChain"); + if(hooked_func_ptr == NULL) return false; + memcpy(CreateDeviceAndSwapChain_ident, hooked_func_ptr, 16); + + m_HasHooks = true; + m_EnabledHooks = true; + + return true; + } + + void EnableHooks(const char *libName, bool enable) + { + m_EnabledHooks = enable; + } + + bool UseHooks() + { + return (d3d11hooks.m_HasHooks && d3d11hooks.m_EnabledHooks); + } + + static HRESULT CreateWrappedDeviceAndSwapChain( + __in_opt IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + __in_opt CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + __out_opt IDXGISwapChain** ppSwapChain, + __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, + __out_opt ID3D11DeviceContext** ppImmediateContext ) + { + return d3d11hooks.Create_Internal(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + } + +private: + static D3D11Hook d3d11hooks; + + bool m_HasHooks; + bool m_EnabledHooks; + + byte CreateDeviceAndSwapChain_ident[16]; + Hook CreateDeviceAndSwapChain; + Hook CreateDevice; + + // re-entrancy detection (can happen in rare cases with e.g. fraps) + bool m_InsideCreate; + + HRESULT Create_Internal( + __in_opt IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + __in_opt CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + __out_opt IDXGISwapChain** ppSwapChain, + __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, + __out_opt ID3D11DeviceContext** ppImmediateContext ) + { + // if we're already inside a wrapped create i.e. this function, then DON'T do anything + // special. Just grab the trampolined function and call it. + if(m_InsideCreate) + { + PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN createFunc = NULL; + + // shouldn't ever get in here if we're in the case without hooks but let's be safe. + if(m_HasHooks) + createFunc = CreateDeviceAndSwapChain(); + else + createFunc = (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(GetModuleHandleA("d3d11.dll"), "D3D11CreateDeviceAndSwapChain"); + + return createFunc(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + + } + + m_InsideCreate = true; + + RDCDEBUG("Call to Create_Internal Flags %x", Flags); + + bool reading = RenderDoc::Inst().IsReplayApp(); + + if(reading) + { + RDCDEBUG("In replay app"); + } + + if(m_EnabledHooks) + { + if(!reading && RenderDoc::Inst().GetCaptureOptions().DebugDeviceMode) + { + Flags |= D3D11_CREATE_DEVICE_DEBUG; + } + else + { + Flags &= ~D3D11_CREATE_DEVICE_DEBUG; + } + } + + DXGI_SWAP_CHAIN_DESC swapDesc; + DXGI_SWAP_CHAIN_DESC *pUsedSwapDesc = NULL; + + if(pSwapChainDesc) + { + swapDesc = *pSwapChainDesc; + pUsedSwapDesc = &swapDesc; + } + + if(pUsedSwapDesc && m_EnabledHooks && !RenderDoc::Inst().GetCaptureOptions().AllowFullscreen) + { + pUsedSwapDesc->Windowed = TRUE; + } + + RDCDEBUG("Calling real createdevice..."); + + PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN createFunc = (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(GetModuleHandleA("d3d11.dll"), "D3D11CreateDeviceAndSwapChain"); + + if(createFunc) + { + byte ident[16]; + memcpy(ident, createFunc, 16); + + // FRAPS compatibility. If FRAPS has come in and modified the real code to something like + // mov rax, [ptrintofraps] + // jmp rax + // then we just jump straight there. If we jump to the trampoline, we'll come in half way through + // those instructions and things will go boom very quickly. + // + // Note that when we call this function FRAPS then restores the asm from before it got here, which is our + // trampolined code, so FRAPS is going to call back into this function. We detect this re-entrancy + // at the top and just go straight into the real d3d function now that FRAPS has restored our trampoline, + // and return right back here + // What a headache! + // + // in the non-fraps case no-one else has messed with this code so the idents will be the same and we + // will use our trampolines. + + if(!memcmp(ident, CreateDeviceAndSwapChain_ident, 16) && m_HasHooks) + createFunc = CreateDeviceAndSwapChain(); + } + + // shouldn't ever get here, we should either have it from procaddress or the trampoline, but let's be + // safe. + if(createFunc == NULL) + { + RDCERR("Something went seriously wrong with the hooks!"); + + m_InsideCreate = false; + + return E_UNEXPECTED; + } + + HRESULT ret = createFunc(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, pUsedSwapDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + + RDCDEBUG("Called real createdevice..."); + + bool suppress = (Flags & D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY) != 0; + + if(suppress && !reading) + { + RDCDEBUG("Application requested not to be hooked."); + } + else if(SUCCEEDED(ret) && m_EnabledHooks && ppDevice) + { + RDCDEBUG("succeeded and hooking."); + + if(!WrappedID3D11Device::IsAlloc(*ppDevice)) + { + D3D11InitParams *params = new D3D11InitParams; + params->DriverType = DriverType; + params->Flags = Flags; + params->SDKVersion = SDKVersion; + params->NumFeatureLevels = FeatureLevels; + if(FeatureLevels > 0) + memcpy(params->FeatureLevels, pFeatureLevels, sizeof(D3D_FEATURE_LEVEL)*FeatureLevels); + + WrappedID3D11Device *wrap = new WrappedID3D11Device(*ppDevice, params); + + RDCDEBUG("created wrapped device."); + + *ppDevice = wrap; + wrap->GetImmediateContext(ppImmediateContext); + + if(ppSwapChain && *ppSwapChain) + *ppSwapChain = new WrappedIDXGISwapChain(*ppSwapChain, wrap); + } + } + else if(SUCCEEDED(ret)) + { + RDCDEBUG("succeeded."); + } + else + { + RDCDEBUG("failed. 0x%08x", ret); + } + + m_InsideCreate = false; + + return ret; + } + + static HRESULT WINAPI D3D11CreateDevice_hook( + __in_opt IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, + __out_opt ID3D11DeviceContext** ppImmediateContext ) + { + HRESULT ret = d3d11hooks.Create_Internal( + pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, NULL, NULL, ppDevice, pFeatureLevel, ppImmediateContext); + + return ret; + } + + static HRESULT WINAPI D3D11CreateDeviceAndSwapChain_hook( + __in_opt IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + __in_opt CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + __out_opt IDXGISwapChain** ppSwapChain, + __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, + __out_opt ID3D11DeviceContext** ppImmediateContext ) + { + HRESULT ret = d3d11hooks.Create_Internal( + pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + + return ret; + } +}; + +D3D11Hook D3D11Hook::d3d11hooks; + +extern "C" __declspec(dllexport) +HRESULT __cdecl RENDERDOC_CreateWrappedD3D11DeviceAndSwapChain( + __in_opt IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + __in_opt CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + __out_opt IDXGISwapChain** ppSwapChain, + __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, + __out_opt ID3D11DeviceContext** ppImmediateContext ) +{ + return D3D11Hook::CreateWrappedDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); +} + +extern "C" __declspec(dllexport) +HRESULT __cdecl RENDERDOC_CreateWrappedD3D11Device( + __in_opt IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + __in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, + __out_opt ID3D11DeviceContext** ppImmediateContext ) +{ + return D3D11Hook::CreateWrappedDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, NULL, NULL, ppDevice, pFeatureLevel, ppImmediateContext); +} diff --git a/renderdoc/hooks/d3d9_hooks.cpp b/renderdoc/hooks/d3d9_hooks.cpp new file mode 100644 index 0000000000..ab29669fbf --- /dev/null +++ b/renderdoc/hooks/d3d9_hooks.cpp @@ -0,0 +1,142 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include + +#include "driver/d3d11/d3d11_device.h" + +#include "hooks.h" + +#define DLL_NAME "d3d9.dll" + +typedef int (WINAPI* PFN_BEGIN_EVENT)( DWORD, WCHAR* ); +typedef int (WINAPI* PFN_END_EVENT)( ); +typedef int (WINAPI* PFN_SET_MARKER_EVENT)( DWORD, WCHAR* ); +typedef void (WINAPI* PFN_SET_OPTIONS)( DWORD ); +typedef DWORD (WINAPI* PFN_GET_OPTIONS)( ); + +typedef IDirect3D9* (WINAPI* PFN_D3D9_CREATE)( UINT ); + +class D3D9Hook : LibraryHook +{ + public: + D3D9Hook() { LibraryHooks::GetInstance().RegisterHook(DLL_NAME, this); m_EnabledHooks = true; } + + bool CreateHooks(const char *libName) + { + bool success = true; + + success &= PERF_BeginEvent.Initialize("D3DPERF_BeginEvent", DLL_NAME, PERF_BeginEvent_hook); + success &= PERF_EndEvent.Initialize("D3DPERF_EndEvent", DLL_NAME, PERF_EndEvent_hook); + success &= PERF_SetMarker.Initialize("D3DPERF_SetMarker", DLL_NAME, PERF_SetMarker_hook); + success &= PERF_SetOptions.Initialize("D3DPERF_SetOptions", DLL_NAME, PERF_SetOptions_hook); + success &= PERF_GetStatus.Initialize("D3DPERF_GetStatus", DLL_NAME, PERF_GetStatus_hook); + + success &= Create9.Initialize("Direct3DCreate9", DLL_NAME, Create9_hook); + + if(!success) return false; + + m_HasHooks = true; + m_EnabledHooks = true; + + return true; + } + + void EnableHooks(const char *libName, bool enable) + { + m_EnabledHooks = enable; + } + + private: + static D3D9Hook d3d9hooks; + + bool m_HasHooks; + bool m_EnabledHooks; + + // D3DPERF api + Hook PERF_BeginEvent; + Hook PERF_EndEvent; + Hook PERF_SetMarker; + Hook PERF_SetOptions; + Hook PERF_GetStatus; + Hook Create9; + + static int WINAPI PERF_BeginEvent_hook(DWORD col, WCHAR *wszName) + { + int ret = WrappedID3D11Device::BeginEvent((uint32_t)col, wszName); + + d3d9hooks.PERF_BeginEvent()(col, wszName); + + return ret; + } + + static int WINAPI PERF_EndEvent_hook() + { + int ret = WrappedID3D11Device::EndEvent(); + + d3d9hooks.PERF_EndEvent()(); + + return ret; + } + + static void WINAPI PERF_SetMarker_hook(DWORD col, WCHAR *wszName) + { + WrappedID3D11Device::SetMarker((uint32_t)col, wszName); + + d3d9hooks.PERF_SetMarker()(col, wszName); + } + + static void WINAPI PERF_SetOptions_hook(DWORD dwOptions) + { + if(dwOptions & 1) + { + RDCDEBUG("Application requested not to be hooked."); + LibraryHooks::GetInstance().EnableHooks(false); + } + else + { + LibraryHooks::GetInstance().EnableHooks(true); + } + } + + static DWORD WINAPI PERF_GetStatus_hook() + { + if(d3d9hooks.m_HasHooks && d3d9hooks.m_EnabledHooks) + { + return 1; + } + + return 0; + } + + static IDirect3D9* WINAPI Create9_hook(UINT SDKVersion) + { + RDCWARN("App creating d3d9 %x device - not hooked!", SDKVersion); + + return d3d9hooks.Create9()(SDKVersion); + } +}; + +D3D9Hook D3D9Hook::d3d9hooks; \ No newline at end of file diff --git a/renderdoc/hooks/dxgi_hooks.cpp b/renderdoc/hooks/dxgi_hooks.cpp new file mode 100644 index 0000000000..35b78a67d9 --- /dev/null +++ b/renderdoc/hooks/dxgi_hooks.cpp @@ -0,0 +1,124 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + + +#include "driver/dxgi/dxgi_wrapped.h" +#include "hooks.h" + +#define DLL_NAME "dxgi.dll" + +typedef HRESULT (WINAPI* PFN_CREATE_DXGI_FACTORY)( __in REFIID, __out void **ppFactory); + +class DXGIHook : LibraryHook +{ +public: + DXGIHook() { LibraryHooks::GetInstance().RegisterHook(DLL_NAME, this); m_EnabledHooks = true; } + + bool CreateHooks(const char *libName) + { + bool success = true; + + // require d3d11.dll hooked as well for proper operation + if(GetModuleHandleA("d3d11.dll") == NULL) return false; + + success &= CreateDXGIFactory.Initialize("CreateDXGIFactory", DLL_NAME, CreateDXGIFactory_hook); + success &= CreateDXGIFactory1.Initialize("CreateDXGIFactory1", DLL_NAME, CreateDXGIFactory1_hook); + + if(!success) return false; + + m_HasHooks = true; + m_EnabledHooks = true; + + return true; + } + + void EnableHooks(const char *libName, bool enable) + { + m_EnabledHooks = enable; + } + + bool UseHooks() + { + return (dxgihooks.m_HasHooks && dxgihooks.m_EnabledHooks); + } + + static HRESULT CreateWrappedFactory1(REFIID riid, void **ppFactory) + { + if(dxgihooks.m_HasHooks) + return dxgihooks.CreateDXGIFactory1_hook(riid, ppFactory); + + PFN_CREATE_DXGI_FACTORY createFunc = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(GetModuleHandleA("dxgi.dll"), "CreateDXGIFactory1"); + + if(!createFunc) + { + RDCERR("Trying to create hooked dxgi factory without dxgi loaded"); + return E_INVALIDARG; + } + + HRESULT ret = createFunc(riid, ppFactory); + + if(SUCCEEDED(ret)) + RefCountDXGIObject::HandleWrap(riid, ppFactory); + + return ret; + } + +private: + static DXGIHook dxgihooks; + + bool m_HasHooks; + bool m_EnabledHooks; + + Hook CreateDXGIFactory; + Hook CreateDXGIFactory1; + + static HRESULT WINAPI CreateDXGIFactory_hook(__in REFIID riid, __out void **ppFactory) + { + HRESULT ret = dxgihooks.CreateDXGIFactory()(riid, ppFactory); + + if(SUCCEEDED(ret) && dxgihooks.m_EnabledHooks) + RefCountDXGIObject::HandleWrap(riid, ppFactory); + + return ret; + } + + static HRESULT WINAPI CreateDXGIFactory1_hook(__in REFIID riid, __out void **ppFactory) + { + HRESULT ret = dxgihooks.CreateDXGIFactory1()(riid, ppFactory); + + if(SUCCEEDED(ret) && dxgihooks.m_EnabledHooks) + RefCountDXGIObject::HandleWrap(riid, ppFactory); + + return ret; + } +}; + +DXGIHook DXGIHook::dxgihooks; + +extern "C" __declspec(dllexport) +HRESULT __cdecl RENDERDOC_CreateWrappedDXGIFactory1(__in REFIID riid, __out void **ppFactory) +{ + return DXGIHook::CreateWrappedFactory1(riid, ppFactory); +} diff --git a/renderdoc/hooks/gl_linux_hooks.cpp b/renderdoc/hooks/gl_linux_hooks.cpp new file mode 100644 index 0000000000..051506f5f0 --- /dev/null +++ b/renderdoc/hooks/gl_linux_hooks.cpp @@ -0,0 +1,395 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include +#include + +#include "hooks/hooks.h" + +#include "driver/gl/gl_common.h" +#include "driver/gl/gl_hookset.h" +#include "driver/gl/gl_driver.h" + +#include "common/string_utils.h" + +// bit of a hack +namespace Keyboard { extern Display *CurrentXDisplay; } + +typedef GLXContext (*PFNGLXCREATECONTEXTPROC)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +typedef const char *(*PFNGLXQUERYEXTENSIONSSTRING)(Display *dpy, int screen); +typedef Bool (*PFNGLXMAKECURRENTPROC)(Display *dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (*PFNGLXSWAPBUFFERSPROC)(Display *dpy, GLXDrawable drawable); + +#define HookInit(function) \ + GL.function = (CONCAT(function, _hooktype))dlsym(RTLD_NEXT, STRINGIZE(function)); + +#define HookExtension(funcPtrType, function) \ + if(!strcmp(func, STRINGIZE(function))) \ + { \ + OpenGLHook::glhooks.GL.function = (funcPtrType)realFunc; \ + return (__GLXextFuncPtr)&function; \ + } + +#define HookExtensionAlias(funcPtrType, function, alias) \ + if(!strcmp(func, STRINGIZE(alias))) \ + { \ + OpenGLHook::glhooks.GL.function = (funcPtrType)realFunc; \ + return (__GLXextFuncPtr)&function; \ + } + +/* + in bash: + + function HookWrapper() + { + N=$1; + echo -n "#define HookWrapper$N(ret, function"; + for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done; + echo ") \\"; + + echo -en "\ttypedef ret (*CONCAT(function, _hooktype)) ("; + for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo "); \\"; + + echo -e "\textern \"C\" __attribute__ ((visibility (\"default\"))) \\"; + + echo -en "\tret function("; + for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo ") \\"; + + echo -en "\t{ return OpenGLHook::glhooks.GetDriver()->function("; + for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo -n "); }"; + } + + for I in `seq 0 ...`; do HookWrapper $I; echo; done + + */ + +#define HookWrapper0(ret, function) \ + typedef ret (*CONCAT(function, _hooktype)) (); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function() \ + { return OpenGLHook::glhooks.GetDriver()->function(); } +#define HookWrapper1(ret, function, t1, p1) \ + typedef ret (*CONCAT(function, _hooktype)) (t1); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1); } +#define HookWrapper2(ret, function, t1, p1, t2, p2) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2); } +#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3); } +#define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4); } +#define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5); } +#define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6); } +#define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7); } +#define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8); } +#define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10) \ + typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ + extern "C" __attribute__ ((visibility ("default"))) \ + ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) \ + { return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } + + +class OpenGLHook : LibraryHook +{ + public: + OpenGLHook() + { + LibraryHooks::GetInstance().RegisterHook("libGL.so", this); + + // TODO: need to check against implementation to ensure we don't claim to support + // an extension that it doesn't! + + glXExts.push_back("GLX_ARB_extensions_string"); + //glXExts.push_back("GLX_ARB_multisample"); + glXExts.push_back("GLX_ARB_create_context"); + glXExts.push_back("GLX_ARB_create_context_profile"); + + merge(glXExts, glXExtsString, ' '); + + m_GLDriver = NULL; + + m_EnabledHooks = true; + m_PopulatedHooks = false; + } + ~OpenGLHook() + { + delete m_GLDriver; + } + + bool CreateHooks(const char *libName) + { + RDCEraseEl(GL); + + if(!m_EnabledHooks) + return false; + + bool success = SetupHooks(GL); + + if(!success) return false; + + m_HasHooks = true; + + return true; + } + + void EnableHooks(const char *libName, bool enable) + { + m_EnabledHooks = enable; + } + + static OpenGLHook glhooks; + + const GLHookSet &GetRealFunctions() + { + if(!m_PopulatedHooks) + m_PopulatedHooks = PopulateHooks(); + return GL; + } + + WrappedOpenGL *GetDriver() + { + if(m_GLDriver == NULL) + m_GLDriver = new WrappedOpenGL(L"", GL); + + return m_GLDriver; + } + + PFNGLXCREATECONTEXTPROC glXCreateContext_real; + PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB_real; + PFNGLXGETPROCADDRESSPROC glXGetProcAddress_real; + PFNGLXMAKECURRENTPROC glXMakeCurrent_real; + PFNGLXSWAPBUFFERSPROC glXSwapBuffers_real; + + WrappedOpenGL *m_GLDriver; + + GLHookSet GL; + + vector glXExts; + string glXExtsString; + + bool m_PopulatedHooks; + bool m_HasHooks; + bool m_EnabledHooks; + + bool SetupHooks(GLHookSet &GL); + bool PopulateHooks(); +}; + +DefineDLLExportHooks(); +DefineGLExtensionHooks(); + +typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display *dpy, GLXFBConfig config); +typedef int (*PFNGLXGETCONFIGPROC)(Display *dpy, XVisualInfo *vis, int attrib, int * value); + +static PFNGLXGETCONFIGPROC getVisualInfoAttrib = NULL; + +__attribute__ ((visibility ("default"))) +GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct) +{ + GLXContext ret = OpenGLHook::glhooks.glXCreateContext_real(dpy, vis, shareList, direct); + + GLInitParams init; + + init.width = 0; + init.height = 0; + + int value = 0; + + if(Keyboard::CurrentXDisplay == NULL) Keyboard::CurrentXDisplay = dpy; + if(getVisualInfoAttrib == NULL) getVisualInfoAttrib = (PFNGLXGETCONFIGPROC)dlsym(RTLD_NEXT, "glXGetConfig"); + + getVisualInfoAttrib(dpy, vis, GLX_BUFFER_SIZE, &value); init.colorBits = value; + getVisualInfoAttrib(dpy, vis, GLX_DEPTH_SIZE, &value); init.depthBits = value; + getVisualInfoAttrib(dpy, vis, GLX_STENCIL_SIZE, &value); init.stencilBits = value; + + OpenGLHook::glhooks.GetDriver()->CreateContext(NULL, ret, shareList, init); + + return ret; +} + +__attribute__ ((visibility ("default"))) +GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, GLXContext shareList, Bool direct, const int *attribList) +{ + GLXContext ret = OpenGLHook::glhooks.glXCreateContextAttribsARB_real(dpy, config, shareList, direct, attribList); + + PFNGLXGETVISUALFROMFBCONFIGPROC getVisual = (PFNGLXGETVISUALFROMFBCONFIGPROC)dlsym(RTLD_NEXT, "glXGetVisualFromFBConfig"); + XVisualInfo *vis = getVisual(dpy, config); + + GLInitParams init; + + init.width = 0; + init.height = 0; + + int value = 0; + + if(Keyboard::CurrentXDisplay == NULL) Keyboard::CurrentXDisplay = dpy; + if(getVisualInfoAttrib == NULL) getVisualInfoAttrib = (PFNGLXGETCONFIGPROC)dlsym(RTLD_NEXT, "glXGetConfig"); + + getVisualInfoAttrib(dpy, vis, GLX_BUFFER_SIZE, &value); init.colorBits = value; + getVisualInfoAttrib(dpy, vis, GLX_DEPTH_SIZE, &value); init.depthBits = value; + getVisualInfoAttrib(dpy, vis, GLX_STENCIL_SIZE, &value); init.stencilBits = value; + + XFree(vis); + + OpenGLHook::glhooks.GetDriver()->CreateContext(NULL, ret, shareList, init); + + return ret; +} + +__attribute__ ((visibility ("default"))) +Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) +{ + Bool ret = OpenGLHook::glhooks.glXMakeCurrent_real(dpy, drawable, ctx); + + OpenGLHook::glhooks.GetDriver()->ActivateContext((void *)drawable, ctx); + + return ret; +} + +__attribute__ ((visibility ("default"))) +void glXSwapBuffers(Display *dpy, GLXDrawable drawable) +{ + Window root; + int x, y; + unsigned int width, height, border_width, depth; + XGetGeometry(dpy, drawable, &root, &x, &y, &width, &height, &border_width, &depth); + + OpenGLHook::glhooks.GetDriver()->WindowSize((void *)drawable, width, height); + + OpenGLHook::glhooks.GetDriver()->Present((void *)drawable); + + OpenGLHook::glhooks.glXSwapBuffers_real(dpy, drawable); +} + +__attribute__ ((visibility ("default"))) +const char *glXQueryExtensionsString(Display *dpy, int screen) +{ +#if !defined(_RELEASE) + PFNGLXQUERYEXTENSIONSSTRING glXGetExtStr = (PFNGLXQUERYEXTENSIONSSTRING)dlsym(RTLD_NEXT, "glXQueryExtensionsString"); + string realExtsString = glXGetExtStr(dpy, screen); + vector realExts; + split(realExtsString, realExts, ' '); +#endif + return OpenGLHook::glhooks.glXExtsString.c_str(); +} + +bool OpenGLHook::SetupHooks(GLHookSet &GL) +{ + bool success = true; + + glXGetProcAddress_real = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress"); + glXCreateContext_real = (PFNGLXCREATECONTEXTPROC)dlsym(RTLD_NEXT, "glXCreateContext"); + glXCreateContextAttribsARB_real = (PFNGLXCREATECONTEXTATTRIBSARBPROC)dlsym(RTLD_NEXT, "glXCreateContextAttribsARB"); + glXMakeCurrent_real = (PFNGLXMAKECURRENTPROC)dlsym(RTLD_NEXT, "glXMakeCurrent"); + glXSwapBuffers_real = (PFNGLXSWAPBUFFERSPROC)dlsym(RTLD_NEXT, "glXSwapBuffers"); + + DLLExportHooks(); + + return success; +} + +__attribute__ ((visibility ("default"))) +__GLXextFuncPtr glXGetProcAddress(const GLubyte *f) +{ + __GLXextFuncPtr realFunc = OpenGLHook::glhooks.glXGetProcAddress_real(f); + const char *func = (const char *)f; + + // if the real RC doesn't support this function, don't bother hooking + if(realFunc == NULL) + return realFunc; + + if(!strcmp(func, "glXCreateContextAttribsARB")) + { + OpenGLHook::glhooks.glXCreateContextAttribsARB_real = (PFNGLXCREATECONTEXTATTRIBSARBPROC)realFunc; + return (__GLXextFuncPtr)&glXCreateContextAttribsARB; + } + + HookCheckGLExtensions(); + + // claim not to know this extension! + RDCWARN("Claiming not to know extension that is available - %s", func); + return NULL; +} + +bool OpenGLHook::PopulateHooks() +{ + bool success = true; + + if(glXGetProcAddress_real == NULL) + glXGetProcAddress_real = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress"); + + glXGetProcAddress_real((const GLubyte *)"glXCreateContextAttribsARB"); + +#undef HookInit +#define HookInit(function) if(GL.function == NULL) GL.function = (CONCAT(function, _hooktype))dlsym(RTLD_NEXT, "glXGetProcAddress"); + + // cheeky +#undef HookExtension +#define HookExtension(funcPtrType, function) glXGetProcAddress((const GLubyte *)STRINGIZE(function)) +#undef HookExtensionAlias +#define HookExtensionAlias(funcPtrType, function, alias) + + DLLExportHooks(); + HookCheckGLExtensions(); + + return true; +} + +OpenGLHook OpenGLHook::glhooks; + +const GLHookSet &GetRealFunctions() { return OpenGLHook::glhooks.GetRealFunctions(); } \ No newline at end of file diff --git a/renderdoc/hooks/gl_win32_hooks.cpp b/renderdoc/hooks/gl_win32_hooks.cpp new file mode 100644 index 0000000000..d86d3e15da --- /dev/null +++ b/renderdoc/hooks/gl_win32_hooks.cpp @@ -0,0 +1,411 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "driver/gl/gl_common.h" +#include "driver/gl/gl_hookset.h" +#include "driver/gl/gl_driver.h" + +#include "common/string_utils.h" + +#include "hooks.h" + +#define DLL_NAME "opengl32.dll" + +#define HookInit(function) \ + success &= CONCAT(function, _hook).Initialize(STRINGIZE(function), DLL_NAME, CONCAT(function, _hooked)); \ + GL.function = CONCAT(function, _hook)(); + +#define HookExtension(funcPtrType, function) \ + if(!strcmp(func, STRINGIZE(function))) \ + { \ + glhooks.GL.function = (funcPtrType)realFunc; \ + return (PROC)&glhooks.CONCAT(function,_hooked); \ + } + +#define HookExtensionAlias(funcPtrType, function, alias) \ + if(!strcmp(func, STRINGIZE(alias))) \ + { \ + glhooks.GL.function = (funcPtrType)realFunc; \ + return (PROC)&glhooks.CONCAT(function,_hooked); \ + } + +/* + in bash: + + function HookWrapper() + { + N=$1; + echo -n "#define HookWrapper$N(ret, function"; + for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done; + echo ") \\"; + + echo -en "\tHook CONCAT(function, _hook); \\"; + + echo -en "\ttypedef ret (WINAPI *CONCAT(function, _hooktype)) ("; + for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo "); \\"; + + echo -en "\tstatic ret WINAPI CONCAT(function, _hooked)("; + for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo ") \\"; + + echo -en "\t{ return glhooks.GetDriver()->function("; + for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo -n "); }"; + } + + for I in `seq 0 ...`; do HookWrapper $I; echo; done + + */ + +#define HookWrapper0(ret, function) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (); \ + static ret WINAPI CONCAT(function, _hooked)() \ + { return glhooks.GetDriver()->function(); } + +#define HookWrapper1(ret, function, t1, p1) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1) \ + { return glhooks.GetDriver()->function(p1); } + +#define HookWrapper2(ret, function, t1, p1, t2, p2) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \ + { return glhooks.GetDriver()->function(p1, p2); } + +#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \ + { return glhooks.GetDriver()->function(p1, p2, p3); } + +#define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4); } + +#define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4, p5); } + +#define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6); } + +#define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7); } + +#define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8); } + +#define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); } + +#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10) \ + Hook CONCAT(function, _hook); \ + typedef ret (WINAPI *CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) \ + { return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } + +class OpenGLHook : LibraryHook +{ + public: + OpenGLHook() + { + LibraryHooks::GetInstance().RegisterHook(DLL_NAME, this); + + // TODO: need to check against implementation to ensure we don't claim to support + // an extension that it doesn't! + + wglExts.push_back("WGL_ARB_extensions_string"); + //wglExts.push_back("WGL_ARB_multisample"); + wglExts.push_back("WGL_ARB_create_context"); + wglExts.push_back("WGL_ARB_create_context_profile"); + + merge(wglExts, wglExtsString, ' '); + + m_GLDriver = NULL; + + m_EnabledHooks = true; + m_PopulatedHooks = false; + } + ~OpenGLHook() + { + delete m_GLDriver; + } + + bool CreateHooks(const char *libName) + { + RDCEraseEl(GL); + + if(!m_EnabledHooks) + return false; + + bool success = SetupHooks(GL); + + if(!success) return false; + + m_HasHooks = true; + + return true; + } + + void EnableHooks(const char *libName, bool enable) + { + m_EnabledHooks = enable; + } + + static OpenGLHook glhooks; + + const GLHookSet &GetRealFunctions() + { + if(!m_PopulatedHooks) + m_PopulatedHooks = PopulateHooks(); + return GL; + } + + private: + WrappedOpenGL *GetDriver() + { + if(m_GLDriver == NULL) + m_GLDriver = new WrappedOpenGL(L"", GL); + + return m_GLDriver; + } + + Hook wglCreateContext_hook; + Hook wglMakeCurrent_hook; + Hook wglGetProcAddress_hook; + Hook SwapBuffers_hook; + + PROC (WINAPI* wglGetProcAddress_realfunc)(const char*); + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB_realfunc; + + static private GLInitParams GetInitParamsForDC(HDC dc) + { + GLInitParams ret; + + int pf = GetPixelFormat(dc); + + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(dc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + HWND w = WindowFromDC(dc); + + RECT r; + GetClientRect(w, &r); + + RDCLOG("dc %p. PFD: type %d, %d color bits, %d depth bits, %d stencil bits. Win: %dx%d", + dc, + pfd.iPixelType, pfd.cColorBits, pfd.cDepthBits, pfd.cStencilBits, + r.right-r.left, r.bottom-r.top); + + ret.colorBits = pfd.cColorBits; + ret.depthBits = pfd.cDepthBits; + ret.stencilBits = pfd.cStencilBits; + ret.width = (r.right-r.left); + ret.height = (r.bottom-r.top); + + if(pfd.iPixelType != PFD_TYPE_RGBA) + { + RDCERR("Unsupported OpenGL pixel type"); + } + + return ret; + } + + static HGLRC WINAPI wglCreateContext_hooked(HDC dc) + { + HGLRC ret = glhooks.wglCreateContext_hook()(dc); + + glhooks.GetDriver()->CreateContext(WindowFromDC(dc), ret, NULL, GetInitParamsForDC(dc)); + + return ret; + } + + static HGLRC WINAPI wglCreateContextAttribsARB_hooked(HDC dc, HGLRC hShareContext, const int *attribList) + { + HGLRC ret = glhooks.wglCreateContextAttribsARB_realfunc(dc, hShareContext, attribList); + + glhooks.GetDriver()->CreateContext(WindowFromDC(dc), ret, hShareContext, GetInitParamsForDC(dc)); + + return ret; + } + + // wglShareLists_hooked ? + + static BOOL WINAPI wglMakeCurrent_hooked(HDC dc, HGLRC rc) + { + BOOL ret = glhooks.wglMakeCurrent_hook()(dc, rc); + + glhooks.GetDriver()->ActivateContext(WindowFromDC(dc), rc); + + return ret; + } + + static BOOL WINAPI SwapBuffers_hooked(HDC dc) + { + HWND w = WindowFromDC(dc); + + RECT r; + GetClientRect(w, &r); + + glhooks.GetDriver()->WindowSize(w, r.right-r.left, r.bottom-r.top); + + glhooks.GetDriver()->Present(dc); + + return glhooks.SwapBuffers_hook()(dc); + } + + static const char * WINAPI wglGetExtensionsStringARB_hooked(HDC dc) + { +#if !defined(_RELEASE) + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtStrARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)glhooks.wglGetProcAddress_realfunc("wglGetExtensionsStringARB"); + string realExtsString = wglGetExtStrARB(dc); + vector realExts; + split(realExtsString, realExts, ' '); +#endif + return glhooks.wglExtsString.c_str(); + } + static const char * WINAPI wglGetExtensionsStringEXT_hooked() + { +#if !defined(_RELEASE) + PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtStrEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)glhooks.wglGetProcAddress_realfunc("wglGetExtensionsStringEXT"); + string realExtsString = wglGetExtStrEXT(); + vector realExts; + split(realExtsString, realExts, ' '); +#endif + return glhooks.wglExtsString.c_str(); + } + + static PROC WINAPI wglGetProcAddress_hooked(const char *func) + { + PROC realFunc = glhooks.wglGetProcAddress_realfunc(func); + + // if the real RC doesn't support this function, don't bother hooking + if(realFunc == NULL) + return realFunc; + + if(!strcmp(func, "wglGetExtensionsStringEXT")) + { + return (PROC)&wglGetExtensionsStringEXT_hooked; + } + if(!strcmp(func, "wglGetExtensionsStringARB")) + { + return (PROC)&wglGetExtensionsStringARB_hooked; + } + if(!strcmp(func, "wglCreateContextAttribsARB")) + { + glhooks.wglCreateContextAttribsARB_realfunc = (PFNWGLCREATECONTEXTATTRIBSARBPROC)realFunc; + return (PROC)&wglCreateContextAttribsARB_hooked; + } + + HookCheckWGLExtensions(); + HookCheckGLExtensions(); + + // claim not to know this extension! + RDCWARN("Claiming not to know extension that is available - %hs", func); + return NULL; + } + + WrappedOpenGL *m_GLDriver; + + GLHookSet GL; + + vector wglExts; + string wglExtsString; + + bool m_PopulatedHooks; + bool m_HasHooks; + bool m_EnabledHooks; + + bool SetupHooks(GLHookSet &GL) + { + bool success = true; + + success &= wglCreateContext_hook.Initialize("wglCreateContext", DLL_NAME, wglCreateContext_hooked); + success &= wglMakeCurrent_hook.Initialize("wglMakeCurrent", DLL_NAME, wglMakeCurrent_hooked); + success &= wglGetProcAddress_hook.Initialize("wglGetProcAddress", DLL_NAME, wglGetProcAddress_hooked); + success &= SwapBuffers_hook.Initialize("SwapBuffers", "gdi32.dll", SwapBuffers_hooked); + + wglGetProcAddress_realfunc = wglGetProcAddress_hook(); + + DLLExportHooks(); + + return success; + } + + bool PopulateHooks() + { + bool success = true; + + if(wglGetProcAddress_realfunc == NULL) + wglGetProcAddress_realfunc = (PROC (WINAPI*)(const char*))Process::GetFunctionAddress(DLL_NAME, "wglGetProcAddress"); + + wglGetProcAddress_hooked("wglCreateContextAttribsARB"); + +#undef HookInit +#define HookInit(function) if(GL.function == NULL) GL.function = (CONCAT(function, _hooktype)) Process::GetFunctionAddress(DLL_NAME, STRINGIZE(function)); + + // cheeky +#undef HookExtension +#define HookExtension(funcPtrType, function) wglGetProcAddress_hooked(STRINGIZE(function)) +#undef HookExtensionAlias +#define HookExtensionAlias(funcPtrType, function, alias) + + DLLExportHooks(); + HookCheckWGLExtensions(); + HookCheckGLExtensions(); + + return true; + } + + DefineDLLExportHooks(); + DefineWGLExtensionHooks(); + DefineGLExtensionHooks(); +}; + +OpenGLHook OpenGLHook::glhooks; + +const GLHookSet &GetRealFunctions() { return OpenGLHook::glhooks.GetRealFunctions(); } diff --git a/renderdoc/hooks/hooks.cpp b/renderdoc/hooks/hooks.cpp new file mode 100644 index 0000000000..9f34e899f0 --- /dev/null +++ b/renderdoc/hooks/hooks.cpp @@ -0,0 +1,68 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" +#include "hooks.h" + +LibraryHooks &LibraryHooks::GetInstance() +{ + static LibraryHooks instance; + return instance; +} + +void LibraryHooks::RegisterHook(const char *libName, LibraryHook *hook) +{ + m_Hooks[libName] = hook; +} + +void LibraryHooks::CreateHooks() +{ + HOOKS_BEGIN(); + for(auto it=m_Hooks.begin(); it!=m_Hooks.end(); ++it) + { + RDCDEBUG("Attempting to hook %hs", it->first); + + if(it->second->CreateHooks(it->first)) + { + RDCLOG("Loaded and hooked into %hs, PID %d", it->first, Process::GetCurrentPID()); + } + else + { + RDCWARN("Couldn't hook into %hs", it->first); + } + } + HOOKS_END(); +} + +void LibraryHooks::EnableHooks(bool enable) +{ + RDCDEBUG("%hs hooks!", enable ? "Enabling" : "Disabling"); + + if(!enable) + return; + + for(auto it=m_Hooks.begin(); it!=m_Hooks.end(); ++it) + it->second->EnableHooks(it->first, enable); +} diff --git a/renderdoc/hooks/hooks.h b/renderdoc/hooks/hooks.h new file mode 100644 index 0000000000..86a336ba15 --- /dev/null +++ b/renderdoc/hooks/hooks.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + + +#pragma once + +#include +using std::map; + +#include "os/os_specific.h" + +// include os-specific hooking mechanisms here + +#if defined(WIN32) + +#include "3rdparty/mhook/mhook-lib/mhook.h" + +template +class Hook +{ + public: + Hook() { trampoline = NULL; } + ~Hook() { Mhook_Unhook(&trampoline); } + + FuncType operator()() + { + return (FuncType)trampoline; + } + + bool Initialize(const char *function, const char *module_name, void *destination_function_ptr) + { + trampoline = Process::GetFunctionAddress(module_name, function); + + if(trampoline == NULL) + return false; + + return Mhook_SetHook(&trampoline, destination_function_ptr); + } + + private: + void* trampoline; +}; + +#define HOOKS_BEGIN() Mhook_SuspendOtherThreads() +#define HOOKS_END() Mhook_ResumeOtherThreads() + +#elif defined(LINUX) + +// just need this for dlsym +#include + +#define HOOKS_BEGIN() +#define HOOKS_END() + +#else + +#error "undefined platform" + +#endif + +// defines the interface that a library hooking class will implement. +// the libName is the name they used when registering +struct LibraryHook +{ + virtual bool CreateHooks(const char *libName) = 0; + virtual void EnableHooks(const char *libName, bool enable) = 0; +}; + +// this singleton allows you to compile in code that defines a hook for a given library +// (and it will be registered). Then when the renderdoc library is initialised in the target +// program CreateHooks() will be called to set up the hooks. +class LibraryHooks +{ + public: + static LibraryHooks &GetInstance(); + void RegisterHook(const char *libName, LibraryHook *hook); + void CreateHooks(); + void EnableHooks(bool enable); + + private: + typedef map HookMap; + + HookMap m_Hooks; +}; diff --git a/renderdoc/hooks/linux_libentry.cpp b/renderdoc/hooks/linux_libentry.cpp new file mode 100644 index 0000000000..b5cb8c79e3 --- /dev/null +++ b/renderdoc/hooks/linux_libentry.cpp @@ -0,0 +1,55 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "core/core.h" +#include "hooks/hooks.h" +#include "os/os_specific.h" + +// DllMain equivalent +__attribute__((constructor)) +void library_loaded() +{ + wstring curfile; + FileIO::GetExecutableFilename(curfile); + + if(curfile.find(L"/renderdoccmd") != wstring::npos || + curfile.find(L"/renderdocui") != wstring::npos) + { + RDCDEBUG("Not creating hooks - in replay app"); + + RenderDoc::Inst().SetReplayApp(true); + + RenderDoc::Inst().Initialise(); + + return; + } + else + { + RenderDoc::Inst().Initialise(); + + RDCLOG("Loading into %S", curfile.c_str()); + + LibraryHooks::GetInstance().CreateHooks(); + } +} diff --git a/renderdoc/hooks/sys_win32_hooks.cpp b/renderdoc/hooks/sys_win32_hooks.cpp new file mode 100644 index 0000000000..fe3ffd9e78 --- /dev/null +++ b/renderdoc/hooks/sys_win32_hooks.cpp @@ -0,0 +1,196 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "core/core.h" +#include "replay/renderdoc.h" + +#include "hooks.h" + +#define DLL_NAME "kernel32.dll" + +typedef BOOL (WINAPI *PFN_CREATE_PROCESS_A)( + __in_opt LPCSTR lpApplicationName, + __inout_opt LPSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCSTR lpCurrentDirectory, + __in LPSTARTUPINFOA lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation + ); + +typedef BOOL (WINAPI *PFN_CREATE_PROCESS_W)( + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation + ); + +class SysHook : LibraryHook +{ + public: + SysHook() { LibraryHooks::GetInstance().RegisterHook(DLL_NAME, this); m_EnabledHooks = true; } + + bool CreateHooks(const char *libName) + { + bool success = true; + + // we want to hook CreateProcess purely so that we can recursively insert our hooks (if we so wish) + success &= CreateProcessA.Initialize("CreateProcessA", DLL_NAME, CreateProcessA_hook); + success &= CreateProcessW.Initialize("CreateProcessW", DLL_NAME, CreateProcessW_hook); + + if(!success) return false; + + m_HasHooks = true; + m_EnabledHooks = true; + + return true; + } + + void EnableHooks(const char *libName, bool enable) + { + m_EnabledHooks = enable; + } + + private: + static SysHook syshooks; + + bool m_HasHooks; + bool m_EnabledHooks; + + // D3DPERF api + Hook CreateProcessA; + Hook CreateProcessW; + + static BOOL WINAPI CreateProcessA_hook( + __in_opt LPCSTR lpApplicationName, + __inout_opt LPSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCSTR lpCurrentDirectory, + __in LPSTARTUPINFOA lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) + { + PROCESS_INFORMATION dummy; + RDCEraseEl(dummy); + + // not sure if this is valid, but I need the PID so I'll fill in my own struct to ensure that. + if(lpProcessInformation == NULL) + { + lpProcessInformation = &dummy; + } + + dwCreationFlags |= CREATE_SUSPENDED; + + BOOL ret = syshooks.CreateProcessA()(lpApplicationName, lpCommandLine, + lpProcessAttributes, lpThreadAttributes, + bInheritHandles, dwCreationFlags, + lpEnvironment, lpCurrentDirectory, lpStartupInfo, + lpProcessInformation); + + if(RenderDoc::Inst().GetCaptureOptions().HookIntoChildren) + { + RDCDEBUG("Intercepting CreateProcessA"); + + // inherit logfile and capture options + RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, + RenderDoc::Inst().GetLogFile(), &RenderDoc::Inst().GetCaptureOptions(), false); + } + + ResumeThread(lpProcessInformation->hThread); + + // ensure we clean up after ourselves + if(dummy.dwProcessId != 0) + { + CloseHandle(dummy.hProcess); + CloseHandle(dummy.hThread); + } + + return ret; + } + + static BOOL WINAPI CreateProcessW_hook( + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) + { + PROCESS_INFORMATION dummy; + RDCEraseEl(dummy); + + // not sure if this is valid, but I need the PID so I'll fill in my own struct to ensure that. + if(lpProcessInformation == NULL) + { + lpProcessInformation = &dummy; + } + + dwCreationFlags |= CREATE_SUSPENDED; + + BOOL ret = syshooks.CreateProcessW()(lpApplicationName, lpCommandLine, + lpProcessAttributes, lpThreadAttributes, + bInheritHandles, dwCreationFlags, + lpEnvironment, lpCurrentDirectory, lpStartupInfo, + lpProcessInformation); + + if(RenderDoc::Inst().GetCaptureOptions().HookIntoChildren) + { + RDCDEBUG("Intercepting CreateProcessW"); + + // inherit logfile and capture options + RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, + RenderDoc::Inst().GetLogFile(), &RenderDoc::Inst().GetCaptureOptions(), false); + } + + ResumeThread(lpProcessInformation->hThread); + + // ensure we clean up after ourselves + if(dummy.dwProcessId != 0) + { + CloseHandle(dummy.hProcess); + CloseHandle(dummy.hThread); + } + + return ret; + } +}; + +SysHook SysHook::syshooks; \ No newline at end of file diff --git a/renderdoc/hooks/win32_libentry.cpp b/renderdoc/hooks/win32_libentry.cpp new file mode 100644 index 0000000000..b5b91d8c15 --- /dev/null +++ b/renderdoc/hooks/win32_libentry.cpp @@ -0,0 +1,120 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +// win32_libentry.cpp : Defines the entry point for the DLL +#include +#include + +#include "common/common.h" +#include "common/string_utils.h" +#include "hooks/hooks.h" + +#include "core/core.h" + +void shutdown() +{ +} + +BOOL add_hooks() +{ + wchar_t curFile[512]; + GetModuleFileNameW(NULL, curFile, 512); + + wstring f = strlower(wstring(curFile)); + + // bail immediately if we're in a system process. We don't want to hook, log, anything - + // this instance is being used for a shell extension. + if(f.find(L"dllhost.exe") != wstring::npos || + f.find(L"explorer.exe") != wstring::npos) + { +#ifndef _RELEASE + OutputDebugStringA("Hosting renderdoc.dll in shell process\n"); +#endif + return TRUE; + } + + if(f.find(L"renderdoccmd.exe") != wstring::npos || + f.find(L"renderdocui.exe") != wstring::npos) + { + RDCDEBUG("Not creating hooks - in replay app"); + + RenderDoc::Inst().SetReplayApp(true); + + RenderDoc::Inst().Initialise(); + + return true; + } + + RenderDoc::Inst().Initialise(); + + RDCLOG("Loading into %ls", curFile); + + const wchar_t *appFilter = NULL; //L"MyApplication"; + + if(appFilter != NULL) + { + if(wcsstr(curFile, appFilter) == 0) + { + RDCDEBUG("Not app I want. Exiting"); + return TRUE; + } + } + + LibraryHooks::GetInstance().CreateHooks(); + + return TRUE; +} + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + return add_hooks(); + break; + } + case DLL_THREAD_ATTACH: + { + int thread_attach=0; + break; + } + case DLL_THREAD_DETACH: + { + int thread_detach=0; + break; + } + case DLL_PROCESS_DETACH: + { + shutdown(); + break; + } + } + return TRUE; +} + diff --git a/renderdoc/maths/camera.cpp b/renderdoc/maths/camera.cpp new file mode 100644 index 0000000000..47658908f0 --- /dev/null +++ b/renderdoc/maths/camera.cpp @@ -0,0 +1,76 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include + +#include "camera.h" +#include "matrix.h" + +void Camera::Arcball(float dist, Vec3f rot) +{ + pos = Vec3f(0.0f, 0.0f, dist); + + order = ORDER_ROT_TRANS; + + angles.x = rot.x; + angles.y = rot.y; +} + +void Camera::fpsLook(Vec3f p, Vec3f rot) +{ + pos = -p; + + angles.x = -rot.x; + angles.y = -rot.y; + + order = ORDER_TRANS_ROT; +} + +const Matrix4f Camera::GetMatrix() +{ + Matrix4f p = Matrix4f::Translation(pos); + Matrix4f r = Matrix4f::RotationXYZ(angles); + + if(order == ORDER_TRANS_ROT) + return r.Mul(p); + + return p.Mul(r); +} + +const Vec3f Camera::GetPosition() +{ + return GetMatrix().GetPosition(); +} + +const Vec3f Camera::GetForward() +{ + return Matrix4f::RotationZYX(-angles).GetForward(); +} + +const Vec3f Camera::GetRight() +{ + return Matrix4f::RotationZYX(-angles).GetRight(); +} diff --git a/renderdoc/maths/camera.h b/renderdoc/maths/camera.h new file mode 100644 index 0000000000..3186c8cbe3 --- /dev/null +++ b/renderdoc/maths/camera.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "vec.h" + +class Matrix4f; + +class Camera +{ + public: + Camera() + : order(ORDER_TRANS_ROT), pos(), angles() + { } + + void Arcball(float dist, Vec3f rot); + void fpsLook(Vec3f pos, Vec3f rot); + + void SetPosition(const Vec3f &p) { pos = p; } + void SetAngles(const Vec3f &r) { angles = r; } + + const Vec3f GetPosition(); + const Vec3f GetForward(); + const Vec3f GetRight(); + const Vec3f GetUp(); + const Matrix4f GetMatrix(); + + private: + enum OperationOrder + { + ORDER_ROT_TRANS = 0, + ORDER_TRANS_ROT, + } order; + + Vec3f pos; + Vec3f angles; +}; diff --git a/renderdoc/maths/formatpacking.h b/renderdoc/maths/formatpacking.h new file mode 100644 index 0000000000..d5e335d069 --- /dev/null +++ b/renderdoc/maths/formatpacking.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +#include "vec.h" + +inline Vec4f ConvertFromR10G10B10A2(uint32_t data) +{ + return Vec4f( float((data>> 0) & 0x3ff) / 1023.0f, + float((data>>10) & 0x3ff) / 1023.0f, + float((data>>20) & 0x3ff) / 1023.0f, + float((data>>30) & 0x003) / 3.0f + ); +} + +inline uint32_t ConvertToR10G10B10A2(Vec4f data) +{ + float x = data.x < 1.0f ? (data.x > 0.0f ? data.x : 0.0f) : 1.0f; + float y = data.y < 1.0f ? (data.y > 0.0f ? data.y : 0.0f) : 1.0f; + float z = data.z < 1.0f ? (data.z > 0.0f ? data.z : 0.0f) : 1.0f; + float w = data.w < 1.0f ? (data.w > 0.0f ? data.w : 0.0f) : 1.0f; + + return (uint32_t(x*1023)<< 0) | + (uint32_t(y*1023)<<10) | + (uint32_t(z*1023)<<20) | + (uint32_t(w*3) <<30) ; +} + +inline Vec3f ConvertFromR11G11B10(uint32_t data) +{ + uint32_t xMantissa = ((data>> 0) & 0x3f); + uint32_t xExponent = ((data>> 6) & 0x1f); + uint32_t yMantissa = ((data>>11) & 0x3f); + uint32_t yExponent = ((data>>17) & 0x1f); + uint32_t zMantissa = ((data>>22) & 0x1f); + uint32_t zExponent = ((data>>27) & 0x1f); + + return Vec3f((float(xMantissa)/64.0f)*powf(2.0f, (float)xExponent - 15.0f), + (float(yMantissa)/32.0f)*powf(2.0f, (float)yExponent - 15.0f), + (float(zMantissa)/32.0f)*powf(2.0f, (float)zExponent - 15.0f)); +} + +/* +inline uint32_t ConvertToR11G11B10(Vec3f data) +{ + return 0; +} +*/ + +inline Vec4f ConvertFromB5G5R5A1(uint16_t data) +{ + return Vec4f( (float)((data >> 0) & 0x1f) / 31.0f, + (float)((data >> 5) & 0x1f) / 31.0f, + (float)((data >> 10) & 0x1f) / 31.0f, + ((data & 0x8000) > 0) ? 1.0f : 0.0f ); +} + +inline Vec3f ConvertFromB5G6R5(uint16_t data) +{ + return Vec3f( (float)((data >> 0) & 0x1f) / 31.0f, + (float)((data >> 5) & 0x3f) / 63.0f, + (float)((data >> 11) & 0x1f) / 31.0f ); +} + +inline Vec4f ConvertFromB4G4R4A4(uint16_t data) +{ + return Vec4f( (float)((data >> 0) & 0xf) / 15.0f, + (float)((data >> 4) & 0xf) / 15.0f, + (float)((data >> 8) & 0xf) / 15.0f, + (float)((data >> 12) & 0xf) / 15.0f ); +} + +#include "half_convert.h" + diff --git a/renderdoc/maths/half_convert.h b/renderdoc/maths/half_convert.h new file mode 100644 index 0000000000..b6f63d59c8 --- /dev/null +++ b/renderdoc/maths/half_convert.h @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Industrial Light & Magic nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#pragma once + +inline uint16_t ConvertToHalf(float comp) +{ + int *alias = (int *)∁ + int i = *alias; + + int sign = (i >> 16) & 0x00008000; + int exponent = ((i >> 23) & 0x000000ff) - (127 - 15); + int mantissa = i & 0x007fffff; + + if(exponent <= 0) + { + if(exponent < -10) + return sign&0xffff; + + mantissa |= 0x00800000; + + int t = 14 - exponent; + int a = (1 << (t - 1)) - 1; + int b = (mantissa >> t) & 1; + + mantissa = (mantissa + a + b) >> t; + + return (sign | mantissa)&0xffff; + } + else if (exponent == 0xff - (127 - 15)) + { + if(mantissa == 0) + return (sign | 0x7c00)&0xffff; + + mantissa >>= 13; + return (sign | 0x7c00 | mantissa | (mantissa == 0))&0xffff; + } + else + { + mantissa = mantissa + 0x00000fff + ((mantissa >> 13) & 1); + + if(mantissa & 0x00800000) + { + mantissa = 0; + exponent += 1; + } + + if(exponent > 30) + { + return (sign | 0x7c00)&0xffff; + } + + return (sign | (exponent << 10) | (mantissa >> 13))&0xffff; + } +} + +inline float ConvertFromHalf(uint16_t comp) +{ + bool sign = (comp & 0x8000) != 0; + int exponent = (comp & 0x7C00) >> 10; + int mantissa = comp & 0x03FF; + + if(exponent == 0x00) + { + if(mantissa == 0) + return 0.0f; + + // subnormal + float ret = (float)mantissa; + int *alias = (int *)&ret; + + // set sign bit and set exponent to 2^-24 + // (2^-14 from spec for subnormals * 2^-10 to convert (float)mantissa to 0.mantissa) + *alias = (sign ? 0x80000000 : 0) | (*alias - (24 << 23)); + + return ret; + } + else if(exponent < 0x1f) + { + exponent -= 15; + + float ret = 0.0f; + int *alias = (int *)&ret; + + // convert to float. Put sign bit in the right place, convert exponent to be + // [-128,127] and put in the right place, then shift mantissa up. + *alias = (sign ? 0x80000000 : 0) | (exponent+127) << 23 | (mantissa << 13); + + return ret; + } + else //if(exponent = 0x1f) + { + int nan = 0x7F800001; + return *(float*)&nan; + } +} diff --git a/renderdoc/maths/matrix.cpp b/renderdoc/maths/matrix.cpp new file mode 100644 index 0000000000..52f6719177 --- /dev/null +++ b/renderdoc/maths/matrix.cpp @@ -0,0 +1,250 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include +#include +#include + +#include "vec.h" +#include "matrix.h" +#include "quat.h" + +static inline size_t matIdx(const size_t x, const size_t y) { return x+y*4; } + +Matrix4f Matrix4f::Mul(const Matrix4f &o) const +{ + Matrix4f m; + for(size_t x=0; x < 4; x++) + { + for(size_t y=0; y < 4; y++) + { + m[matIdx(x,y)] = (*this)[matIdx(x,0)] * o[matIdx(0,y)] + + (*this)[matIdx(x,1)] * o[matIdx(1,y)] + + (*this)[matIdx(x,2)] * o[matIdx(2,y)] + + (*this)[matIdx(x,3)] * o[matIdx(3,y)]; + } + } + + return m; +} + +Matrix4f Matrix4f::Inverse() const +{ + float a0 = (*this)[ 0]*(*this)[ 5] - (*this)[ 1]*(*this)[ 4]; + float a1 = (*this)[ 0]*(*this)[ 6] - (*this)[ 2]*(*this)[ 4]; + float a2 = (*this)[ 0]*(*this)[ 7] - (*this)[ 3]*(*this)[ 4]; + float a3 = (*this)[ 1]*(*this)[ 6] - (*this)[ 2]*(*this)[ 5]; + float a4 = (*this)[ 1]*(*this)[ 7] - (*this)[ 3]*(*this)[ 5]; + float a5 = (*this)[ 2]*(*this)[ 7] - (*this)[ 3]*(*this)[ 6]; + float b0 = (*this)[ 8]*(*this)[13] - (*this)[ 9]*(*this)[12]; + float b1 = (*this)[ 8]*(*this)[14] - (*this)[10]*(*this)[12]; + float b2 = (*this)[ 8]*(*this)[15] - (*this)[11]*(*this)[12]; + float b3 = (*this)[ 9]*(*this)[14] - (*this)[10]*(*this)[13]; + float b4 = (*this)[ 9]*(*this)[15] - (*this)[11]*(*this)[13]; + float b5 = (*this)[10]*(*this)[15] - (*this)[11]*(*this)[14]; + + float det = a0*b5 - a1*b4 + a2*b3 + a3*b2 - a4*b1 + a5*b0; + if (fabs(det) > FLT_EPSILON) + { + Matrix4f inverse; + inverse[ 0] = + (*this)[ 5]*b5 - (*this)[ 6]*b4 + (*this)[ 7]*b3; + inverse[ 4] = - (*this)[ 4]*b5 + (*this)[ 6]*b2 - (*this)[ 7]*b1; + inverse[ 8] = + (*this)[ 4]*b4 - (*this)[ 5]*b2 + (*this)[ 7]*b0; + inverse[12] = - (*this)[ 4]*b3 + (*this)[ 5]*b1 - (*this)[ 6]*b0; + inverse[ 1] = - (*this)[ 1]*b5 + (*this)[ 2]*b4 - (*this)[ 3]*b3; + inverse[ 5] = + (*this)[ 0]*b5 - (*this)[ 2]*b2 + (*this)[ 3]*b1; + inverse[ 9] = - (*this)[ 0]*b4 + (*this)[ 1]*b2 - (*this)[ 3]*b0; + inverse[13] = + (*this)[ 0]*b3 - (*this)[ 1]*b1 + (*this)[ 2]*b0; + inverse[ 2] = + (*this)[13]*a5 - (*this)[14]*a4 + (*this)[15]*a3; + inverse[ 6] = - (*this)[12]*a5 + (*this)[14]*a2 - (*this)[15]*a1; + inverse[10] = + (*this)[12]*a4 - (*this)[13]*a2 + (*this)[15]*a0; + inverse[14] = - (*this)[12]*a3 + (*this)[13]*a1 - (*this)[14]*a0; + inverse[ 3] = - (*this)[ 9]*a5 + (*this)[10]*a4 - (*this)[11]*a3; + inverse[ 7] = + (*this)[ 8]*a5 - (*this)[10]*a2 + (*this)[11]*a1; + inverse[11] = - (*this)[ 8]*a4 + (*this)[ 9]*a2 - (*this)[11]*a0; + inverse[15] = + (*this)[ 8]*a3 - (*this)[ 9]*a1 + (*this)[10]*a0; + + float invDet = 1.0f/det; + inverse[ 0] *= invDet; + inverse[ 1] *= invDet; + inverse[ 2] *= invDet; + inverse[ 3] *= invDet; + inverse[ 4] *= invDet; + inverse[ 5] *= invDet; + inverse[ 6] *= invDet; + inverse[ 7] *= invDet; + inverse[ 8] *= invDet; + inverse[ 9] *= invDet; + inverse[10] *= invDet; + inverse[11] *= invDet; + inverse[12] *= invDet; + inverse[13] *= invDet; + inverse[14] *= invDet; + inverse[15] *= invDet; + + return inverse; + } + + // no inverse + return Matrix4f::Identity(); +} + +Vec3f Matrix4f::Transform(const Vec3f &v, const float w) const +{ + Vec3f vout = Vec3f((*this)[matIdx(0,0)] * v.x + (*this)[matIdx(0,1)] * v.y + (*this)[matIdx(0,2)] * v.z + (*this)[matIdx(0,3)] * w, + (*this)[matIdx(1,0)] * v.x + (*this)[matIdx(1,1)] * v.y + (*this)[matIdx(1,2)] * v.z + (*this)[matIdx(1,3)] * w, + (*this)[matIdx(2,0)] * v.x + (*this)[matIdx(2,1)] * v.y + (*this)[matIdx(2,2)] * v.z + (*this)[matIdx(2,3)] * w); + float wout = (*this)[matIdx(3,0)] * v.x + (*this)[matIdx(3,1)] * v.y + (*this)[matIdx(3,2)] * v.z + (*this)[matIdx(3,3)] * w; + + return vout*(1.0f/wout); +} + +const Vec3f Matrix4f::GetPosition() const +{ + return Vec3f(f[12], f[13], f[14]); +} + +const Vec3f Matrix4f::GetForward() const +{ + return Vec3f(f[8], f[9], f[10]); +} + +const Vec3f Matrix4f::GetRight() const +{ + return Vec3f(f[0], f[1], f[2]); +} + +const Vec3f Matrix4f::GetUp() const +{ + return Vec3f(f[4], f[5], f[6]); +} + +Matrix4f Matrix4f::Translation(const Vec3f &t) +{ + Matrix4f trans = Matrix4f::Identity(); + + trans[12] = t.x; + trans[13] = t.y; + trans[14] = t.z; + + return trans; +} + +Matrix4f Matrix4f::RotationX(const float r) +{ + float m[16] = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, cosf(r), -sinf(r), 0.0f, + 0.0f, sinf(r), cosf(r), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + return Matrix4f(m); +} + +Matrix4f Matrix4f::RotationY(const float r) +{ + float m[16] = { cosf(r), 0.0f, sinf(r), 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + -sinf(r), 0.0f, cosf(r), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + return Matrix4f(m); +} + +Matrix4f Matrix4f::RotationZ(const float r) +{ + float m[16] = { cosf(r), -sinf(r), 0.0f, 0.0f, + sinf(r), cosf(r), 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + return Matrix4f(m); +} + +Matrix4f Matrix4f::RotationZYX(const Vec3f &rot) +{ + Quatf Qx = Quatf::AxisAngle(Vec3f(1.0f, 0.0f, 0.0f), rot.x); + Quatf Qy = Quatf::AxisAngle(Vec3f(0.0f, 1.0f, 0.0f), rot.y); + Quatf Qz = Quatf::AxisAngle(Vec3f(0.0f, 0.0f, 1.0f), rot.z); + + Quatf R = Qx * Qy * Qz; + + return R.GetMatrix(); +} + +Matrix4f Matrix4f::RotationXYZ(const Vec3f &rot) +{ + Quatf Qx = Quatf::AxisAngle(Vec3f(1.0f, 0.0f, 0.0f), rot.x); + Quatf Qy = Quatf::AxisAngle(Vec3f(0.0f, 1.0f, 0.0f), rot.y); + Quatf Qz = Quatf::AxisAngle(Vec3f(0.0f, 0.0f, 1.0f), rot.z); + + Quatf R = Qz * Qy * Qx; + + return R.GetMatrix(); +} + +Matrix4f Matrix4f::Orthographic(const float near, const float far) +{ + float L = -10.0f; + float R = 10.0f; + + float T = 10.0f; + float B = -10.0f; + + float N = -abs(far-near)*0.5f; + float F = abs(far-near)*0.5f; + + if(far < near) + { + float tmp = F; + F = N; + N = tmp; + } + + float ortho[16] = { 2.0f/(R-L), 0.0f, 0.0f, (L+R)/(L-R), + 0.0f, 2.0f/(T-B), 0.0f, (T+B)/(B-T), + 0.0f, 0.0f, 1.0f/(F-N), (F+N)/(N-F), + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + return Matrix4f(ortho); +} + +Matrix4f Matrix4f::Perspective(const float degfov, const float N, const float F, const float A) +{ + const float radfov = degfov * (3.1415926535f/180.0f); + float S = 1/tanf(radfov * 0.5f); + + float persp[16] = { S/A, 0.0f, 0.0f, 0.0f, + 0.0f, S, 0.0f, 0.0f, + 0.0f, 0.0f, F/(F-N), 1.0f, + 0.0f, 0.0f, -(F*N)/(F-N), 0.0f, + }; + + return Matrix4f(persp); +} diff --git a/renderdoc/maths/matrix.h b/renderdoc/maths/matrix.h new file mode 100644 index 0000000000..bb9015750e --- /dev/null +++ b/renderdoc/maths/matrix.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +class Vec3f; +class Quatf; + +#include + +class Matrix4f +{ + public: + Matrix4f() {} + + ////////////////////////////////////////////////////// + // Matrix generation functions + + inline static Matrix4f Zero() + { + Matrix4f m; + memset(&m, 0, sizeof(Matrix4f)); + return m; + } + + inline static Matrix4f Identity() + { + Matrix4f m = Zero(); + m[0] = m[5] = m[10] = m[15] = 1.0f; + return m; + } + + static Matrix4f Translation(const Vec3f &t); + static Matrix4f RotationX(const float r); + static Matrix4f RotationY(const float r); + static Matrix4f RotationZ(const float r); + static Matrix4f RotationXYZ(const Vec3f &rot); + static Matrix4f RotationZYX(const Vec3f &rot); + static Matrix4f Orthographic(const float nearplane, const float farplane); + static Matrix4f Perspective(const float degfov, const float nearplane, const float farplane, const float aspect); + + inline float operator[](const size_t i) const + { + return f[i]; + } + + inline float &operator[](const size_t i) + { + return f[i]; + } + + Matrix4f Inverse() const; + Matrix4f Mul(const Matrix4f &o) const; + + Vec3f Transform(const Vec3f &v, const float w=1.0f) const; + + const float * const Data() const { return &f[0]; } + + const Vec3f GetPosition() const; + const Vec3f GetForward() const; + const Vec3f GetRight() const; + const Vec3f GetUp() const; + + private: + Matrix4f(const float *d) { memcpy(f, d, sizeof(Matrix4f)); } + + friend class Quatf; + + float f[16]; +}; diff --git a/renderdoc/maths/quat.h b/renderdoc/maths/quat.h new file mode 100644 index 0000000000..adce35eec2 --- /dev/null +++ b/renderdoc/maths/quat.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include "vec.h" +#include "matrix.h" + +class Quatf +{ + public: + float w; + Vec3f v; + + static Quatf AxisAngle(Vec3f axis, float angle) + { + Quatf q; + + q.w = cosf(angle/2.0f); + q.v.x = axis.x * sinf(angle/2.0f); + q.v.y = axis.y * sinf(angle/2.0f); + q.v.z = axis.z * sinf(angle/2.0f); + + return q; + } + + Matrix4f GetMatrix() + { + float q0 = w; + float q1 = v.x; + float q2 = v.y; + float q3 = v.z; + + float m[16] = { 1.0f - 2*(q2*q2 + q3*q3), 2.0f*(q1*q2 - q0*q3), 2.0f*(q0*q2 + q1*q3), 0.0f, + 2.0f*(q1*q2 + q0*q3), 1.0f - 2*(q1*q1 + q3*q3), 2.0f*(q2*q3 - q0*q1), 0.0f, + 2.0f*(q1*q3 - q0*q2), 2.0f*(q0*q1 + q2*q3), 1.0f - 2*(q1*q1 + q2*q2), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + return Matrix4f(m); + } +}; + +inline Quatf operator *(const Quatf &a, const Quatf &b) +{ + Quatf r; + + r.w = a.w * b.w - a.v.Dot(b.v); + r.v = b.v * a.w + a.v * b.w + a.v.Cross(b.v); + + return r; +} diff --git a/renderdoc/maths/vec.h b/renderdoc/maths/vec.h new file mode 100644 index 0000000000..659e4ab862 --- /dev/null +++ b/renderdoc/maths/vec.h @@ -0,0 +1,108 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include + +struct Vec2f +{ + Vec2f(float X = 0.0f, float Y = 0.0f) { x = X; y = Y; } + float x; + float y; +}; + +class Vec3f +{ + public: + Vec3f(const float X=0.0f, const float Y=0.0f, const float Z=0.0f) + : x(X), y(Y), z(Z) + { } + + inline float Dot(const Vec3f &o) const + { + return x*o.x + y*o.y + z*o.z; + } + + inline Vec3f Cross(const Vec3f &o) const + { + return Vec3f(y*o.z - z*o.y, + z*o.x - x*o.z, + x*o.y - y*o.x); + } + + inline float Length() const + { + return sqrt(Dot(*this)); + } + + inline void Normalise() + { + float l = Length(); + x /= l; + y /= l; + z /= l; + } + + float x, y, z; +}; + +struct Vec4f +{ + Vec4f(float X = 0.0f, float Y = 0.0f, float Z = 0.0f, float W = 0.0f) { x = X; y = Y; z = Z; w = W; } + float x, y, z, w; +}; + +inline Vec3f operator *(const Vec3f &a, const float b) +{ + return Vec3f(a.x*b, a.y*b, a.z*b); +} + +inline Vec3f operator +(const Vec3f &a, const Vec3f &b) +{ + return Vec3f(a.x+b.x, a.y+b.y, a.z+b.z); +} + +inline Vec3f operator -(const Vec3f &a) +{ + return Vec3f(-a.x, -a.y, -a.z); +} + +inline Vec3f operator -(const Vec3f &a, const Vec3f &b) +{ + return a + (-b); +} + +inline Vec3f operator -=(Vec3f &a, const Vec3f &b) +{ + a = a-b; + return a; +} + +inline Vec3f operator +=(Vec3f &a, const Vec3f &b) +{ + a = a+b; + return a; +} \ No newline at end of file diff --git a/renderdoc/os/linux/linux_callstack.cpp b/renderdoc/os/linux/linux_callstack.cpp new file mode 100644 index 0000000000..006613f365 --- /dev/null +++ b/renderdoc/os/linux/linux_callstack.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" + +namespace Callstack +{ + void Init() {} + Stackwalk *Collect() { RDCUNIMPLEMENTED(); return NULL; } + Stackwalk *Load(uint64_t *calls, size_t numLevels) { RDCUNIMPLEMENTED(); return NULL; } + StackResolver *MakeResolver(char *moduleDB, size_t DBSize, wstring pdbSearchPaths, volatile bool *killSignal) { RDCUNIMPLEMENTED(); return NULL; } + + bool GetLoadedModules(char *&buf, size_t &size) { RDCUNIMPLEMENTED(); return false; } +}; diff --git a/renderdoc/os/linux/linux_network.cpp b/renderdoc/os/linux/linux_network.cpp new file mode 100644 index 0000000000..6eaa7fb2b6 --- /dev/null +++ b/renderdoc/os/linux/linux_network.cpp @@ -0,0 +1,345 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +using std::string; +using std::wstring; + +#include "common/string_utils.h" +#include "os/os_specific.h" + +namespace Network +{ + +void Init() +{ +} + +void Shutdown() +{ +} + +Socket::~Socket() +{ + Shutdown(); +} + +void Socket::Shutdown() +{ + if(Connected()) + { + shutdown((int)socket, SHUT_RDWR); + close((int)socket); + socket = -1; + } +} + +bool Socket::Connected() +{ + return (int)socket != -1; +} + +Socket *Socket::AcceptClient(bool wait) +{ + do + { + int s = accept(socket, NULL, NULL); + + if(s != -1) + { + int flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags | O_NONBLOCK); + + int nodelay = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); + + return new Socket((ptrdiff_t)s); + } + + int err = errno; + + if(err != EWOULDBLOCK) + { + RDCWARN("accept: %d", err); + Shutdown(); + } + + Threading::Sleep(4); + } while(wait); + + return NULL; +} + +bool Socket::SendDataBlocking(const void *buf, uint32_t length) +{ + if(length == 0) return true; + + uint32_t sent = 0; + + char *src = (char *)buf; + + int flags = fcntl(socket, F_GETFL, 0); + fcntl(socket, F_SETFL, flags & ~O_NONBLOCK); + + while(sent < length) + { + int ret = send(socket, src, length-sent, 0); + + if(ret <= 0) + { + int err = errno; + + if(err == EWOULDBLOCK) + { + ret = 0; + } + else + { + RDCWARN("send: %d", err); + Shutdown(); + return false; + } + } + + sent += ret; + src += ret; + } + + flags = fcntl(socket, F_GETFL, 0); + fcntl(socket, F_SETFL, flags | O_NONBLOCK); + + RDCASSERT(sent == length); + + return true; +} + +bool Socket::IsRecvDataWaiting() +{ + char dummy; + int ret = recv(socket, &dummy, 1, MSG_PEEK); + + if(ret == 0) + { + Shutdown(); + return false; + } + else if(ret <= 0) + { + int err = errno; + + if(err == EWOULDBLOCK) + { + ret = 0; + } + else + { + RDCWARN("recv: %d", err); + Shutdown(); + return false; + } + } + + return ret > 0; +} + +bool Socket::RecvDataBlocking(void *buf, uint32_t length) +{ + if(length == 0) return true; + + uint32_t received = 0; + + char *dst = (char *)buf; + + int flags = fcntl(socket, F_GETFL, 0); + fcntl(socket, F_SETFL, flags & ~O_NONBLOCK); + + while(received < length) + { + int ret = recv(socket, dst, length-received, 0); + + if(ret == 0) + { + Shutdown(); + return false; + } + else if(ret <= 0) + { + int err = errno; + + if(err == EWOULDBLOCK) + { + ret = 0; + } + else + { + RDCWARN("recv: %d", err); + Shutdown(); + return false; + } + } + + received += ret; + dst += ret; + } + + flags = fcntl(socket, F_GETFL, 0); + fcntl(socket, F_SETFL, flags | O_NONBLOCK); + + RDCASSERT(received == length); + + return true; +} + +Socket *CreateServerSocket(const char *bindaddr, uint16_t port, int queuesize) +{ + int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(s == -1) + return NULL; + + sockaddr_in addr; + RDCEraseEl(addr); + + hostent *hp = gethostbyname(bindaddr); + + addr.sin_family = AF_INET; + memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_port = htons(port); + + int result = bind(s, (sockaddr *)&addr, sizeof(addr)); + if(result == -1) + { + RDCWARN("Failed to bind to %s:%d - %d", bindaddr, port, errno); + close(s); + return NULL; + } + + result = listen(s, queuesize); + if(result == -1) + { + RDCWARN("Failed to listen on %s:%d - %d", bindaddr, port, errno); + close(s); + return NULL; + } + + int flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags | O_NONBLOCK); + + return new Socket((ptrdiff_t)s); +} + +Socket *CreateClientSocket(const wchar_t *host, uint16_t port, int timeoutMS) +{ + char portstr[7] = {0}; + StringFormat::snprintf(portstr, 6, "%d", port); + + addrinfo hints; + RDCEraseEl(hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + + wstring hostWide = wstring(host); + string hoststr = narrow(hostWide); + + if(widen(hoststr) != hostWide) + RDCWARN("Unicode hostname truncated: %S", hostWide.c_str()); + + addrinfo *result = NULL; + getaddrinfo(hoststr.c_str(), portstr, &hints, &result); + + for(addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next) + { + int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(s == -1) + return NULL; + + int flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags | O_NONBLOCK); + + int result = connect(s, ptr->ai_addr, (int)ptr->ai_addrlen); + if(result == -1) + { + fd_set set; + FD_ZERO(&set); + FD_SET(s, &set); + + int err = errno; + + if(err == EWOULDBLOCK) + { + timeval timeout; + timeout.tv_sec = (timeoutMS/1000); + timeout.tv_usec = (timeoutMS%1000)*1000; + result = select(0, NULL, &set, NULL, &timeout); + + if(result <= 0) + { + RDCDEBUG("connect timed out"); + close(s); + continue; + } + else + { + RDCDEBUG("connect before timeout"); + } + } + else + { + RDCDEBUG("problem other than blocking"); + close(s); + continue; + } + } + else + { + RDCDEBUG("connected immediately"); + } + + int nodelay = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); + + return new Socket((ptrdiff_t)s); + } + + RDCWARN("Failed to connect to %S:%d", host, port); + return NULL; +} + +}; diff --git a/renderdoc/os/linux/linux_process.cpp b/renderdoc/os/linux/linux_process.cpp new file mode 100644 index 0000000000..7c30371385 --- /dev/null +++ b/renderdoc/os/linux/linux_process.cpp @@ -0,0 +1,52 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" +#include +#include + +uint32_t Process::InjectIntoProcess(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit) +{ + RDCUNIMPLEMENTED(); + return 0; +} + +uint32_t Process::CreateAndInjectIntoProcess(const wchar_t *app, const wchar_t *workingDir, const wchar_t *cmdLine, + const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit) +{ + RDCUNIMPLEMENTED(); + return 0; +} + +void *Process::GetFunctionAddress(const char *module, const char *function) +{ + RDCUNIMPLEMENTED(); + return NULL; +} + +uint32_t Process::GetCurrentPID() +{ + return (uint32_t)getpid(); +} \ No newline at end of file diff --git a/renderdoc/os/linux/linux_stringio.cpp b/renderdoc/os/linux/linux_stringio.cpp new file mode 100644 index 0000000000..a4bb644474 --- /dev/null +++ b/renderdoc/os/linux/linux_stringio.cpp @@ -0,0 +1,375 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "common/string_utils.h" +#include "common/threading.h" +using std::string; + +namespace Keyboard +{ + void Init() + { + } + + Display *CurrentXDisplay = NULL; + + void AddInputWindow(void *wnd) + { + // TODO check against this drawable & parent window being focused in GetKeyState + } + + void RemoveInputWindow(void *wnd) + { + } + + bool GetKeyState(KeyButton key) + { + KeySym ks = 0; + + if(CurrentXDisplay == NULL) return false; + + switch(key) + { + case eKey_F11: ks = XK_F11; break; + case eKey_F12: ks = XK_F12; break; + case eKey_PrtScrn: ks = XK_Print; break; + default: + return false; + } + + KeyCode kc = XKeysymToKeycode(CurrentXDisplay, ks); + + char keyState[32]; + XQueryKeymap(CurrentXDisplay, keyState); + + int byteIdx = (kc/8); + int bitMask = 1 << (kc%8); + + uint8_t keyByte = (uint8_t)keyState[byteIdx]; + + return (keyByte & bitMask) != 0; + } +} + +namespace FileIO +{ + void GetExecutableFilename(wstring &selfName) + { + char path[512] = {0}; + readlink("/proc/self/exe", path, 511); + + selfName = widen(string(path)); + } + + void GetDefaultFiles(const wchar_t *logBaseName, wstring &capture_filename, wstring &logging_filename, wstring &target) + { + char path[512] = {0}; + readlink("/proc/self/exe", path, 511); + const char *mod = strrchr(path, '/'); + if(mod == NULL) + mod = "unknown"; + else + mod++; + + target = widen(string(mod)); + + time_t t = time(NULL); + tm now = *localtime(&t); + + char temp_filename[512] = {0}; + + snprintf(temp_filename, 511, "/tmp/%s_%04d.%02d.%02d_%02d.%02d.rdc", mod, 1900+now.tm_year, now.tm_mon+1, now.tm_mday, now.tm_hour, now.tm_min); + + capture_filename = widen(string(temp_filename)); + + string baseName = narrow(wstring(logBaseName)); + + snprintf(temp_filename, 511, "/tmp/%s_%04d.%02d.%02d_%02d.%02d.%02d.log", baseName.c_str(), 1900+now.tm_year, now.tm_mon+1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); + + logging_filename = widen(string(temp_filename)); + } + + uint64_t GetModifiedTimestamp(const wchar_t *filename) + { + string fn = narrow(wstring(filename)); + + struct ::stat st; + int res = stat(fn.c_str(), &st); + + if(res == 0) + { + return (uint64_t)st.st_mtim.tv_sec; + } + + return 0; + } + + void CopyFileW(const wchar_t *from, const wchar_t *to, bool allowOverwrite) + { + if(from[0] == 0 || to[0] == 0) + return; + + RDCUNIMPLEMENTED(); + } + + void UnlinkFileW(const wchar_t *path) + { + string fn = narrow(wstring(path)); + + unlink(fn.c_str()); + } + + FILE *fopen(const wchar_t *filename, const wchar_t *mode) + { + string fn = narrow(wstring(filename)); + + char m[5]; + + for(int i=0; i < 5; i++) + { + if(!mode[i]) break; + m[i] = (char)mode[i]; + } + + return ::fopen(fn.c_str(), m); + } + + size_t fread(void *buf, size_t elementSize, size_t count, FILE *f) { return ::fread(buf, elementSize, count, f); } + size_t fwrite(const void *buf, size_t elementSize, size_t count, FILE *f) { return ::fwrite(buf, elementSize, count, f); } + + uint64_t ftell64(FILE *f) { return (uint64_t)::ftell(f); } + void fseek64(FILE *f, uint64_t offset, int origin) { ::fseek(f, (long)offset, origin); } + + int fclose(FILE *f) { return ::fclose(f); } +}; + +namespace StringFormat +{ + int snprintf(char *str, size_t bufSize, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + + int ret = vsnprintf(str, bufSize, fmt, args); + + va_end(args); + + return ret; + } + + int vsnprintf(char *str, size_t bufSize, const char *format, va_list args) + { + return ::vsnprintf(str, bufSize, format, args); + } + + int wsnprintf(wchar_t *str, size_t bufSize, const wchar_t *fmt, ...) + { + va_list args; + va_start(args, fmt); + + int ret = vswprintf(str, bufSize, fmt, args); + + va_end(args); + + return ret; + } + + void sntimef(char *str, size_t bufSize, const char *format) + { + time_t tim; + time(&tim); + + tm *tmv = localtime(&tim); + + strftime(str, bufSize, format, tmv); + } + + void wcsncpy(wchar_t *dst, const wchar_t *src, size_t count) + { + ::wcsncpy(dst, src, count); + } + + string Fmt(const char *format, ...) + { + va_list args; + va_start(args, format); + + int size = ::vsnprintf(NULL, 0, format, args)+1; + + char *buf = new char[size]; + + StringFormat::vsnprintf(buf, size, format, args); + + va_end(args); + + string ret = buf; + + delete[] buf; + + return ret; + } + + wstring WFmt(const wchar_t *format, ...) + { + va_list args; + va_start(args, format); + + FILE *f = ::fopen("/dev/null", "wb"); + + int size = ::vfwprintf(f, format, args)+1; + + fclose(f); + + va_end(args); + va_start(args, format); + + wchar_t *buf = new wchar_t[size]; + + ::vswprintf(buf, size, format, args); + + va_end(args); + + wstring ret = buf; + + delete[] buf; + + return ret; + } + + // save on reallocation, keep a persistent scratch buffer for conversions + vector charBuffer; + vector wcharBuffer; + + // cache iconv_t descriptors to save on iconv_open/iconv_close each time + iconv_t iconvWide2UTF8 = (iconv_t)-1; + iconv_t iconvUTF82Wide = (iconv_t)-1; + + // iconv is not thread safe when sharing an iconv_t descriptor + // I don't expect much contention but if it happens we could TryLock + // before creating a temporary iconv_t, or hold two iconv_ts, or something. + Threading::CriticalSection lockWide2UTF8, lockUTF82Wide; + + string Wide2UTF8(const wstring &s) + { + // include room for null terminator, assuming unicode input (not ucs) + // utf-8 characters can be max 4 bytes. We can afford to be generous about + // this length as we resize relatively rarely. + size_t len = (s.length()+1)*4; + + if(charBuffer.size() < len) + charBuffer.resize(len); + + size_t ret; + + { + SCOPED_LOCK(lockWide2UTF8); + + if(iconvWide2UTF8 == (iconv_t)-1) + iconvWide2UTF8 = iconv_open("UTF-8", "WCHAR_T"); + + if(iconvWide2UTF8 == (iconv_t)-1) + { + RDCERR("Couldn't open iconv for WCHAR_T to UTF-8: %d", errno); + return ""; + } + + char *inbuf = (char *)s.c_str(); + size_t insize = (s.length()+1)*sizeof(wchar_t); // include null terminator + char *outbuf = &charBuffer[0]; + size_t outsize = len; + + ret = iconv(iconvWide2UTF8, &inbuf, &insize, &outbuf, &outsize); + } + + if(ret == (size_t)-1) + { +#if !defined(_RELEASE) + RDCWARN("Failed to convert wstring: \"%ls\"", s.c_str()); +#endif + return ""; + } + + // convert to string from null-terminated string - utf-8 never contains + // 0 bytes before the null terminator, and this way we don't care if + // charBuffer is larger than the string + return string(&charBuffer[0]); + } + + wstring UTF82Wide(const string &s) + { + // Include room for null terminator. Since we're converting from utf-8, + // worst case it's ascii and every byte is a character so length is the same + size_t len = s.length()+1; + + if(wcharBuffer.size() < len) + wcharBuffer.resize(len); + + size_t ret; + + { + SCOPED_LOCK(lockUTF82Wide); + + if(iconvUTF82Wide == (iconv_t)-1) + iconvUTF82Wide = iconv_open("WCHAR_T", "UTF-8"); + + if(iconvUTF82Wide == (iconv_t)-1) + { + RDCERR("Couldn't open iconv for UTF-8 to WCHAR_T: %d", errno); + return L""; + } + + char *inbuf = (char *)s.c_str(); + size_t insize = s.length()+1; // include null terminator + char *outbuf = (char *)&wcharBuffer[0]; + size_t outsize = len*sizeof(wchar_t); + + ret = iconv(iconvUTF82Wide, &inbuf, &insize, &outbuf, &outsize); + } + + if(ret == (size_t)-1) + { +#if !defined(_RELEASE) + RDCWARN("Failed to convert utf-8 string: \"%s\"", s.c_str()); +#endif + return L""; + } + + return wstring(&wcharBuffer[0]); + } +}; diff --git a/renderdoc/os/linux/linux_threading.cpp b/renderdoc/os/linux/linux_threading.cpp new file mode 100644 index 0000000000..f974c32c3e --- /dev/null +++ b/renderdoc/os/linux/linux_threading.cpp @@ -0,0 +1,149 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" + +#include +#include + +double Timing::GetTickFrequency() +{ + return 1000000.0; +} + +uint64_t Timing::GetTick() +{ + timespec ts; + clock_gettime(CLOCK_MONOTONIC,&ts); + return uint64_t(ts.tv_sec)*1000000000ULL + uint32_t(ts.tv_nsec & 0xffffffff); +} + +namespace Atomic +{ + int32_t Inc32(volatile int32_t *i) + { + return __sync_fetch_and_add(i, int32_t(1)); + } + + int64_t Inc64(volatile int64_t *i) + { + return __sync_fetch_and_add(i, int64_t(1)); + } + + int64_t Dec64(volatile int64_t *i) + { + return __sync_fetch_and_add(i, int64_t(-1)); + } + + int64_t ExchAdd64(volatile int64_t *i, int64_t a) + { + return __sync_add_and_fetch(i, int64_t(a)); + } +}; + +namespace Threading +{ + template<> + CriticalSection::CriticalSectionTemplate() + { + pthread_mutexattr_init(&m_Data.attr); + pthread_mutexattr_settype(&m_Data.attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_Data.lock, &m_Data.attr); + } + + template<> + CriticalSection::~CriticalSectionTemplate() + { + pthread_mutex_destroy(&m_Data.lock); + pthread_mutexattr_destroy(&m_Data.attr); + } + + template<> + void CriticalSection::Lock() + { + pthread_mutex_lock(&m_Data.lock); + } + + template<> + bool CriticalSection::Trylock() + { + return pthread_mutex_trylock(&m_Data.lock) == 0; + } + + template<> + void CriticalSection::Unlock() + { + pthread_mutex_unlock(&m_Data.lock); + } + + struct ThreadInitData + { + ThreadEntry entryFunc; + void *userData; + }; + + static void *sThreadInit(void *init) + { + ThreadInitData *data = (ThreadInitData *)init; + + // delete before going into entry function so lifetime is limited. + ThreadInitData local = *data; + delete data; + + local.entryFunc(local.userData); + + return NULL; + } + + ThreadHandle CreateThread(ThreadEntry entryFunc, void *userData) + { + pthread_t thread; + + ThreadInitData *initData = new ThreadInitData(); + initData->entryFunc = entryFunc; + initData->userData = userData; + + int res = pthread_create(&thread, NULL, sThreadInit, (void *)initData); + if(res != 0) + { + delete initData; + return (ThreadHandle)0; + } + + return (ThreadHandle)thread; + } + void JoinThread(ThreadHandle handle) + { + pthread_join((pthread_t)handle, NULL); + } + void CloseThread(ThreadHandle handle) + { + } + + void Sleep(uint32_t milliseconds) + { + usleep(milliseconds*1000); + } +}; diff --git a/renderdoc/os/linux_specific.h b/renderdoc/os/linux_specific.h new file mode 100644 index 0000000000..2d6a6cf380 --- /dev/null +++ b/renderdoc/os/linux_specific.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include + +#include "data/embedded_files.h" + +#define __PRETTY_FUNCTION_SIGNATURE__ __PRETTY_FUNCTION__ + +#define GetEmbeddedResource(filename) string( CONCAT(CONCAT(_binary_, filename), _start) , CONCAT(CONCAT(_binary_, filename), _end) ) + +namespace OSUtility +{ + inline void ForceCrash() { __builtin_trap(); } + inline void DebugBreak() { raise(SIGTRAP); } + inline bool DebuggerPresent() { return true; } + inline void DebugOutputA(const char *str) { } +}; + +namespace Threading +{ + struct pthreadLockData + { + pthread_mutex_t lock; + pthread_mutexattr_t attr; + }; + typedef CriticalSectionTemplate CriticalSection; +}; + diff --git a/renderdoc/os/os_specific.cpp b/renderdoc/os/os_specific.cpp new file mode 100644 index 0000000000..1e95e66709 --- /dev/null +++ b/renderdoc/os/os_specific.cpp @@ -0,0 +1,54 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" +#include "common/string_utils.h" + +using std::string; + +wstring Callstack::AddressDetails::formattedString(const char *commonPath) +{ + wchar_t fmt[512] = {0}; + + const wchar_t *f = filename.c_str(); + + if(commonPath) + { + wstring common = strlower(widen(string(commonPath))); + wstring fn = strlower(filename.substr(0, common.length())); + + if(common == fn) + { + f += common.length(); + } + } + + if(line > 0) + swprintf(fmt, 511, L"%ls line %d", function.c_str(), line); + else + swprintf(fmt, 511, L"%ls", function.c_str()); + + return fmt; +} \ No newline at end of file diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h new file mode 100644 index 0000000000..5778add4dd --- /dev/null +++ b/renderdoc/os/os_specific.h @@ -0,0 +1,245 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// this file defines several 'interfaces' that are then implemented by conditionally compiling in +// the platform's specific implementation +// +// Anything that won't compile on all platforms MUST be wrapped and specified in this file, so +// that we isolate any OS-specific code to one place that can just be swapped out easily. + +#pragma once + +#include "common/common.h" + +#include +#include +#include + +#include +#include +using std::string; +using std::wstring; +using std::vector; + +struct CaptureOptions; + +namespace Process +{ + uint32_t InjectIntoProcess(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit); + uint32_t CreateAndInjectIntoProcess(const wchar_t *app, const wchar_t *workingDir, const wchar_t *cmdLine, + const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit); + void *GetFunctionAddress(const char *module, const char *function); + uint32_t GetCurrentPID(); +}; + +namespace Timing +{ + double GetTickFrequency(); + uint64_t GetTick(); +}; + +namespace Threading +{ + template + class CriticalSectionTemplate + { + public: + CriticalSectionTemplate(); + ~CriticalSectionTemplate(); + void Lock(); + bool Trylock(); + void Unlock(); + + private: + // no copying + CriticalSectionTemplate &operator =(const CriticalSectionTemplate &other); + CriticalSectionTemplate(const CriticalSectionTemplate &other); + + data m_Data; + }; + + // must typedef CriticalSectionTemplate CriticalSection + + typedef void (*ThreadEntry)(void *); + typedef uint64_t ThreadHandle; + ThreadHandle CreateThread(ThreadEntry entryFunc, void *userData); + void JoinThread(ThreadHandle handle); + void CloseThread(ThreadHandle handle); + void Sleep(uint32_t milliseconds); +}; + +namespace Network +{ + class Socket + { + public: + Socket(ptrdiff_t s) : socket(s) {} + ~Socket(); + void Shutdown(); + + bool Connected(); + + Socket *AcceptClient(bool wait); + + bool IsRecvDataWaiting(); + + bool SendDataBlocking(const void *buf, uint32_t length); + bool RecvDataBlocking(void *data, uint32_t length); + private: + ptrdiff_t socket; + }; + + Socket *CreateServerSocket(const char *addr, uint16_t port, int queuesize); + Socket *CreateClientSocket(const wchar_t *host, uint16_t port, int timeoutMS); + + void Init(); + void Shutdown(); +}; + +namespace Atomic +{ + int32_t Inc32(volatile int32_t *i); + int64_t Inc64(volatile int64_t *i); + int64_t Dec64(volatile int64_t *i); + int64_t ExchAdd64(volatile int64_t *i, int64_t a); +}; + +namespace Callstack +{ + class Stackwalk + { + public: + virtual ~Stackwalk() {} + virtual size_t NumLevels() const = 0; + virtual uint64_t *GetAddrs() const = 0; + }; + + struct AddressDetails + { + AddressDetails() : line(0) {} + + wstring function; + wstring filename; + uint32_t line; + + wstring formattedString(const char *commonPath = NULL); + }; + + class StackResolver + { + public: + virtual ~StackResolver() {} + virtual AddressDetails GetAddr(uint64_t addr) = 0; + }; + + void Init(); + + Stackwalk *Collect(); + Stackwalk *Load(uint64_t *calls, size_t numLevels); + + StackResolver *MakeResolver(char *moduleDB, size_t DBSize, wstring pdbSearchPaths, volatile bool *killSignal); + + bool GetLoadedModules(char *&buf, size_t &size); +}; // namespace Callstack + +namespace FileIO +{ + void GetDefaultFiles(const wchar_t *logBaseName, wstring &capture_filename, wstring &logging_filename, wstring &target); + wstring GetAppFolderFilename(wstring filename); + + void GetExecutableFilename(wstring &selfName); + + uint64_t GetModifiedTimestamp(const wchar_t *filename); + + void CopyFileW(const wchar_t *from, const wchar_t *to, bool allowOverwrite); + void UnlinkFileW(const wchar_t *path); + + FILE *fopen(const wchar_t *filename, const wchar_t *mode); + + size_t fread(void *buf, size_t elementSize, size_t count, FILE *f); + size_t fwrite(const void *buf, size_t elementSize, size_t count, FILE *f); + + uint64_t ftell64(FILE *f); + void fseek64(FILE *f, uint64_t offset, int origin); + + int fclose(FILE *f); +}; + +namespace Keyboard +{ + enum KeyButton + { + eKey_0 = 0x30, // '0' + // ... + eKey_1 = 0x39, // '9' + eKey_A = 0x41, // 'A' + // ... + eKey_Z = 0x5A, // 'Z' + + eKey_F11, + eKey_F12, + eKey_PrtScrn, + + eKey_Max, + }; + + void Init(); + void AddInputWindow(void *wnd); + void RemoveInputWindow(void *wnd); + bool GetKeyState(KeyButton key); +}; + +namespace StringFormat +{ + int snprintf(char *str, size_t bufSize, const char *format, ...); + int wsnprintf(wchar_t *str, size_t bufSize, const wchar_t *format, ...); + int vsnprintf(char *str, size_t bufSize, const char *format, va_list v); + void sntimef(char *str, size_t bufSize, const char *format); + void wcsncpy(wchar_t *dst, const wchar_t *src, size_t count); + + string Fmt(const char *format, ...); + wstring WFmt(const wchar_t *format, ...); + + string Wide2UTF8(const wstring &s); + wstring UTF82Wide(const string &s); +}; + +namespace OSUtility +{ + inline void ForceCrash(); + inline void DebugBreak(); + inline bool DebuggerPresent(); + inline void DebugOutputA(const char *str); +}; + +// must #define: +// __PRETTY_FUNCTION_SIGNATURE__ - undecorated function signature +// GetEmbeddedResource(name_with_underscores_ext) - function/inline that returns the given file in a std::string + +#ifdef RENDERDOC_PLATFORM +// "win32_specific.h" (in directory os/) +#include STRINGIZE(CONCAT(RENDERDOC_PLATFORM,_specific.h)) +#else +#error Undefined Platform! +#endif diff --git a/renderdoc/os/win32/comexport.def b/renderdoc/os/win32/comexport.def new file mode 100644 index 0000000000..1aeefcc796 --- /dev/null +++ b/renderdoc/os/win32/comexport.def @@ -0,0 +1,4 @@ +LIBRARY RENDERDOC +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE diff --git a/renderdoc/os/win32/win32_callstack.cpp b/renderdoc/os/win32/win32_callstack.cpp new file mode 100644 index 0000000000..3b4ca0e732 --- /dev/null +++ b/renderdoc/os/win32/win32_callstack.cpp @@ -0,0 +1,767 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" +#include "common/string_utils.h" + +#include +#include +#include + +#define DBGHELP_TRANSLATE_TCHAR + +#include +#include +#include +#include +#include + +class Win32Callstack : public Callstack::Stackwalk +{ + public: + Win32Callstack(); + Win32Callstack(uint64_t *calls, size_t numLevels); + ~Win32Callstack(); + + size_t NumLevels() const { return m_NumLevels; } + uint64_t *GetAddrs() const { return m_AddrStack; } + private: + Win32Callstack(const Callstack::Stackwalk &other); + + void Collect(); + + size_t m_NumLevels; + DWORD64 *m_AddrStack; + DWORD64 *m_AllocStack; +}; + +class Win32CallstackResolver : public Callstack::StackResolver +{ + public: + Win32CallstackResolver(char *moduleDB, size_t DBSize, wstring pdbSearchPaths, volatile bool *killSignal); + ~Win32CallstackResolver(); + + Callstack::AddressDetails GetAddr(uint64_t addr); + private: + // must match definition in pdblocate.cpp + struct AddrInfo + { + wchar_t funcName[127]; + wchar_t fileName[127]; + unsigned long lineNum; + + wchar_t *formattedString(const char *commonPath = NULL); + }; + + wstring pdbBrowse(wstring startingPoint); + wstring LookupModule(wchar_t *modName, GUID guid, DWORD age); + + void *SendRecvPipeMessage(wstring message); + + void OpenPdblocateHandle(); + uint32_t GetModuleID(wstring pdbName, GUID guid, DWORD age); + void SetModuleBaseAddress(uint32_t moduleId, DWORD64 base); + AddrInfo GetAddrInfoForModule(uint32_t moduleId, DWORD64 addr); + + struct Module + { + wstring name; + DWORD64 base; + DWORD size; + + uint32_t moduleId; + }; + + HANDLE pdblocateProcess; + HANDLE pdblocatePipe; + + vector pdbRememberedPaths; + vector pdbIgnores; + vector modules; + + char pipeMessageBuf[2048]; +}; + +/////////////////////////////////////////////////// + +typedef BOOL +(CALLBACK *PSYM_ENUMMODULES_CALLBACK64W)( + __in PCWSTR ModuleName, + __in DWORD64 BaseOfDll, + __in_opt PVOID UserContext + ); + +typedef BOOL (WINAPI *PSYMINITIALIZEW)(HANDLE, PCTSTR, BOOL); +typedef BOOL (WINAPI *PSYMGETMODULEINFO64W)(HANDLE, DWORD64, PIMAGEHLP_MODULEW64); +typedef BOOL (WINAPI *PSYMENUMERATEMODULES64W)(HANDLE, PSYM_ENUMMODULES_CALLBACK64W, PVOID); + +PSYMINITIALIZEW dynSymInitializeW = NULL; +PSYMENUMERATEMODULES64W dynSymEnumerateModules64W = NULL; +PSYMGETMODULEINFO64W dynSymGetModuleInfo64W = NULL; + +void *renderdocBase = NULL; +uint32_t renderdocSize = 0; + +// gives us an address to identify this dll with +static int dllLocator=0; + +static bool InitDbgHelp() +{ + static bool doinit = true; + static bool ret = false; + + if(!doinit) + return ret; + + doinit = false; + + HMODULE module = NULL; + + // can't reliably co-exist with dbghelp already being used in the process + if(GetModuleHandleA("dbghelp.dll") != NULL) + { + ret = false; + return false; + } + else + { + wchar_t path[MAX_PATH] = {0}; + GetModuleFileNameW(GetModuleHandleA("renderdoc.dll"), path, MAX_PATH-1); + + wchar_t *slash = wcsrchr(path, '\\'); + + if(slash) + { + *slash = 0; + } + else + { + slash = wcsrchr(slash, '/'); + + if(slash == 0) + { + ret = false; + return false; + } + + *slash = 0; + } + +#if defined(WIN64) + wcscat_s(path, L"/pdblocate/x64/dbghelp.dll"); +#else + wcscat_s(path, L"/pdblocate/x86/dbghelp.dll"); +#endif + + module = LoadLibraryW(path); + } + + if(!module) + { + RDCWARN("Couldn't open dbghelp.dll"); + ret = false; + return false; + } + + dynSymInitializeW = (PSYMINITIALIZEW)GetProcAddress(module, "SymInitializeW"); + dynSymEnumerateModules64W = (PSYMENUMERATEMODULES64W)GetProcAddress(module, "SymEnumerateModulesW64"); + dynSymGetModuleInfo64W = (PSYMGETMODULEINFO64W)GetProcAddress(module, "SymGetModuleInfoW64"); + + if(!dynSymInitializeW || + !dynSymEnumerateModules64W || + !dynSymGetModuleInfo64W) + { + RDCERR("Couldn't get some dbghelp function"); + ret = false; + return ret; + } + + dynSymInitializeW(GetCurrentProcess(), L".", TRUE); + + HMODULE hModule = NULL; + GetModuleHandleEx( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR)&dllLocator, + &hModule); + + if(hModule != NULL) + { + MODULEINFO modinfo = { 0 }; + + BOOL result = GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(modinfo)); + + if(result != FALSE) + { + renderdocBase = modinfo.lpBaseOfDll; + renderdocSize = modinfo.SizeOfImage; + } + } + + ret = true; + return ret; +} + +/////////////////////////////////////////////////// + +struct CV_INFO_PDB70 +{ + DWORD CvSignature; + GUID Signature; + DWORD Age; + char PdbFileName[1024]; +}; + +struct EnumBuf +{ + char *bufPtr; + size_t size; +}; + +struct EnumModChunk +{ + DWORD64 base; + DWORD size; + DWORD age; + GUID guid; + size_t imageNameLen; + // WCHAR* imageName; // follows (null terminated) +}; + +BOOL CALLBACK EnumModule(PCWSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) +{ + EnumBuf *buf = (EnumBuf *)UserContext; + + IMAGEHLP_MODULEW64 ModInfo; + ZeroMemory(&ModInfo, sizeof(IMAGEHLP_MODULEW64)); + ModInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); + BOOL res = dynSymGetModuleInfo64W(GetCurrentProcess(), BaseOfDll, &ModInfo); + DWORD err = GetLastError(); + + EnumModChunk chunk; + + chunk.base = BaseOfDll; + chunk.size = ModInfo.ImageSize; + + // can't get symbol the easy way, let's walk the PE structure. + // Thanks to http://msdn.microsoft.com/en-us/library/ms809762.aspx + // and also http://www.debuginfo.com/articles/debuginfomatch.html + if(ModInfo.PdbSig70.Data1 == 0 && ModInfo.SymType == SymPdb ) + { + BYTE *addr32 = (BYTE *)BaseOfDll; + +#ifndef WIN64 + RDCASSERT((BaseOfDll & 0xffffffff00000000ULL) == 0x0ULL); // we're downcasting technically, make sure. +#endif + + PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)addr32; + + char *PE00 = (char *)(addr32 + dosheader->e_lfanew); + PIMAGE_FILE_HEADER fileHeader = (PIMAGE_FILE_HEADER)(PE00+4); + PIMAGE_OPTIONAL_HEADER optHeader = (PIMAGE_OPTIONAL_HEADER)((BYTE *)fileHeader+sizeof(IMAGE_FILE_HEADER)); + + PIMAGE_SECTION_HEADER sections = (PIMAGE_SECTION_HEADER)((BYTE *)optHeader+sizeof(IMAGE_OPTIONAL_HEADER)); + + DWORD dbgSize = optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + DWORD dbgOffset = optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + PIMAGE_DEBUG_DIRECTORY debugDir = (PIMAGE_DEBUG_DIRECTORY)(addr32 + dbgOffset); + + CV_INFO_PDB70 *pdb70Data = (CV_INFO_PDB70*)(addr32 + debugDir->AddressOfRawData); + + chunk.age = pdb70Data->Age; + chunk.guid = pdb70Data->Signature; + } + else + { + chunk.age = ModInfo.PdbAge; + chunk.guid = ModInfo.PdbSig70; + } + + WCHAR *pdb = ModInfo.CVData; + + if(pdb == NULL || pdb[0] == 0) + pdb = ModInfo.ImageName; + + chunk.imageNameLen = wcslen(pdb)+1; // include null terminator + + if(buf->bufPtr) + { + memcpy(buf->bufPtr, &chunk, sizeof(EnumModChunk)); buf->bufPtr += sizeof(EnumModChunk); + memcpy(buf->bufPtr, pdb, chunk.imageNameLen*sizeof(WCHAR)); buf->bufPtr += chunk.imageNameLen*sizeof(WCHAR); + } + + buf->size += sizeof(EnumModChunk) + chunk.imageNameLen*sizeof(WCHAR); + + return TRUE; +} + +void Win32Callstack::Collect() +{ + std::vector stack32; + + stack32.resize(64); + + USHORT num = RtlCaptureStackBackTrace(0, 63, &stack32[0], NULL); + + stack32.resize(num); + + while(!stack32.empty() && + (uint64_t)stack32[0] >= (uint64_t)renderdocBase && + (uint64_t)stack32[0] <= (uint64_t)renderdocBase+renderdocSize) + { + stack32.erase(stack32.begin()); + } + + m_NumLevels = stack32.size(); + m_AllocStack = m_AddrStack = new DWORD64[m_NumLevels]; + for(size_t i=0; i < m_NumLevels; i++) + m_AddrStack[i] = (DWORD64)stack32[i]; +} + +Win32Callstack::Win32Callstack() +{ + bool ret = InitDbgHelp(); + + m_AllocStack = m_AddrStack = NULL; + m_NumLevels = 0; + + if(ret && renderdocBase != NULL) + Collect(); +} + +Win32Callstack::Win32Callstack(DWORD64 *calls, size_t numLevels) +{ + m_NumLevels = numLevels; + m_AllocStack = m_AddrStack = new DWORD64[m_NumLevels]; + for(size_t i=0; i < m_NumLevels; i++) + m_AddrStack[i] = calls[i]; +} + +Win32Callstack::~Win32Callstack() +{ + SAFE_DELETE_ARRAY(m_AllocStack); +} + +wstring Win32CallstackResolver::pdbBrowse(wstring startingPoint) +{ + OPENFILENAME ofn; + RDCEraseMem(&ofn, sizeof(ofn)); + + wchar_t outBuf[MAX_PATH*2]; + wcscpy_s(outBuf, startingPoint.c_str()); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.lpstrTitle = _T("Locate PDB File"); + ofn.lpstrFilter = _T("PDB File\0*.pdb\0"); + ofn.lpstrFile = outBuf; + ofn.nMaxFile = MAX_PATH*2-1; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; // | OFN_ENABLEINCLUDENOTIFY | OFN_ENABLEHOOK + + BOOL ret = GetOpenFileName(&ofn); + + if(ret == FALSE) + return L""; + + return outBuf; +} + +void Win32CallstackResolver::OpenPdblocateHandle() +{ + STARTUPINFOW si; + RDCEraseEl(si); + + PROCESS_INFORMATION pi; + RDCEraseEl(pi); + + wchar_t locateCmd[128] = {0}; + + wcscpy_s(locateCmd, L"\".\\pdblocate\\pdblocate.exe\""); + + BOOL success = CreateProcessW(NULL, locateCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + if(!success) + return; + + Sleep(100); + + CloseHandle(pi.hThread); + + pdblocateProcess = pi.hProcess; + + pdblocatePipe = CreateFileW(L"\\\\.\\pipe\\RenderDoc.pdblocate", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if(pdblocatePipe == INVALID_HANDLE_VALUE) + { + RDCERR("Couldn't open pdblocate pipe"); + CloseHandle(pdblocatePipe); + pdblocatePipe = NULL; + return; + } + + DWORD mode = PIPE_READMODE_MESSAGE; + success = SetNamedPipeHandleState(pdblocatePipe, &mode, NULL, NULL); + + if(!success) + { + RDCERR("Couldn't set pdblocate pipe to message mode"); + CloseHandle(pdblocatePipe); + pdblocatePipe = NULL; + return; + } +} + +void *Win32CallstackResolver::SendRecvPipeMessage(wstring message) +{ + DWORD written = 0; + DWORD msgLen = (DWORD)message.length()*sizeof(wchar_t); + BOOL success = WriteFile(pdblocatePipe, message.c_str(), msgLen, &written, NULL); + + if(!success || written != msgLen) + { + DWORD err = GetLastError(); + return NULL; + } + + byte *bufPtr = (byte *)pipeMessageBuf; + DWORD bufSize = sizeof(pipeMessageBuf); + + do + { + DWORD read = 0; + success = ReadFile(pdblocatePipe, bufPtr, bufSize, &read, NULL); + + RDCDEBUG("'%ls' -> %lu", message.c_str(), read); + + DWORD err = GetLastError(); + if (!success && err != ERROR_MORE_DATA) + { + break; + } + + bufPtr += read; + bufSize -= read; + } while (!success); + + RDCDEBUG("buf: %02x %02x %02x %02x", bufPtr[0], bufPtr[1], bufPtr[2], bufPtr[3]); + + return pipeMessageBuf; +} + +std::wstring Win32CallstackResolver::LookupModule(wchar_t *modName, GUID guid, DWORD age) +{ + wchar_t msg[1024] = {0}; + swprintf_s(msg, L"lookup %d %d %d %d %d %d %d %d %d %d %d %d %ls", age, + guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7], + modName); + + wchar_t *ret = (wchar_t *)SendRecvPipeMessage(msg); + + wstring result = (ret == NULL ? L"" : ret); + + if(result == L"Not Found") + result = L""; + + return result; +} + +void Win32CallstackResolver::SetModuleBaseAddress(uint32_t moduleId, DWORD64 base) +{ + wchar_t msg[1024]; + swprintf_s(msg, L"baseaddr %d %llu", moduleId, base); + SendRecvPipeMessage(msg); +} + +uint32_t Win32CallstackResolver::GetModuleID(wstring pdbName, GUID guid, DWORD age) +{ + wchar_t msg[1024] = {0}; + swprintf_s(msg, L"getmodule %d %d %d %d %d %d %d %d %d %d %d %d %ls", age, + guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7], + pdbName.c_str()); + + uint32_t *modID = (uint32_t *)SendRecvPipeMessage(msg); + + return modID == NULL ? 0 : *modID; +} + +Win32CallstackResolver::AddrInfo Win32CallstackResolver::GetAddrInfoForModule(uint32_t moduleId, DWORD64 addr) +{ + wchar_t msg[1024]; + swprintf_s(msg, L"getaddr %d %llu", moduleId, addr); + + AddrInfo *info = (AddrInfo *)SendRecvPipeMessage(msg); + return info == NULL ? AddrInfo() : *info; +} + +Win32CallstackResolver::Win32CallstackResolver(char *moduleDB, size_t DBSize, wstring pdbSearchPaths, volatile bool *killSignal) +{ + wstring configPath = FileIO::GetAppFolderFilename(L"config.ini"); + { + FILE *f = NULL; + _wfopen_s(&f, configPath.c_str(), L"a"); + if(f) fclose(f); + } + + wchar_t inputBuf[2048]; + GetPrivateProfileStringW(L"renderdoc", L"ignores", NULL, &inputBuf[0], 2048, configPath.c_str()); + wstring ignores = inputBuf; + split(ignores, pdbIgnores, L';'); + + split(pdbSearchPaths, pdbRememberedPaths, L';'); + + EnumModChunk *chunk = (EnumModChunk *)moduleDB; + WCHAR *modName = (WCHAR *)(moduleDB+sizeof(EnumModChunk)); + + pdblocateProcess = NULL; + pdblocatePipe = NULL; + + OpenPdblocateHandle(); + + // loop over all our modules + for(char *end = moduleDB + DBSize; + moduleDB < end; + moduleDB += sizeof(EnumModChunk)+(chunk->imageNameLen)*sizeof(WCHAR) ) + { + chunk = (EnumModChunk *)moduleDB; + modName = (WCHAR *)(moduleDB+sizeof(EnumModChunk)); + + if(killSignal && *killSignal) + break; + + Module m; + + m.name = modName; + m.base = chunk->base; + m.size = chunk->size; + m.moduleId = 0; + + if(find(pdbIgnores.begin(), pdbIgnores.end(), m.name) != pdbIgnores.end()) + { + RDCWARN("Not attempting to get symbols for %ls", m.name.c_str()); + + modules.push_back(m); + continue; + } + + // get default pdb (this also looks up symbol server etc) + // relies on pdblocate. Always done in unicode + std::wstring defaultPdb = LookupModule(modName, chunk->guid, chunk->age); + + // strip newline + if(defaultPdb != L"" && defaultPdb[defaultPdb.length()-1] == '\n') + defaultPdb.pop_back(); + + // if we didn't even get a default pdb we'll have to prompt first time through + bool failed = false; + + if(defaultPdb == L"") + { + defaultPdb = strlower(basename(m.name)); + strreplace(defaultPdb, L".dll", L".pdb"); + strreplace(defaultPdb, L".exe", L".pdb"); + failed = true; + } + + std::wstring pdbName = defaultPdb; + + int fallbackIdx = -1; + + while(m.moduleId == 0) + { + if(failed) + { + fallbackIdx++; + // try one of the folders we've been given, just in case the symbols + // are there + if(fallbackIdx < (int)pdbRememberedPaths.size()) + { + pdbName = pdbRememberedPaths[fallbackIdx] + L"\\" + basename(pdbName); + } + else + { + pdbName = dirname(defaultPdb) + L"\\" + basename(defaultPdb); + + // prompt for new pdbName, unless it's renderdoc or dbghelp + if(pdbName.find(L"renderdoc.") != wstring::npos || + pdbName.find(L"dbghelp.") != wstring::npos) + pdbName = L""; + else + pdbName = pdbBrowse(pdbName); + + // user cancelled, just don't load this pdb + if(pdbName == L"") + break; + } + + failed = false; + } + + m.moduleId = GetModuleID(pdbName, chunk->guid, chunk->age); + + if(m.moduleId == 0) + { + failed = true; + } + else + { + if(fallbackIdx >= (int)pdbRememberedPaths.size()) + { + wstring dir = dirname(pdbName); + if(find(pdbRememberedPaths.begin(), pdbRememberedPaths.end(), dir) == pdbRememberedPaths.end()) + { + pdbRememberedPaths.push_back(dir); + } + } + } + } + + // didn't load the pdb? go to the next module. + if (m.moduleId == 0) + { + modules.push_back(m); // still add the module, with 0 module id + + RDCWARN("Couldn't get symbols for %ls", m.name.c_str()); + + // silently ignore renderdoc.dll and dbghelp.dll without asking to permanently ignore + if(m.name.find(L"renderdoc") != wstring::npos || + m.name.find(L"dbghelp") != wstring::npos) + continue; + +#if defined(UNICODE) + wchar_t text[1024]; + wsprintf(text, L"Do you want to permanently ignore this file?\nPath: %ls", m.name.c_str()); +#else + char text[1024]; + wsprintf(text, "Do you want to permanently ignore this file?\nPath: %hs", m.name.c_str()); +#endif + + int ret = MessageBox(NULL, text, _T("Ignore this pdb?"), MB_YESNO); + + if(ret == IDYES) + pdbIgnores.push_back(m.name); + + continue; + } + + SetModuleBaseAddress(m.moduleId, chunk->base); + + RDCLOG("Loaded Symbols for %ls", m.name.c_str()); + + modules.push_back(m); + } + + sort( pdbIgnores.begin(), pdbIgnores.end() ); + pdbIgnores.erase( unique( pdbIgnores.begin(), pdbIgnores.end() ), pdbIgnores.end() ); + merge(pdbIgnores, ignores, L';'); + WritePrivateProfileStringW(L"renderdoc", L"ignores", ignores.c_str(), configPath.c_str()); + + int a=0; +} + +Win32CallstackResolver::~Win32CallstackResolver() +{ + if(pdblocatePipe != NULL) + CloseHandle(pdblocatePipe); + if(pdblocateProcess != NULL) + TerminateProcess(pdblocateProcess, 0); +} + +Callstack::AddressDetails Win32CallstackResolver::GetAddr(DWORD64 addr) +{ + AddrInfo info; + + info.lineNum = 0; + memset(info.fileName, 0, sizeof(info.fileName)); + memset(info.fileName, 0, sizeof(info.funcName)); + + wcsncpy_s(info.fileName, L"Unknown", 126); + wsprintfW(info.funcName, L"0x%08I64x", addr); + + for(size_t i=0; i < modules.size(); i++) + { + DWORD64 base = modules[i].base; + DWORD size = modules[i].size; + if(addr > modules[i].base && addr < modules[i].base + modules[i].size) + { + if(modules[i].moduleId != 0) + info = GetAddrInfoForModule(modules[i].moduleId, addr); + + wcsncpy_s(info.fileName, modules[i].name.c_str(), 126); + + break; + } + } + + Callstack::AddressDetails ret; + ret.filename = info.fileName; + ret.function = info.funcName; + ret.line = info.lineNum; + + return ret; +} + +//////////////////////////////////////////////////////////////////// +// implement public interface + +namespace Callstack +{ + void Init() + { + ::InitDbgHelp(); + } + + Stackwalk *Collect() + { + return new Win32Callstack(); + } + + Stackwalk *Load(uint64_t *calls, size_t numLevels) + { + return new Win32Callstack(calls, numLevels); + } + + StackResolver *MakeResolver(char *moduleDB, size_t DBSize, wstring pdbSearchPaths, volatile bool *killSignal) + { + return new Win32CallstackResolver(moduleDB, DBSize, pdbSearchPaths, killSignal); + } + + bool GetLoadedModules(char *&buf, size_t &size) + { + EnumBuf e; + e.bufPtr = buf; + e.size = 0; + + bool inited = InitDbgHelp(); + + if(inited) + dynSymEnumerateModules64W(GetCurrentProcess(), &EnumModule, &e); + + size = e.size; + + return true; + } +}; // namespace Callstack \ No newline at end of file diff --git a/renderdoc/os/win32/win32_network.cpp b/renderdoc/os/win32/win32_network.cpp new file mode 100644 index 0000000000..6646ae3219 --- /dev/null +++ b/renderdoc/os/win32/win32_network.cpp @@ -0,0 +1,325 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include + +#include "os/os_specific.h" + +namespace Network +{ + +void Init() +{ + WSAData wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); +} + +void Shutdown() +{ + WSACleanup(); +} + +Socket::~Socket() +{ + Shutdown(); +} + +void Socket::Shutdown() +{ + if(Connected()) + { + shutdown((SOCKET)socket, SD_BOTH); + closesocket((SOCKET)socket); + socket = -1; + } +} + +bool Socket::Connected() +{ + return (SOCKET)socket != INVALID_SOCKET; +} + +Socket *Socket::AcceptClient(bool wait) +{ + do + { + SOCKET s = accept(socket, NULL, NULL); + + if(s != INVALID_SOCKET) + { + u_long enable = 1; + ioctlsocket(s, FIONBIO, &enable); + + BOOL nodelay = TRUE; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char *)&nodelay, sizeof(nodelay)); + + return new Socket((ptrdiff_t)s); + } + + int err = WSAGetLastError(); + + if(err != WSAEWOULDBLOCK) + { + RDCWARN("accept: %d", err); + Shutdown(); + } + + Threading::Sleep(4); + } while(wait); + + return NULL; +} + +bool Socket::SendDataBlocking(const void *buf, uint32_t length) +{ + if(length == 0) return true; + + uint32_t sent = 0; + + char *src = (char *)buf; + + u_long enable = 0; + ioctlsocket(socket, FIONBIO, &enable); + + while(sent < length) + { + int ret = send(socket, src, length-sent, 0); + + if(ret <= 0) + { + int err = WSAGetLastError(); + + if(err == WSAEWOULDBLOCK) + { + ret = 0; + } + else + { + RDCWARN("send: %d", err); + Shutdown(); + return false; + } + } + + sent += ret; + src += ret; + } + + enable = 1; + ioctlsocket(socket, FIONBIO, &enable); + + RDCASSERT(sent == length); + + return true; +} + +bool Socket::IsRecvDataWaiting() +{ + char dummy; + int ret = recv(socket, &dummy, 1, MSG_PEEK); + + if(ret == 0) + { + Shutdown(); + return false; + } + else if(ret <= 0) + { + int err = WSAGetLastError(); + + if(err == WSAEWOULDBLOCK) + { + ret = 0; + } + else + { + RDCWARN("recv: %d", err); + Shutdown(); + return false; + } + } + + return ret > 0; +} + +bool Socket::RecvDataBlocking(void *buf, uint32_t length) +{ + if(length == 0) return true; + + uint32_t received = 0; + + char *dst = (char *)buf; + + u_long enable = 0; + ioctlsocket(socket, FIONBIO, &enable); + + while(received < length) + { + int ret = recv(socket, dst, length-received, 0); + + if(ret == 0) + { + Shutdown(); + return false; + } + else if(ret <= 0) + { + int err = WSAGetLastError(); + + if(err == WSAEWOULDBLOCK) + { + ret = 0; + } + else + { + RDCWARN("recv: %d", err); + Shutdown(); + return false; + } + } + + received += ret; + dst += ret; + } + + enable = 1; + ioctlsocket(socket, FIONBIO, &enable); + + RDCASSERT(received == length); + + return true; +} + +Socket *CreateServerSocket(const char *bindaddr, uint16_t port, int queuesize) +{ + SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(s == INVALID_SOCKET) + return NULL; + + sockaddr_in addr; + RDCEraseEl(addr); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(bindaddr); + addr.sin_port = htons(port); + + int result = bind(s, (SOCKADDR *)&addr, sizeof(addr)); + if(result == SOCKET_ERROR) + { + RDCWARN("Failed to bind to %hs:%d - %d", bindaddr, port, WSAGetLastError()); + closesocket(s); + return NULL; + } + + result = listen(s, queuesize); + if(result == SOCKET_ERROR) + { + RDCWARN("Failed to listen on %hs:%d - %d", bindaddr, port, WSAGetLastError()); + closesocket(s); + return NULL; + } + + u_long nonblock = 1; + ioctlsocket(s, FIONBIO, &nonblock); + + return new Socket((ptrdiff_t)s); +} + +Socket *CreateClientSocket(const wchar_t *host, uint16_t port, int timeoutMS) +{ + wchar_t portstr[7] = {0}; + StringFormat::wsnprintf(portstr, 6, L"%d", port); + + addrinfoW hints; + RDCEraseEl(hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + addrinfoW *result = NULL; + GetAddrInfoW(host, portstr, &hints, &result); + + for(addrinfoW *ptr = result; ptr != NULL; ptr = ptr->ai_next) + { + SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(s == INVALID_SOCKET) + return NULL; + + u_long enable = 1; + ioctlsocket(s, FIONBIO, &enable); + + int result = connect(s, ptr->ai_addr, (int)ptr->ai_addrlen); + if(result == SOCKET_ERROR) + { + fd_set set; + FD_ZERO(&set); + FD_SET(s, &set); + + int err = WSAGetLastError(); + + if(err == WSAEWOULDBLOCK) + { + timeval timeout; + timeout.tv_sec = (timeoutMS/1000); + timeout.tv_usec = (timeoutMS%1000)*1000; + result = select(0, NULL, &set, NULL, &timeout); + + if(result <= 0) + { + RDCDEBUG("connect timed out"); + closesocket(s); + continue; + } + else + { + RDCDEBUG("connect before timeout"); + } + } + else + { + RDCDEBUG("problem other than blocking"); + closesocket(s); + continue; + } + } + else + { + RDCDEBUG("connected immediately"); + } + + BOOL nodelay = TRUE; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char *)&nodelay, sizeof(nodelay)); + + return new Socket((ptrdiff_t)s); + } + + RDCWARN("Failed to connect to %ls:%d", host, port); + return NULL; +} + +}; \ No newline at end of file diff --git a/renderdoc/os/win32/win32_process.cpp b/renderdoc/os/win32/win32_process.cpp new file mode 100644 index 0000000000..c8c57d1dfa --- /dev/null +++ b/renderdoc/os/win32/win32_process.cpp @@ -0,0 +1,422 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" + +#include "core/core.h" + +#include "common/string_utils.h" + +#include +#include +#include + +#include +using std::string; + +void InjectDLL(HANDLE hProcess, wstring libName) +{ + wchar_t dllPath[MAX_PATH + 1] = {0}; + wcscpy_s(dllPath, libName.c_str()); + + static HMODULE kernel32 = GetModuleHandle(_T("Kernel32")); + + void *remoteMem = VirtualAllocEx(hProcess, NULL, sizeof(dllPath), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + WriteProcessMemory(hProcess, remoteMem, (void *)dllPath, sizeof(dllPath), NULL); + + HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(kernel32, "LoadLibraryW"), remoteMem, 0, NULL); + WaitForSingleObject(hThread, INFINITE); + + CloseHandle(hThread); + VirtualFreeEx(hProcess, remoteMem, sizeof(dllPath), MEM_RELEASE); +} + +uintptr_t FindRemoteDLL(DWORD pid, wstring libName) +{ + HANDLE hModuleSnap = INVALID_HANDLE_VALUE; + + libName = strlower(libName); + + // up to 10 retries + for(int i=0; i < 10; i++) + { + hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); + + if(hModuleSnap == INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError(); + + RDCWARN("CreateToolhelp32Snapshot(%u) -> 0x%08x", pid, err); + + // retry if error is ERROR_BAD_LENGTH + if(err == ERROR_BAD_LENGTH) + continue; + } + + // didn't retry, or succeeded + break; + } + + if(hModuleSnap == INVALID_HANDLE_VALUE) + { + RDCERR("Couldn't create toolhelp dump of modules in process %u", pid); + return 0; + } + + MODULEENTRY32 me32; + RDCEraseEl(me32); + me32.dwSize = sizeof(MODULEENTRY32); + + BOOL success = Module32First(hModuleSnap, &me32); + + if(success == FALSE) + { + DWORD err = GetLastError(); + + RDCERR("Couldn't get first module in process %u: 0x%08x", pid, err); + CloseHandle(hModuleSnap); + return 0; + } + + uintptr_t ret = 0; + + int numModules = 0; + + do + { + wchar_t modnameLower[MAX_MODULE_NAME32+1]; + RDCEraseEl(modnameLower); + wcsncpy_s(modnameLower, me32.szModule, MAX_MODULE_NAME32); + + wchar_t *wc = &modnameLower[0]; + while(*wc) + { + *wc = towlower(*wc); + wc++; + } + + numModules++; + + if(wcsstr(modnameLower, libName.c_str())) + { + ret = (uintptr_t)me32.modBaseAddr; + } + } while(ret == 0 && Module32Next(hModuleSnap, &me32)); + + if(ret == 0) + { + RDCERR("Couldn't find module '%ls' among %d modules", libName.c_str(), numModules); + } + + CloseHandle(hModuleSnap); + + return ret; +} + +void InjectFunctionCall(HANDLE hProcess, uintptr_t renderdoc_remote, const char *funcName, void *data, const size_t dataLen) +{ + if(dataLen == 0) + { + RDCERR("Invalid function call injection attempt"); + return; + } + + RDCDEBUG("Injecting call to %hs", funcName); + + HMODULE renderdoc_local = GetModuleHandleA("renderdoc.dll"); + + uintptr_t func_local = (uintptr_t)GetProcAddress(renderdoc_local, funcName); + + // we've found SetCaptureOptions in our local instance of the module, now calculate the offset and so get the function + // in the remote module (which might be loaded at a different base address + uintptr_t func_remote = func_local + renderdoc_remote - (uintptr_t)renderdoc_local; + + void *remoteMem = VirtualAllocEx(hProcess, NULL, dataLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + SIZE_T numWritten; + WriteProcessMemory(hProcess, remoteMem, data, dataLen, &numWritten); + + HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)func_remote, remoteMem, 0, NULL); + WaitForSingleObject(hThread, INFINITE); + + ReadProcessMemory(hProcess, remoteMem, data, dataLen, &numWritten); + + CloseHandle(hThread); + VirtualFreeEx(hProcess, remoteMem, dataLen, MEM_RELEASE); +} + +uint32_t Process::InjectIntoProcess(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit) +{ + CaptureOptions options; + if(opts) options = *opts; + + HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | PROCESS_VM_READ | SYNCHRONIZE, + FALSE, pid ); + + if(options.DelayForDebugger > 0) + { + RDCDEBUG("Waiting for debugger attach to %lu", pid); + uint32_t timeout = 0; + + BOOL debuggerAttached = FALSE; + + while(!debuggerAttached) + { + CheckRemoteDebuggerPresent(hProcess, &debuggerAttached); + + Sleep(10); + timeout += 10; + + if(timeout > options.DelayForDebugger*1000) + break; + } + + if(debuggerAttached) + RDCDEBUG("Debugger attach detected after %.2f s", float(timeout)/1000.0f); + else + RDCDEBUG("Timed out waiting for debugger, gave up after %u s", options.DelayForDebugger); + } + + RDCLOG("Injecting renderdoc into process %lu", pid); + + wchar_t renderdocPath[MAX_PATH] = {0}; + GetModuleFileNameW(GetModuleHandleA("renderdoc.dll"), &renderdocPath[0], MAX_PATH-1); + + BOOL isWow64 = FALSE; + BOOL success = IsWow64Process(hProcess, &isWow64); + + if(!success) + { + RDCERR("Couldn't determine bitness of process"); + CloseHandle(hProcess); + return 0; + } + +#if !defined(WIN64) + if(!isWow64) + { + RDCERR("Can't capture x64 process with x86 renderdoc"); + CloseHandle(hProcess); + return 0; + } +#else + // farm off to x86 version + if(isWow64) + { + wchar_t *slash = wcsrchr(renderdocPath, L'\\'); + + if(slash) *slash = 0; + + wcscat_s(renderdocPath, L"\\x86\\renderdoccmd.exe"); + + PROCESS_INFORMATION pi; + STARTUPINFO si; + SECURITY_ATTRIBUTES pSec; + SECURITY_ATTRIBUTES tSec; + + RDCEraseEl(pi); + RDCEraseEl(si); + RDCEraseEl(pSec); + RDCEraseEl(tSec); + + pSec.nLength = sizeof(pSec); + tSec.nLength = sizeof(tSec); + + wchar_t *paramsAlloc = new wchar_t[256]; + + string optstr = opts->ToString(); + + _snwprintf_s(paramsAlloc, 255, 255, L"\"%ls\" -cap32for64 %d \"%ls\" \"%hs\"", renderdocPath, pid, logfile, optstr.c_str()); + + BOOL retValue = CreateProcessW(NULL, paramsAlloc, &pSec, &tSec, false, CREATE_SUSPENDED, NULL, NULL, &si, &pi); + + SAFE_DELETE_ARRAY(paramsAlloc); + + if (!retValue) + { + RDCERR("Can't spawn x86 renderdoccmd - missing files?"); + return 0; + } + + ResumeThread(pi.hThread); + WaitForSingleObject(pi.hThread, INFINITE); + CloseHandle(pi.hThread); + + DWORD exitCode = 0; + GetExitCodeProcess(pi.hProcess, &exitCode); + CloseHandle(pi.hProcess); + + if(waitForExit) + WaitForSingleObject(hProcess, INFINITE); + + CloseHandle(hProcess); + + return (uint32_t)exitCode; + } +#endif + + // misc + InjectDLL(hProcess, L"kernel32.dll"); + + // D3D11 + InjectDLL(hProcess, L"d3d9.dll"); + InjectDLL(hProcess, L"d3d11.dll"); + InjectDLL(hProcess, L"dxgi.dll"); + + // OpenGL + InjectDLL(hProcess, L"opengl32.dll"); + InjectDLL(hProcess, L"gdi32.dll"); + + InjectDLL(hProcess, renderdocPath); + + uintptr_t loc = FindRemoteDLL(pid, L"renderdoc.dll"); + + uint32_t remoteident = 0; + + if(loc == 0) + { + RDCERR("Can't locate renderdoc.dll in remote PID %d", pid); + } + else + { + // safe to cast away the const as we know these functions don't modify the parameters + + if(logfile != NULL) + InjectFunctionCall(hProcess, loc, "RENDERDOC_SetLogFile", (wchar_t *)logfile, (wcslen(logfile)+1)*sizeof(wchar_t)); + + if(opts != NULL) + InjectFunctionCall(hProcess, loc, "RENDERDOC_SetCaptureOptions", (CaptureOptions *)opts, sizeof(CaptureOptions)); + + InjectFunctionCall(hProcess, loc, "RENDERDOC_InitRemoteAccess", &remoteident, sizeof(remoteident)); + } + + if(waitForExit) + WaitForSingleObject(hProcess, INFINITE); + + CloseHandle(hProcess); + + return remoteident; +} + +uint32_t Process::CreateAndInjectIntoProcess(const wchar_t *app, const wchar_t *workingDir, const wchar_t *cmdLine, + const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit) +{ + void *func = GetProcAddress(GetModuleHandleA("renderdoc.dll"), "RENDERDOC_SetLogFile"); + + if (func == NULL) + { + RDCERR("Can't find required export function in renderdoc.dll - corrupted/missing file?"); + return 0; + } + + PROCESS_INFORMATION pi; + STARTUPINFO si; + SECURITY_ATTRIBUTES pSec; + SECURITY_ATTRIBUTES tSec; + + RDCEraseEl(pi); + RDCEraseEl(si); + RDCEraseEl(pSec); + RDCEraseEl(tSec); + + pSec.nLength = sizeof(pSec); + tSec.nLength = sizeof(tSec); + + wstring workdir = dirname(wstring(app)); + + if(workingDir != NULL && workingDir[0] != 0) + workdir = workingDir; + + wchar_t *paramsAlloc = NULL; + + // CreateProcessW can modify the params, need space. + size_t len = wcslen(app)+10; + + if(cmdLine != NULL && cmdLine[0] != 0) + len += wcslen(cmdLine); + + paramsAlloc = new wchar_t[len]; + + RDCEraseMem(paramsAlloc, len); + + wcscpy_s(paramsAlloc, len, L"\""); + wcscat_s(paramsAlloc, len, app); + wcscat_s(paramsAlloc, len, L"\""); + + if(cmdLine != NULL && cmdLine[0] != 0) + { + wcscat_s(paramsAlloc, len, L" "); + wcscat_s(paramsAlloc, len, cmdLine); + } + + BOOL retValue = CreateProcessW(NULL, paramsAlloc, + &pSec, &tSec, false, CREATE_SUSPENDED, + NULL, workdir.c_str(), &si, &pi); + + SAFE_DELETE_ARRAY(paramsAlloc); + + // don't need it + CloseHandle(pi.hProcess); + + if (!retValue) + { + RDCERR("Process %ls could not be loaded.", app); + return 0; + } + + uint32_t ret = InjectIntoProcess(pi.dwProcessId, logfile, opts, false); + + if(ret == 0) + { + ResumeThread(pi.hThread); + CloseHandle(pi.hThread); + return 0; + } + + ResumeThread(pi.hThread); + + if(waitForExit) + WaitForSingleObject(pi.hThread, INFINITE); + + CloseHandle(pi.hThread); + + return ret; +} + +void *Process::GetFunctionAddress(const char *module, const char *function) +{ + HMODULE mod = GetModuleHandleA(module); + if(mod == 0) + return NULL; + + return (void *)GetProcAddress(mod, function); +} + +uint32_t Process::GetCurrentPID() +{ + return (uint32_t)GetCurrentProcessId(); +} + diff --git a/renderdoc/os/win32/win32_shellext.cpp b/renderdoc/os/win32/win32_shellext.cpp new file mode 100644 index 0000000000..804d92c728 --- /dev/null +++ b/renderdoc/os/win32/win32_shellext.cpp @@ -0,0 +1,336 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// in this file we define the shell extension that renderdoc sets up to be able to +// display thumbnails of captures in windows explorer. We register as a thumbnail +// provider and either the installer or the UI installs the appropriate registry keys. + +#include +#include +#include "common/common.h" +#include "core/core.h" +#include "serialise/serialiser.h" + +#include "3rdparty/jpeg-compressor/jpgd.h" + +// {5D6BF029-A6BA-417A-8523-120492B1DCE3} +static const GUID CLSID_RDCThumbnailProvider = { 0x5d6bf029, 0xa6ba, 0x417a, { 0x85, 0x23, 0x12, 0x4, 0x92, 0xb1, 0xdc, 0xe3 } }; + +unsigned int numProviders = 0; + +struct RDCThumbnailProvider : public IThumbnailProvider, IInitializeWithStream +{ + unsigned int m_iRefcount; + bool m_Inited; + Serialiser *m_Ser; + + RDCThumbnailProvider() + : m_iRefcount(1), + m_Inited(false), + m_Ser(NULL) + { + InterlockedIncrement(&numProviders); + } + + virtual ~RDCThumbnailProvider() + { + InterlockedDecrement(&numProviders); + SAFE_DELETE(m_Ser); + } + + ULONG STDMETHODCALLTYPE AddRef() + { + InterlockedIncrement(&m_iRefcount); + return m_iRefcount; + } + ULONG STDMETHODCALLTYPE Release() + { + unsigned int ret = InterlockedDecrement(&m_iRefcount); + if(ret == 0) + delete this; + return ret; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == CLSID_RDCThumbnailProvider) + { + *ppvObject = (void *)this; + AddRef(); + return S_OK; + } + else if(riid == __uuidof(IUnknown)) + { + *ppvObject = (void *)(IUnknown *)(IThumbnailProvider *)this; + AddRef(); + return S_OK; + } + else if(riid == __uuidof(IThumbnailProvider)) + { + *ppvObject = (void *)(IThumbnailProvider *)this; + AddRef(); + return S_OK; + } + else if(riid == __uuidof(IInitializeWithStream)) + { + *ppvObject = (void *)(IInitializeWithStream *)this; + AddRef(); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; + } + + virtual HRESULT STDMETHODCALLTYPE Initialize(IStream *pstream, DWORD grfMode) + { + if(m_Inited) + return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED); + + byte *buf = new byte[512*1024 + 1]; + ULONG numRead = 0; + HRESULT hr = pstream->Read(buf, 512*1024, &numRead); + + if(hr != S_OK && hr != S_FALSE) + { + delete[] buf; + return E_INVALIDARG; + } + + RDCLOG("RDCThumbnailProvider Initialize read %d bytes from file", numRead); + + m_Ser = new Serialiser(numRead, buf, true); + + m_Inited = true; + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha) + { + RDCLOG("RDCThumbnailProvider GetThumbnail %d", cx); + + if(!m_Inited || !m_Ser) + { + RDCERR("Not initialized"); + return E_NOTIMPL; + } + + if(m_Ser->HasError()) + { + RDCERR("Problem serialising file"); + return E_NOTIMPL; + } + + int ctx = m_Ser->PushContext(NULL, 1, false); + + if(ctx != THUMBNAIL_DATA) + { + return E_NOTIMPL; + } + + bool HasThumbnail = false; + m_Ser->Serialise(NULL, HasThumbnail); + + if(!HasThumbnail) + { + return E_NOTIMPL; + } + + byte *jpgbuf = NULL; + size_t thumblen = 0; + uint32_t thumbwidth = 0, thumbheight = 0; + { + m_Ser->Serialise("ThumbWidth", thumbwidth); + m_Ser->Serialise("ThumbHeight", thumbheight); + m_Ser->SerialiseBuffer("ThumbnailPixels", jpgbuf, thumblen); + } + + if(jpgbuf == NULL) + { + return E_NOTIMPL; + } + + int w = thumbwidth; + int h = thumbheight; + int comp = 3; + byte *thumbpixels = jpgd::decompress_jpeg_image_from_memory(jpgbuf, (int)thumblen, &w, &h, &comp, 3); + + delete[] jpgbuf; + + float aspect = float(thumbwidth)/float(thumbheight); + + BITMAPV5HEADER bi; + RDCEraseEl(bi); + bi.bV5Size = sizeof(BITMAPV5HEADER); + bi.bV5Width = RDCMIN((LONG)cx, (LONG)thumbwidth); + bi.bV5Height = (LONG)(bi.bV5Width/aspect); + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00FF0000; + bi.bV5GreenMask = 0x0000FF00; + bi.bV5BlueMask = 0x000000FF; + bi.bV5AlphaMask = 0xFF000000; + + HDC dc = ::CreateCompatibleDC(0); + + RGBQUAD* pArgb; + *phbmp = ::CreateDIBSection(dc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&pArgb, NULL, 0); + + float widthf = float(thumbwidth); + float heightf = float(thumbheight); + + if(*phbmp) + { + DWORD *pBits = (DWORD*)pArgb; + for(int y = 0; y < bi.bV5Height; y++) + { + for(int x = 0; x < bi.bV5Width; x++) + { + *pBits = 0xff000000; + + byte *srcPixel = NULL; + + float xf = float(x)/float(bi.bV5Width); + float yf = float(bi.bV5Height-y-1)/float(bi.bV5Height); + + srcPixel = &thumbpixels[ 3*(uint32_t(xf*widthf) + thumbwidth*uint32_t(yf*heightf)) ]; + + *pBits |= (srcPixel[0] << 16); + *pBits |= (srcPixel[1] << 8); + *pBits |= (srcPixel[2] << 0); + + pBits++; + } + } + } + + free(thumbpixels); + + DeleteObject(dc); + + *pdwAlpha = WTSAT_ARGB; + + return S_OK; + } + +}; + +struct RDCThumbnailProviderFactory : public IClassFactory +{ + unsigned int m_iRefcount; + + RDCThumbnailProviderFactory() + : m_iRefcount(1) + { + } + + virtual ~RDCThumbnailProviderFactory() + { + } + + ULONG STDMETHODCALLTYPE AddRef() + { + InterlockedIncrement(&m_iRefcount); + return m_iRefcount; + } + ULONG STDMETHODCALLTYPE Release() + { + unsigned int ret = InterlockedDecrement(&m_iRefcount); + if(ret == 0) + delete this; + return ret; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IClassFactory)) + { + *ppvObject = (void *)(IClassFactory *)this; + AddRef(); + return S_OK; + } + else if(riid == __uuidof(IUnknown)) + { + *ppvObject = (void *)(IUnknown *)this; + AddRef(); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; + } + + virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) + { + if(pUnkOuter != NULL) + { + return CLASS_E_NOAGGREGATION; + } + + if(riid == CLSID_RDCThumbnailProvider) + { + *ppvObject = (void *)(new RDCThumbnailProvider()); + return S_OK; + } + else if(riid == __uuidof(IThumbnailProvider)) + { + *ppvObject = (void *)(new RDCThumbnailProvider()); + return S_OK; + } + else if(riid == __uuidof(IUnknown)) + { + *ppvObject = (void *)(IUnknown *)(IThumbnailProvider *)(new RDCThumbnailProvider()); + return S_OK; + } + + *ppvObject = NULL; + + return E_NOINTERFACE; + } + + virtual HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) { locked = (fLock == TRUE); return S_OK; } + + bool locked; +}; + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + if(rclsid == CLSID_RDCThumbnailProvider) + { + *ppv = (LPVOID)(new RDCThumbnailProviderFactory); + return S_OK; + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +STDAPI DllCanUnloadNow() +{ + if(numProviders > 0) + return S_FALSE; + + return S_OK; +} diff --git a/renderdoc/os/win32/win32_stringio.cpp b/renderdoc/os/win32/win32_stringio.cpp new file mode 100644 index 0000000000..946c61f36d --- /dev/null +++ b/renderdoc/os/win32/win32_stringio.cpp @@ -0,0 +1,363 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" + +#include +#include +#include + +#include +#include + +#include +using std::set; + +// gives us an address to identify this dll with +static int dllLocator=0; + +string GetEmbeddedResourceWin32(int resource) +{ + HMODULE mod = NULL; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)&dllLocator, &mod); + + HRSRC res = FindResource(mod, MAKEINTRESOURCE(resource), MAKEINTRESOURCE(TYPE_EMBED)); + int err = GetLastError(); + HGLOBAL data = LoadResource(mod, res); + DWORD resSize = SizeofResource(mod, res); + const char* resData = (const char*)LockResource(data); + + return string(resData, resData+resSize); +} + +namespace Keyboard +{ + void Init() + { + } + + set inputWindows; + + void AddInputWindow(void *wnd) + { + inputWindows.insert((HWND)wnd); + } + + void RemoveInputWindow(void *wnd) + { + inputWindows.erase((HWND)wnd); + } + + bool GetKeyState(KeyButton key) + { + int vk = 0; + + switch(key) + { + case eKey_F11: vk = VK_F11; break; + case eKey_F12: vk = VK_F12; break; + case eKey_PrtScrn: vk = VK_SNAPSHOT; break; + default: + return false; + } + + bool keydown = GetAsyncKeyState(vk) != 0; + + if(inputWindows.empty() || !keydown) + return keydown; + + for(auto it=inputWindows.begin(); it != inputWindows.end(); ++it) + { + HWND w = *it; + HWND fore = GetForegroundWindow(); + + while(w) + { + if(w == fore) + return keydown; + + w = GetParent(w); + } + } + + return false; + } +} + +namespace FileIO +{ + void GetExecutableFilename(wstring &selfName) + { + wchar_t curFile[512] = {0}; + GetModuleFileNameW(NULL, curFile, 511); + + selfName = curFile; + } + + void GetDefaultFiles(const wchar_t *logBaseName, wstring &capture_filename, wstring &logging_filename, wstring &target) + { + wchar_t temp_filename[MAX_PATH]; + + GetTempPathW(MAX_PATH, temp_filename); + + wchar_t curFile[512]; + GetModuleFileNameW(NULL, curFile, 512); + + wchar_t fn[MAX_PATH]; + wcscpy_s(fn, MAX_PATH, curFile); + + wchar_t *mod = wcsrchr(fn, L'.'); + if(mod) *mod = 0; + mod = wcsrchr(fn, L'/'); + if(!mod) mod = fn; + mod = wcsrchr(mod, L'\\'); + + mod++; // now points to base filename without extension + + target = mod; + + time_t t = time(NULL); + tm now; + localtime_s(&now, &t); + + wchar_t *filename_start = temp_filename+wcslen(temp_filename); + + wsprintf(filename_start, L"%ls_%04d.%02d.%02d_%02d.%02d.rdc", mod, 1900+now.tm_year, now.tm_mon+1, now.tm_mday, now.tm_hour, now.tm_min); + + capture_filename = temp_filename; + + *filename_start = 0; + + wsprintf(filename_start, L"%ls_%04d.%02d.%02d_%02d.%02d.%02d.log", logBaseName, 1900+now.tm_year, now.tm_mon+1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); + + logging_filename = temp_filename; + } + + wstring GetAppFolderFilename(wstring filename) + { + PWSTR appDataPath; + SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_SIMPLE_IDLIST|KF_FLAG_DONT_UNEXPAND, NULL, &appDataPath); + wstring appdata = appDataPath; + CoTaskMemFree(appDataPath); + + if(appdata[appdata.size()-1] == '/' || appdata[appdata.size()-1] == '\\') appdata.pop_back(); + + appdata += L"\\renderdoc\\"; + + CreateDirectoryW(appdata.c_str(), NULL); + + return appdata + filename; + } + + uint64_t GetModifiedTimestamp(const wchar_t *filename) + { + struct _stat st; + int res = _wstat(filename, &st); + + if(res == 0) + { + return (uint64_t)st.st_mtime; + } + + return 0; + } + + void CopyFileW(const wchar_t *from, const wchar_t *to, bool allowOverwrite) + { + ::CopyFileW(from, to, allowOverwrite == false); + } + + void UnlinkFileW(const wchar_t *path) + { + ::DeleteFileW(path); + } + + FILE *fopen(const wchar_t *filename, const wchar_t *mode) + { + FILE *ret = NULL; + ::_wfopen_s(&ret, filename, mode); + return ret; + } + + size_t fread(void *buf, size_t elementSize, size_t count, FILE *f) { return ::fread(buf, elementSize, count, f); } + size_t fwrite(const void *buf, size_t elementSize, size_t count, FILE *f) { return ::fwrite(buf, elementSize, count, f); } + int fprintf(FILE *f, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + + int ret = ::fprintf(f, fmt, args); + + va_end(args); + + return ret; + } + + uint64_t ftell64(FILE *f) { return ::_ftelli64(f); } + void fseek64(FILE *f, uint64_t offset, int origin) { ::_fseeki64(f, offset, origin); } + + int fclose(FILE *f) { return ::fclose(f); } +}; + +namespace StringFormat +{ + int snprintf(char *str, size_t bufSize, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + + int ret = vsnprintf(str, bufSize, fmt, args); + + va_end(args); + + return ret; + } + + int wsnprintf(wchar_t *str, size_t bufSize, const wchar_t *format, ...) + { + va_list args; + va_start(args, format); + + int ret = ::_vsnwprintf_s(str, bufSize, bufSize, format, args); + + va_end(args); + + return ret; + } + + int vsnprintf(char *str, size_t bufSize, const char *format, va_list args) + { + return ::vsprintf_s(str, bufSize, format, args); + } + + void sntimef(char *str, size_t bufSize, const char *format) + { + time_t tim; + time(&tim); + + tm tmv; + localtime_s(&tmv, &tim); + + strftime(str, bufSize, format, &tmv); + } + + void wcsncpy(wchar_t *dst, const wchar_t *src, size_t count) + { + ::wcsncpy_s(dst, count, src, count); + } + + string Fmt(const char *format, ...) + { + va_list args; + va_start(args, format); + + int size = _vscprintf(format, args)+1; + + char *buf = new char[size]; + + StringFormat::vsnprintf(buf, size, format, args); + + va_end(args); + + string ret = buf; + + delete[] buf; + + return ret; + } + + wstring WFmt(const wchar_t *format, ...) + { + va_list args; + va_start(args, format); + + int size = _vscwprintf(format, args)+1; + + wchar_t *buf = new wchar_t[size]; + + ::vswprintf_s(buf, size, format, args); + + va_end(args); + + wstring ret = buf; + + delete[] buf; + + return ret; + } + + // save on reallocation, keep a persistent scratch buffer for conversions + vector charBuffer; + vector wcharBuffer; + + string Wide2UTF8(const wstring &s) + { + // include room for null terminator, assuming unicode input (not ucs) + // utf-8 characters can be max 4 bytes. We can afford to be generous about + // this length as we resize relatively rarely. + size_t len = (s.length()+1)*4; + + if(charBuffer.size() < len) + charBuffer.resize(len); + + int ret = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, &charBuffer[0], (int)len, NULL, NULL); + + if(ret == 0) + { +#if !defined(_RELEASE) + RDCWARN("Failed to convert wstring: \"%ls\"", s.c_str()); +#endif + return ""; + } + + // convert to string from null-terminated string - utf-8 never contains + // 0 bytes before the null terminator, and this way we don't care if + // charBuffer is larger than the string + return string(&charBuffer[0]); + } + + wstring UTF82Wide(const string &s) + { + // Include room for null terminator. Since we're converting from utf-8, + // worst case it's ascii and every byte is a character so length is the same + size_t len = s.length()+1; + + if(wcharBuffer.size() < len) + wcharBuffer.resize(len); + + int ret = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, &wcharBuffer[0], (int)len); + + if(ret == 0) + { +#if !defined(_RELEASE) + RDCWARN("Failed to convert utf-8 string: \"%s\"", s.c_str()); +#endif + return L""; + } + + return wstring(&wcharBuffer[0]); + } +}; + diff --git a/renderdoc/os/win32/win32_threading.cpp b/renderdoc/os/win32/win32_threading.cpp new file mode 100644 index 0000000000..14ec0b4965 --- /dev/null +++ b/renderdoc/os/win32/win32_threading.cpp @@ -0,0 +1,140 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "os/os_specific.h" + +double Timing::GetTickFrequency() +{ + LARGE_INTEGER li; + QueryPerformanceFrequency(&li); + return double(li.QuadPart)/1000.0; +} + +uint64_t Timing::GetTick() +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + + return li.QuadPart; +} + +namespace Atomic +{ + int32_t Inc32(volatile int32_t *i) + { + return (int32_t)InterlockedIncrement((volatile LONG *)i); + } + + int64_t Inc64(volatile int64_t *i) + { + return (int64_t)InterlockedIncrement64((volatile LONG64 *)i); + } + + int64_t Dec64(volatile int64_t *i) + { + return (int64_t)InterlockedDecrement64((volatile LONG64 *)i); + } + + int64_t ExchAdd64(volatile int64_t *i, int64_t a) + { + return (int64_t)InterlockedExchangeAdd64((volatile LONG64 *)i, a); + } +}; + +namespace Threading +{ + + CriticalSection::CriticalSectionTemplate() + { + InitializeCriticalSection(&m_Data); + } + + CriticalSection::~CriticalSectionTemplate() + { + DeleteCriticalSection(&m_Data); + } + + void CriticalSection::Lock() + { + EnterCriticalSection(&m_Data); + } + + bool CriticalSection::Trylock() + { + return TryEnterCriticalSection(&m_Data) == TRUE; + } + + void CriticalSection::Unlock() + { + LeaveCriticalSection(&m_Data); + } + + struct ThreadInitData + { + ThreadEntry entryFunc; + void *userData; + }; + + static DWORD __stdcall sThreadInit(void *init) + { + ThreadInitData *data = (ThreadInitData *)init; + + // delete before going into entry function so lifetime is limited. + ThreadInitData local = *data; + delete data; + + local.entryFunc(local.userData); + + return 0; + } + + ThreadHandle CreateThread(ThreadEntry entryFunc, void *userData) + { + ThreadInitData *initData = new ThreadInitData; + initData->entryFunc = entryFunc; + initData->userData = userData; + + HANDLE h = ::CreateThread(NULL, 0, &sThreadInit, (void *)initData, 0, NULL); + + return (ThreadHandle)h; + } + + void JoinThread(ThreadHandle handle) + { + if(handle == 0) return; + WaitForSingleObject((HANDLE)handle, INFINITE); + } + + void CloseThread(ThreadHandle handle) + { + if(handle == 0) return; + CloseHandle((HANDLE)handle); + } + + void Sleep(uint32_t milliseconds) + { + ::Sleep((DWORD)milliseconds); + } +}; \ No newline at end of file diff --git a/renderdoc/os/win32_specific.h b/renderdoc/os/win32_specific.h new file mode 100644 index 0000000000..e73ee57b68 --- /dev/null +++ b/renderdoc/os/win32_specific.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include "data/resource.h" + +#define __PRETTY_FUNCTION_SIGNATURE__ __FUNCSIG__ + +#define GetEmbeddedResource(filename) GetEmbeddedResourceWin32( CONCAT(RESOURCE_, filename) ) +string GetEmbeddedResourceWin32(int resource); + +namespace OSUtility +{ + inline void ForceCrash() { *((int *)NULL) = 0; } + inline void DebugBreak() { __debugbreak(); } + inline bool DebuggerPresent() { return ::IsDebuggerPresent() == TRUE; } + inline void DebugOutputA(const char *str) { OutputDebugStringA(str); } +}; + +namespace Threading +{ + typedef CriticalSectionTemplate CriticalSection; +}; diff --git a/renderdoc/renderdoc.config b/renderdoc/renderdoc.config new file mode 100644 index 0000000000..8cec188b38 --- /dev/null +++ b/renderdoc/renderdoc.config @@ -0,0 +1 @@ +// ADD PREDEFINED MACROS HERE! diff --git a/renderdoc/renderdoc.creator b/renderdoc/renderdoc.creator new file mode 100644 index 0000000000..e94cbbd302 --- /dev/null +++ b/renderdoc/renderdoc.creator @@ -0,0 +1 @@ +[General] diff --git a/renderdoc/renderdoc.files b/renderdoc/renderdoc.files new file mode 100644 index 0000000000..576d053ef8 --- /dev/null +++ b/renderdoc/renderdoc.files @@ -0,0 +1,89 @@ +3rdparty/jpeg-compressor/jpgd.cpp +3rdparty/jpeg-compressor/jpgd.h +3rdparty/jpeg-compressor/jpge.cpp +3rdparty/jpeg-compressor/jpge.h +3rdparty/jpeg-compressor/LICENSE.txt +3rdparty/lz4/lz4.c +3rdparty/lz4/lz4.h +common/common.cpp +common/common.h +common/globalconfig.h +common/threading.h +common/timing.h +common/utils.h +common/wrapped_pool.h +core/core.cpp +core/core.h +core/crash_handler.h +core/remote_access.cpp +core/remote_replay.cpp +core/replay_proxy.cpp +core/replay_proxy.h +core/resource_manager.cpp +core/resource_manager.h +core/socket_helpers.h +data/debugcbuffers.h +data/debugcommon.hlsl +data/debugdisplay.hlsl +data/debugtext.hlsl +data/histogram.hlsl +data/multisample.hlsl +data/renderdoc.rc +data/resource.h +driver/gl/official/glcorearb.h +driver/gl/official/glext.h +driver/gl/official/glxext.h +driver/gl/official/wglext.h +driver/gl/gl_common.cpp +driver/gl/gl_common.h +driver/gl/gl_context_driver.cpp +driver/gl/gl_device_driver.cpp +driver/gl/gl_driver.cpp +driver/gl/gl_driver.h +driver/gl/gl_enum.h +driver/gl/gl_hookset.h +driver/gl/gl_hookset_defs.h +driver/gl/gl_manager.cpp +driver/gl/gl_manager.h +driver/gl/gl_replay.cpp +driver/gl/gl_replay.h +driver/gl/gl_resources.cpp +driver/gl/gl_resources.h +hooks/gl_linux_hooks.cpp +maths/camera.cpp +maths/camera.h +maths/formatpacking.h +maths/half_convert.h +maths/matrix.cpp +maths/matrix.h +maths/quat.h +maths/vec.h +os/linux/linux_callstack.cpp +os/linux/linux_network.cpp +os/linux/linux_process.cpp +os/linux/linux_stringio.cpp +os/linux/linux_threading.cpp +os/linux_specific.h +os/os_specific.cpp +os/os_specific.h +replay/basic_types.cpp +replay/basic_types.h +replay/capture_options.h +replay/control_types.h +replay/d3d11_pipestate.h +replay/data_types.h +replay/entry_points.cpp +replay/renderdoc.h +replay/replay_driver.h +replay/replay_enums.h +replay/replay_output.cpp +replay/replay_renderer.cpp +replay/replay_renderer.h +replay/shader_types.h +replay/type_helpers.cpp +replay/type_helpers.h +serialise/serialiser.cpp +serialise/serialiser.h +hooks/linux_libentry.cpp +hooks/hooks.h +hooks/hooks.cpp diff --git a/renderdoc/renderdoc.includes b/renderdoc/renderdoc.includes new file mode 100644 index 0000000000..80e52ce593 --- /dev/null +++ b/renderdoc/renderdoc.includes @@ -0,0 +1 @@ +./ diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj new file mode 100644 index 0000000000..3bb48c07fe --- /dev/null +++ b/renderdoc/renderdoc.vcxproj @@ -0,0 +1,382 @@ + + + + + Profile + Win32 + + + Profile + x64 + + + Release + Win32 + + + Release + x64 + + + + {E2B46D67-90E2-40B6-9597-72930E7845E5} + Win32Proj + renderdoc + renderdoc + + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(ProgramFiles)\Windows Kits\8.1\Debuggers\inc;$(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(VSInstallDir)\DIA SDK\include;$(SolutionDir)\breakpad;$(IncludePath) + $(ProgramFiles)\Windows Kits\8.1\lib\win8\um\x86;$(SolutionDir)\breakpad\lib32;$(LibraryPath) + $(ProgramFiles)\Windows Kits\8.1\bin\x86;$(ExecutablePath) + $(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(ExcludePath) + + + false + $(SolutionDir)\$(Platform)\$(Configuration)\ + $(ProgramFiles)\Windows Kits\8.1\Debuggers\inc;$(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(VSInstallDir)\DIA SDK\include;$(SolutionDir)\breakpad;$(IncludePath) + $(ProgramFiles)\Windows Kits\8.1\lib\win8\um\x64;$(SolutionDir)\breakpad\lib64;$(LibraryPath) + $(ProgramFiles)\Windows Kits\8.1\bin;$(ExecutablePath) + $(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(ExcludePath) + + + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(ProgramFiles)\Windows Kits\8.1\Debuggers\inc;$(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(VSInstallDir)\DIA SDK\include;$(SolutionDir)\breakpad;$(IncludePath) + $(ProgramFiles)\Windows Kits\8.1\lib\win8\um\x86;$(SolutionDir)\breakpad\lib32;$(LibraryPath) + $(ProgramFiles)\Windows Kits\8.1\bin\x86;$(ExecutablePath) + $(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(ExcludePath) + + + false + $(SolutionDir)\$(Platform)\$(Configuration)\ + $(ProgramFiles)\Windows Kits\8.1\Debuggers\inc;$(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(VSInstallDir)\DIA SDK\include;$(SolutionDir)\breakpad;$(IncludePath) + $(ProgramFiles)\Windows Kits\8.1\lib\win8\um\x64;$(SolutionDir)\breakpad\lib64;$(LibraryPath) + $(ProgramFiles)\Windows Kits\8.1\bin;$(ExecutablePath) + $(ProgramFiles)\Windows Kits\8.1\Include\um;$(ProgramFiles)\Windows Kits\8.1\Include\shared;$(ExcludePath) + + + + Level4 + NotUsing + MaxSpeed + true + true + RENDERDOC_EXPORTS;RENDERDOC_PLATFORM=win32;USE_BREAKPAD;WIN32;RELEASE;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + + + /wd4100 /wd4189 /wd4127 /DRENDERDOC_PLATFORM=win32 %(AdditionalOptions) + $(ProjectDir) + false + true + true + + + Windows + true + true + true + $(ProjectDir)os\win32\comexport.def + breakpad_common.lib;exception_handler.lib;crash_generation_client.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;psapi.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level4 + NotUsing + MaxSpeed + true + true + RENDERDOC_EXPORTS;RENDERDOC_PLATFORM=win32;USE_BREAKPAD;WIN64;WIN32;RELEASE;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + + + /wd4100 /wd4189 /wd4127 /DRENDERDOC_PLATFORM=win32 %(AdditionalOptions) + $(ProjectDir) + false + true + true + + + Windows + true + true + true + $(ProjectDir)os\win32\comexport.def + breakpad_common.lib;exception_handler.lib;crash_generation_client.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;psapi.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /Y /Q /S $(SolutionDir)\Win32\$(ConfigurationName)\pdblocate $(OutputPath)\pdblocate\ + + + + + Level4 + NotUsing + Disabled + false + false + RENDERDOC_EXPORTS;RENDERDOC_PLATFORM=win32;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + + + /wd4100 /wd4189 /wd4127 %(AdditionalOptions) + false + EnableFastChecks + $(ProjectDir) + false + false + true + true + + + Windows + true + false + false + $(ProjectDir)os\win32\comexport.def + breakpad_common.lib;exception_handler.lib;crash_generation_client.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;psapi.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Default + + + + + + + + + Level4 + NotUsing + Disabled + false + false + RENDERDOC_EXPORTS;RENDERDOC_PLATFORM=win32;WIN64;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + + + /wd4100 /wd4189 /wd4127 /DRENDERDOC_PLATFORM=win32 %(AdditionalOptions) + false + EnableFastChecks + $(ProjectDir) + false + true + true + + + Windows + true + false + false + $(ProjectDir)os\win32\comexport.def + breakpad_common.lib;exception_handler.lib;crash_generation_client.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;psapi.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Default + + + xcopy /Y /Q /S $(SolutionDir)\Win32\$(ConfigurationName)\pdblocate $(OutputPath)\pdblocate\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NoListing + + + + + + + + AssemblyAndSourceCode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters new file mode 100644 index 0000000000..7e588a5c5c --- /dev/null +++ b/renderdoc/renderdoc.vcxproj.filters @@ -0,0 +1,523 @@ + + + + + {97bbc5c9-b6a8-429b-a2d6-16fea62eed1a} + + + {ff594035-e059-4ceb-a85c-ec4dbc83d029} + + + {205098b7-5360-41d3-b186-6fe15b1b4e4b} + + + {c1ae2bd1-c932-42f6-8997-a4553322bdfa} + + + {0e2454ca-656b-499c-bb19-07cf1da7e703} + + + {3e51a921-b167-4794-937d-e77573a928b8} + + + {669b3fbf-5c6d-4c5a-b013-4e28ad5a01a7} + + + {a9a0e0ca-e0e6-4ebb-a21e-f971943c46ba} + + + {358bfcbf-2408-42ff-b4b1-29de135a0fc4} + + + {a8f3f549-4980-4c2f-8fa4-989c22755f07} + + + {fcdcbe00-6b01-4234-9a3b-cc019f88a8ed} + + + {a9f6ac9b-cc6a-4449-be40-a3fad76a0067} + + + {ffbf4a4f-115e-415f-a800-b372db445027} + + + {6308ad7d-d930-4fed-9d4b-68bb66b29a78} + + + {36ccf267-d6c1-41c9-87c3-92c1dfcbe88b} + + + {62242fef-51cb-419e-bbe9-3347653ece06} + + + {880a29ed-1f7d-46f2-9bcd-c4a9b73b7be5} + + + {dfe56374-9726-4919-8529-123cf5ba6ef5} + + + {92099e5e-bd1b-44f6-9556-4dd01c91c23f} + + + {1d17fb69-fd1a-44a6-a530-05642d97ddc6} + + + {911d2076-eaea-4783-b0c3-789e5b6eff1f} + + + {e2f5b1f2-ae41-4e3c-999e-5ade627a91d1} + + + {0ecdcd74-a30b-457e-8b22-92bd58405c56} + + + {889cc549-e49b-430b-9e9b-5a42e7c26b03} + + + + + Common\Maths + + + Common\Maths + + + Common\Maths + + + Common\Serialise + + + Resources + + + hooks + + + Common + + + Common + + + Common + + + Common\Maths + + + Common + + + Common + + + Drivers\D3D11\shaders + + + Drivers\D3D11\shaders + + + Drivers\D3D11\shaders + + + Drivers\D3D11\shaders + + + Drivers\D3D11\shaders + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + OS + + + Drivers\D3D11 + + + OS\Win32 + + + Core + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Drivers\OpenGL\ARB Headers + + + Drivers\OpenGL\ARB Headers + + + Drivers\OpenGL\ARB Headers + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Drivers\OpenGL + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\jpeg-compressor + + + 3rdparty\jpeg-compressor + + + Common\Maths + + + Drivers\OpenGL + + + Core\networking + + + Core\networking + + + 3rdparty\lz4 + + + Core + + + Drivers\OpenGL + + + Replay\external interface + + + Replay\external interface + + + Replay\external interface + + + Replay + + + Replay\external interface + + + Replay\external interface + + + Replay\external interface + + + Replay\external interface + + + Replay + + + Replay + + + Drivers\DXGI + + + Core + + + Common\Maths + + + Replay\external interface + + + Common + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Resources\hlsl + + + Replay\external interface + + + + + Common\Maths + + + Common\Maths + + + Common\Serialise + + + hooks\libs + + + hooks + + + hooks\libs + + + hooks\libs + + + hooks + + + Common + + + Drivers\D3D11\shaders + + + Drivers\D3D11\shaders + + + Drivers\D3D11\shaders + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + OS\Win32 + + + OS\Win32 + + + OS + + + Drivers\D3D11 + + + Drivers\D3D11 + + + Drivers\D3D11 + + + OS\Win32 + + + OS\Win32 + + + Core + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Drivers\OpenGL + + + OS\Win32 + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\mhook + + + 3rdparty\jpeg-compressor + + + 3rdparty\jpeg-compressor + + + OS\Win32 + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Drivers\OpenGL + + + Core\networking + + + Core\networking + + + Core\networking + + + 3rdparty\lz4 + + + Replay + + + Replay + + + Replay + + + Replay + + + Replay + + + hooks\libs + + + Drivers\DXGI + + + Core + + + hooks\libs + + + Drivers\OpenGL + + + Drivers\OpenGL + + + + + OS\Win32 + + + Resources\hlsl + + + Resources\hlsl + + + Resources\hlsl + + + Resources\hlsl + + + Resources\hlsl + + + Resources\glsl + + + Resources\glsl + + + Resources\glsl + + + Resources\glsl + + + Resources\glsl + + + Resources\glsl + + + Resources\glsl + + + + + Resources + + + \ No newline at end of file diff --git a/renderdoc/replay/basic_types.cpp b/renderdoc/replay/basic_types.cpp new file mode 100644 index 0000000000..038f678ce4 --- /dev/null +++ b/renderdoc/replay/basic_types.cpp @@ -0,0 +1,70 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "basic_types.h" + +namespace rdctype +{ + +wstr &wstr::operator =(const std::wstring &in) +{ + Delete(); + count = (int32_t)in.size(); + elems = (wchar_t*)allocate(sizeof(wchar_t)*(count+1)); + memcpy(elems, &in[0], sizeof(wchar_t)*in.size()); + elems[count] = 0; + return *this; +} + +str &str::operator =(const std::string &in) +{ + Delete(); + count = (int32_t)in.size(); + elems = (char*)allocate(sizeof(char)*(count+1)); + memcpy(elems, &in[0], sizeof(char)*in.size()); + elems[count] = 0; + return *this; +} + +wstr &wstr::operator =(const wchar_t *const in) +{ + Delete(); + count = (int32_t)wcslen(in); + elems = (wchar_t*)allocate(sizeof(wchar_t)*(count+1)); + memcpy(elems, &in[0], sizeof(wchar_t)*count); + elems[count] = 0; + return *this; +} + +str &str::operator =(const char *const in) +{ + Delete(); + count = (int32_t)strlen(in); + elems = (char*)allocate(sizeof(char)*(count+1)); + memcpy(elems, &in[0], sizeof(char)*count); + elems[count] = 0; + return *this; +} + +}; // namespace rdctype diff --git a/renderdoc/replay/basic_types.h b/renderdoc/replay/basic_types.h new file mode 100644 index 0000000000..4ea76c4033 --- /dev/null +++ b/renderdoc/replay/basic_types.h @@ -0,0 +1,162 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include +#include +#include + +#include +#include + +// we provide a basic templated type that is a fixed array that just contains a pointer to the element +// array and a size. This could easily map to C as just void* and size but in C++ at least we can be +// type safe. +// +// While we can use STL elsewhere in the main library, we want to expose data to the UI layer as fixed +// arrays so that it's a plain C compatible interface. +namespace rdctype +{ + +template +struct pair +{ + A first; + B second; +}; + +template +struct array +{ + T *elems; + int32_t count; + + array() : elems(0), count(0) {} + ~array() { Delete(); } + void Delete() { deallocate(elems); elems = 0; count = 0; } + + static void deallocate(const void *p) { free((void *)p); } + static void *allocate(size_t s) { return malloc(s); } + + T &operator [](size_t i) { return elems[i]; } + const T &operator [](size_t i) const { return elems[i]; } + + array(const T *const in) { elems = 0; count = 0; *this = in; } + array &operator =(const T *const in); + + array(const std::vector &in) { elems = 0; count = 0; *this = in; } + array &operator =(const std::vector &in) + { + Delete(); + count = (int32_t)in.size(); + elems = (T*)allocate(sizeof(T)*count); + for(int32_t i=0; i < count; i++) + new (elems+i) T(in[i]); + return *this; + } + + array(const array &o) + { elems = 0; count = 0; *this = o; } + + array &operator =(const array &o) + { + // do nothing if we're self-assigning + if(this == &o) return *this; + + Delete(); + count = o.count; + if(count == 0) + { + elems = 0; + } + else + { + elems = (T*)allocate(sizeof(T)*o.count); + for(int32_t i=0; i < count; i++) + new (elems+i) T(o.elems[i]); + } + return *this; + } +}; + +struct str : public rdctype::array +{ + str &operator =(const std::string &in); + str &operator =(const char *const in); + + str() : rdctype::array() {} + str(const str &o) { elems = 0; count = 0; *this = o; } + str &operator =(const str &o) + { + // do nothing if we're self-assigning + if(this == &o) return *this; + + Delete(); + count = o.count; + if(count == 0) + { + elems = NULL; + } + else + { + elems = (char*)allocate(sizeof(char)*(o.count+1)); + memcpy(elems, o.elems, sizeof(char)*o.count); + elems[count] = 0; + } + + return *this; + } +}; + +struct wstr : public rdctype::array +{ + wstr &operator =(const std::wstring &in); + wstr &operator =(const wchar_t *const in); + + wstr() : rdctype::array() {} + wstr(const wstr &o) { elems = 0; count = 0; *this = o; } + wstr &operator =(const wstr &o) + { + // do nothing if we're self-assigning + if(this == &o) return *this; + + Delete(); + count = o.count; + if(count == 0) + { + elems = 0; + } + else + { + elems = (wchar_t*)allocate(sizeof(wchar_t)*(o.count+1)); + memcpy(elems, o.elems, sizeof(wchar_t)*o.count); + elems[count] = 0; + } + + return *this; + } +}; + +}; // namespace rdctype \ No newline at end of file diff --git a/renderdoc/replay/capture_options.h b/renderdoc/replay/capture_options.h new file mode 100644 index 0000000000..849daf4071 --- /dev/null +++ b/renderdoc/replay/capture_options.h @@ -0,0 +1,128 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include // istringstream/ostringstream used to avoid other dependencies + +typedef uint8_t byte; +typedef uint32_t bool32; + +// We give every resource a globally unique ID so that we can differentiate +// between two textures allocated in the same memory (after the first is freed) +// +// it's a struct around a uint64_t to aid in template selection +struct ResourceId +{ + ResourceId() : id() {} + ResourceId(uint64_t val, bool) { id = val; } + + bool operator ==(const ResourceId u) const + { + return id == u.id; + } + + bool operator !=(const ResourceId u) const + { + return id != u.id; + } + + bool operator <(const ResourceId u) const + { + return id < u.id; + } + + uint64_t id; +}; + +struct CaptureOptions +{ + CaptureOptions() + : AllowVSync(true), + AllowFullscreen(true), + DebugDeviceMode(false), + CaptureCallstacks(false), + CaptureCallstacksOnlyDraws(false), + DelayForDebugger(0), + CacheStateObjects(true), + HookIntoChildren(false), + RefAllResources(false), + SaveAllInitials(false), + CaptureAllCmdLists(false) + {} + + bool32 AllowVSync; + bool32 AllowFullscreen; + bool32 DebugDeviceMode; + bool32 CaptureCallstacks; + bool32 CaptureCallstacksOnlyDraws; + uint32_t DelayForDebugger; + bool32 CacheStateObjects; + bool32 HookIntoChildren; + bool32 RefAllResources; + bool32 SaveAllInitials; + bool32 CaptureAllCmdLists; + +#ifdef __cplusplus + void FromString(std::string str) + { + std::istringstream iss(str); + + iss >> AllowFullscreen + >> AllowVSync + >> DebugDeviceMode + >> CaptureCallstacks + >> CaptureCallstacksOnlyDraws + >> DelayForDebugger + >> CacheStateObjects + >> HookIntoChildren + >> RefAllResources + >> SaveAllInitials + >> CaptureAllCmdLists; + } + + std::string ToString() const + { + std::ostringstream oss; + + oss << AllowFullscreen << " " + << AllowVSync << " " + << DebugDeviceMode << " " + << CaptureCallstacks << " " + << CaptureCallstacksOnlyDraws << " " + << DelayForDebugger << " " + << CacheStateObjects << " " + << HookIntoChildren << " " + << RefAllResources << " " + << SaveAllInitials << " " + << CaptureAllCmdLists << " "; + + return oss.str(); + } +#endif +}; + + diff --git a/renderdoc/replay/control_types.h b/renderdoc/replay/control_types.h new file mode 100644 index 0000000000..b559a77655 --- /dev/null +++ b/renderdoc/replay/control_types.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +struct OutputConfig +{ + OutputType m_Type; +}; + +struct MeshDisplay +{ + MeshDataStage type; + + bool32 arcballCamera; + FloatVector cameraPos; + FloatVector cameraRot; + + bool32 ortho; + float fov, aspect, nearPlane, farPlane; + + bool32 thisDrawOnly; + + bool32 showVerts; + FloatVector hilightVerts[3]; + + FloatVector prevMeshColour; + FloatVector currentMeshColour; + + SolidShadeMode solidShadeMode; + bool32 wireframeDraw; +}; + +struct TextureDisplay +{ + ResourceId texid; + float rangemin; + float rangemax; + float scale; + bool32 Red, Green, Blue, Alpha; + float HDRMul; + ResourceId CustomShader; + uint32_t mip; + uint32_t sliceFace; + bool32 rawoutput; + + float offx, offy; + + FloatVector lightBackgroundColour; + FloatVector darkBackgroundColour; + + TextureDisplayOverlay overlay; +}; + +struct RemoteMessage +{ + RemoteMessage() {} + + RemoteMessageType Type; + + struct NewCaptureData + { + uint32_t ID; + uint64_t timestamp; + rdctype::array thumbnail; + rdctype::wstr localpath; + } NewCapture; + + struct RegisterAPIData + { + rdctype::wstr APIName; + } RegisterAPI; + + struct BusyData + { + rdctype::wstr ClientName; + } Busy; +}; diff --git a/renderdoc/replay/d3d11_pipestate.h b/renderdoc/replay/d3d11_pipestate.h new file mode 100644 index 0000000000..f608c985fc --- /dev/null +++ b/renderdoc/replay/d3d11_pipestate.h @@ -0,0 +1,269 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +struct D3D11PipelineState +{ + D3D11PipelineState() {} + + struct InputAssembler + { + InputAssembler() : Bytecode(NULL), Topology(eTopology_Unknown) {} + + struct LayoutInput + { + LayoutInput() : SemanticIndex(0), InputSlot(0), ByteOffset(0), PerInstance(false), InstanceDataStepRate(0) {} + rdctype::wstr SemanticName; + uint32_t SemanticIndex; + ResourceFormat Format; + uint32_t InputSlot; + uint32_t ByteOffset; + bool32 PerInstance; + uint32_t InstanceDataStepRate; + }; + rdctype::array layouts; + ResourceId layout; + ShaderReflection *Bytecode; + + struct VertexBuffer + { + VertexBuffer() : Buffer(), Stride(0), Offset(0) {} + ResourceId Buffer; + uint32_t Stride; + uint32_t Offset; + }; + rdctype::array vbuffers; + + struct IndexBuffer + { + IndexBuffer() : Buffer(), Offset(0) {} + ResourceId Buffer; + ResourceFormat Format; + uint32_t Offset; + } ibuffer; + + PrimitiveTopology Topology; + } m_IA; + + struct ShaderStage + { + ShaderStage() : Shader(), ShaderDetails(NULL) {} + ResourceId Shader; + ShaderReflection *ShaderDetails; + + ShaderStageType stage; + + struct ResourceView + { + ResourceView() : View(), Resource(), + Format(), + Structured(false), BufferStructCount(0), + ElementOffset(0), ElementWidth(0), + FirstElement(0), NumElements(0), + Flags(0), + HighestMip(0), NumMipLevels(0), MipSlice(0), + ArraySize(0), FirstArraySlice(0) {} + + ResourceId View; + ResourceId Resource; + rdctype::wstr Type; + ResourceFormat Format; + + bool32 Structured; + uint32_t BufferStructCount; + + // Buffer (SRV) + uint32_t ElementOffset; + uint32_t ElementWidth; + + // Buffer (UAV) + uint32_t FirstElement; + uint32_t NumElements; + + // BufferEx + uint32_t Flags; + + // Texture + uint32_t HighestMip; + uint32_t NumMipLevels; + + uint32_t MipSlice; + + // Texture Array + uint32_t ArraySize; + uint32_t FirstArraySlice; + }; + rdctype::array SRVs; + rdctype::array UAVs; + + struct Sampler + { + Sampler() : Samp(), MaxAniso(0), MaxLOD(0.0f), MinLOD(0.0f), MipLODBias(0.0f) + { BorderColor[0] = BorderColor[1] = BorderColor[2] = BorderColor[3] = 0.0f; } + ResourceId Samp; + rdctype::wstr AddressU, AddressV, AddressW; + float BorderColor[4]; + rdctype::wstr Comparison; + rdctype::wstr Filter; + uint32_t MaxAniso; + float MaxLOD; + float MinLOD; + float MipLODBias; + }; + rdctype::array Samplers; + + struct CBuffer + { + CBuffer() : Buffer(), VecOffset(0), VecCount(0) {} + ResourceId Buffer; + uint32_t VecOffset; + uint32_t VecCount; + }; + rdctype::array ConstantBuffers; + + rdctype::array ClassInstances; + } m_VS, m_HS, m_DS, m_GS, m_PS, m_CS; + + struct Streamout + { + struct Output + { + Output() : Buffer(), Offset(0) { } + ResourceId Buffer; + uint32_t Offset; + }; + rdctype::array Outputs; + } m_SO; + + struct Rasterizer + { + struct Viewport + { + Viewport(float TX=0.0f, float TY=0.0f, float W=0.0f, float H=0.0f, float MN=0.0f, float MX=0.0f) + : Width(W), Height(H), MinDepth(MN), MaxDepth(MX) + { TopLeft[0] = TX; TopLeft[1] = TY; } + float TopLeft[2]; + float Width, Height; + float MinDepth, MaxDepth; + }; + rdctype::array Viewports; + + struct Scissor + { + Scissor(int l=0, int t=0, int r=0, int b=0) : left(l), top(t), right(r), bottom(b) {} + int32_t left, top, right, bottom; + }; + rdctype::array Scissors; + + struct RasterizerState + { + RasterizerState() + : State(), FillMode(eFill_Solid), CullMode(eCull_None), FrontCCW(false), DepthBias(0), + DepthBiasClamp(0.0f), SlopeScaledDepthBias(0.0f), DepthClip(false), + ScissorEnable(false), MultisampleEnable(false), AntialiasedLineEnable(false), + ForcedSampleCount(0) {} + ResourceId State; + TriangleFillMode FillMode; + TriangleCullMode CullMode; + bool32 FrontCCW; + int32_t DepthBias; + float DepthBiasClamp; + float SlopeScaledDepthBias; + bool32 DepthClip; + bool32 ScissorEnable; + bool32 MultisampleEnable; + bool32 AntialiasedLineEnable; + uint32_t ForcedSampleCount; + } m_State; + } m_RS; + + struct OutputMerger + { + struct DepthStencilState + { + DepthStencilState() + : State(), DepthEnable(false), StencilEnable(false), + StencilReadMask(0), StencilWriteMask(0), StencilRef(0) {} + ResourceId State; + bool32 DepthEnable; + rdctype::wstr DepthFunc; + bool32 DepthWrites; + bool32 StencilEnable; + byte StencilReadMask; + byte StencilWriteMask; + + struct StencilOp + { + rdctype::wstr FailOp; + rdctype::wstr DepthFailOp; + rdctype::wstr PassOp; + rdctype::wstr Func; + } m_FrontFace, m_BackFace; + + uint32_t StencilRef; + } m_State; + + struct BlendState + { + BlendState() : AlphaToCoverage(false), IndependentBlend(false), SampleMask(0) + { BlendFactor[0] = BlendFactor[1] = BlendFactor[2] = BlendFactor[3] = 0.0f; } + + ResourceId State; + + bool32 AlphaToCoverage; + bool32 IndependentBlend; + + struct RTBlend + { + RTBlend() : Enabled(false), WriteMask(0) {} + struct BlendOp + { + rdctype::wstr Source; + rdctype::wstr Destination; + rdctype::wstr Operation; + } m_Blend, m_AlphaBlend; + + rdctype::wstr LogicOp; + + bool32 Enabled; + bool32 LogicEnabled; + byte WriteMask; + }; + rdctype::array Blends; + + float BlendFactor[4]; + uint32_t SampleMask; + } m_BlendState; + + rdctype::array RenderTargets; + + uint32_t UAVStartSlot; + rdctype::array UAVs; + + ShaderStage::ResourceView DepthTarget; + bool32 DepthReadOnly; + bool32 StencilReadOnly; + } m_OM; +}; diff --git a/renderdoc/replay/data_types.h b/renderdoc/replay/data_types.h new file mode 100644 index 0000000000..cbab17c1e9 --- /dev/null +++ b/renderdoc/replay/data_types.h @@ -0,0 +1,210 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +struct FloatVector +{ + FloatVector() {} + FloatVector(float X, float Y, float Z, float W) + : x(X), y(Y), z(Z), w(W) {} + float x, y, z, w; +}; + +struct ResourceFormat +{ + ResourceFormat() + { + rawType = 0; + special = true; + specialFormat = eSpecial_Unknown; + + compCount = compByteWidth = 0; + compType = eCompType_Float; + + srgbCorrected = false; + } + + uint32_t rawType; + + // indicates it's not a type represented with the members below + // usually this means non-uniform across components or block compressed + bool32 special; + SpecialFormat specialFormat; + + rdctype::wstr strname; + + uint32_t compCount; + uint32_t compByteWidth; + FormatComponentType compType; + + bool32 srgbCorrected; +}; + +struct FetchBuffer +{ + ResourceId ID; + rdctype::wstr name; + bool32 customName; + uint32_t length; + uint32_t structureSize; + uint32_t creationFlags; + uint64_t byteSize; +}; + +struct FetchTexture +{ + rdctype::wstr name; + bool32 customName; + ResourceFormat format; + uint32_t dimension; + uint32_t width, height, depth; + ResourceId ID; + bool32 cubemap; + uint32_t mips; + uint32_t arraysize; + uint32_t numSubresources; + uint32_t creationFlags; + uint32_t msQual, msSamp; + uint64_t byteSize; +}; + +struct FetchFrameInfo +{ + uint32_t frameNumber; + uint32_t firstEvent; + uint64_t fileOffset; + ResourceId immContextId; +}; + +struct FetchAPIEvent +{ + uint32_t eventID; + + ResourceId context; + + rdctype::array callstack; + + rdctype::wstr eventDesc; + + uint64_t fileOffset; +}; + +struct DebugMessage +{ + DebugMessageCategory category; + DebugMessageSeverity severity; + uint32_t messageID; + rdctype::str description; +}; + +struct EventUsage +{ + EventUsage() + : eventID(0), usage(eUsage_None) {} + EventUsage(uint32_t e, ResourceUsage u) + : eventID(e), usage(u) {} + + uint32_t eventID; + ResourceUsage usage; +}; + +struct FetchDrawcall +{ + FetchDrawcall() + { + Reset(); + } + + void Reset() + { + eventID = 0; + drawcallID = 0; + numIndices = 0; + numInstances = 0; + indexOffset = 0; + vertexOffset = 0; + instanceOffset = 0; + flags = 0; + context = ResourceId(); + duration = -1.0f; + parent = 0; + previous = 0; + next = 0; + for(int i=0; i < 10; i++) + outputs[i] = ResourceId(); + } + + uint32_t eventID, drawcallID; + + rdctype::wstr name; + + uint32_t flags; + + uint32_t numIndices; + uint32_t numInstances; + uint32_t indexOffset; + uint32_t vertexOffset; + uint32_t instanceOffset; + + ResourceId context; + + double duration; + + int64_t parent; + + int64_t previous; + int64_t next; + + ResourceId outputs[8]; + ResourceId depthOut; + + rdctype::array events; + rdctype::array children; + + rdctype::array debugMessages; +}; + +struct APIProperties +{ + APIPipelineStateType pipelineType; +}; + +struct PixelValue +{ + union + { + float value_f[4]; + uint32_t value_u[4]; + int32_t value_i[4]; + uint16_t value_u16[4]; + }; +}; + +struct PostVSMeshData +{ + rdctype::array buf; + uint32_t numVerts; + PrimitiveTopology topo; +}; diff --git a/renderdoc/replay/entry_points.cpp b/renderdoc/replay/entry_points.cpp new file mode 100644 index 0000000000..de4b6456e0 --- /dev/null +++ b/renderdoc/replay/entry_points.cpp @@ -0,0 +1,309 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "common/common.h" +#include "maths/camera.h" +#include "maths/formatpacking.h" +#include "serialise/serialiser.h" +#include "core/core.h" +#include "replay/replay_renderer.h" +#include "replay/renderdoc.h" + +extern "C" RENDERDOC_API float RENDERDOC_CC Maths_HalfToFloat(uint16_t half) +{ + return ConvertFromHalf(half); +} + +extern "C" RENDERDOC_API uint16_t RENDERDOC_CC Maths_FloatToHalf(float f) +{ + return ConvertToHalf(f); +} + +extern "C" RENDERDOC_API void RENDERDOC_CC Maths_CameraArcball(float dist, const FloatVector &rot, FloatVector *pos, FloatVector *fwd, FloatVector *right) +{ + Camera c; + c.Arcball(dist, Vec3f(rot.x, rot.y, rot.z)); + + Vec3f p = c.GetPosition(); + Vec3f f = c.GetForward(); + Vec3f r = c.GetRight(); + + pos->x = p.x; + pos->y = p.y; + pos->z = p.z; + + fwd->x = f.x; + fwd->y = f.y; + fwd->z = f.z; + + right->x = r.x; + right->y = r.y; + right->z = r.z; +} + +extern "C" RENDERDOC_API void RENDERDOC_CC Maths_CameraFPSLook(const FloatVector &lookpos, const FloatVector &rot, FloatVector *pos, FloatVector *fwd, FloatVector *right) +{ + Camera c; + c.fpsLook(Vec3f(lookpos.x, lookpos.y, lookpos.z), Vec3f(rot.x, rot.y, rot.z)); + + Vec3f p = c.GetPosition(); + Vec3f f = c.GetForward(); + Vec3f r = c.GetRight(); + + pos->x = p.x; + pos->y = p.y; + pos->z = p.z; + + fwd->x = f.x; + fwd->y = f.y; + fwd->z = f.z; + + right->x = r.x; + right->y = r.y; + right->z = r.z; +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_LogText(const wchar_t *text) +{ + RDCLOG("%ls", text); +} + +extern "C" RENDERDOC_API +const wchar_t* RENDERDOC_CC RENDERDOC_GetLogFilename() +{ + return RDCGETLOGFILE(); +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_TriggerExceptionHandler(void *exceptionPtrs, bool crashed) +{ + if(RenderDoc::Inst().GetCrashHandler() == NULL) + return; + + if(exceptionPtrs) + { + RenderDoc::Inst().GetCrashHandler()->WriteMinidump(exceptionPtrs); + } + else + { + if(!crashed) + { + RDCLOG("Writing crash log"); + } + + RenderDoc::Inst().GetCrashHandler()->WriteMinidump(); + + if(!crashed) + { + RenderDoc::Inst().RecreateCrashHandler(); + } + } +} + +extern "C" RENDERDOC_API +bool RENDERDOC_CC RENDERDOC_SupportLocalReplay(const wchar_t *logfile, rdctype::wstr *driver) +{ + if(logfile == NULL) + return false; + + RDCDriver driverType = RDC_Unknown; + wstring driverName = L""; + RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, NULL); + + if(driver) *driver = driverName; + + return RenderDoc::Inst().HasReplayDriver(driverType); +} + +extern "C" RENDERDOC_API +ReplayCreateStatus RENDERDOC_CC RENDERDOC_CreateReplayRenderer(const wchar_t *logfile, float *progress, ReplayRenderer **rend) +{ + if(rend == NULL) return eReplayCreate_InternalError; + + RenderDoc::Inst().SetProgressPtr(progress); + + ReplayRenderer *render = new ReplayRenderer(); + + if(!render) + { + RenderDoc::Inst().SetProgressPtr(NULL); + return eReplayCreate_InternalError; + } + + ReplayCreateStatus ret = render->CreateDevice(logfile); + + if(ret != eReplayCreate_Success) + { + delete render; + RenderDoc::Inst().SetProgressPtr(NULL); + return ret; + } + + *rend = render; + + RenderDoc::Inst().SetProgressPtr(NULL); + return eReplayCreate_Success; +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_SetLogFile(const wchar_t *logfile) +{ + RDCLOG("Using logfile %ls", logfile); + RenderDoc::Inst().SetLogFile(logfile); +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_SetCaptureOptions(const CaptureOptions *opts) +{ + RDCLOG("Setting capture options"); + RenderDoc::Inst().SetCaptureOptions(opts); +} + +extern "C" RENDERDOC_API +uint32_t RENDERDOC_CC RENDERDOC_ExecuteAndInject(const wchar_t *app, const wchar_t *workingDir, const wchar_t *cmdLine, + const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit) +{ + return Process::CreateAndInjectIntoProcess(app, workingDir, cmdLine, logfile, opts, waitForExit); +} + +extern "C" RENDERDOC_API +uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit) +{ + return Process::InjectIntoProcess(pid, logfile, opts, waitForExit); +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_TriggerCapture() +{ + RenderDoc::Inst().TriggerCapture(); +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_QueueCapture(uint32_t frameNumber) +{ + RenderDoc::Inst().QueueCapture(frameNumber); +} + +extern "C" RENDERDOC_API +bool RENDERDOC_CC RENDERDOC_GetThumbnail(const wchar_t *filename, byte *buf, uint32_t &len) +{ + Serialiser ser(filename, Serialiser::READING, false); + + if(ser.HasError()) + return false; + + ser.Rewind(); + + int chunkType = ser.PushContext(NULL, 1, false); + + if(chunkType != THUMBNAIL_DATA) + return false; + + bool HasThumbnail = false; + ser.Serialise(NULL, HasThumbnail); + + if(!HasThumbnail) + return false; + + byte *jpgbuf = NULL; + size_t thumblen = 0; + uint32_t thumbwidth = 0, thumbheight = 0; + { + ser.Serialise("ThumbWidth", thumbwidth); + ser.Serialise("ThumbHeight", thumbheight); + ser.SerialiseBuffer("ThumbnailPixels", jpgbuf, thumblen); + } + + if(jpgbuf == NULL) + return false; + + if(buf == NULL) + { + len = (uint32_t)thumblen; + return true; + } + + if(thumblen > len) + { + delete[] jpgbuf; + return false; + } + + memcpy(buf, jpgbuf, thumblen); + + delete[] jpgbuf; + + return true; +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_FreeArrayMem(const void *mem) +{ + rdctype::array::deallocate(mem); +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_InitRemoteAccess(uint32_t *ident) +{ + if(ident) *ident = RenderDoc::Inst().GetRemoteAccessIdent(); +} + +extern "C" RENDERDOC_API +uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteConnections(const wchar_t *host, uint32_t *idents) +{ + if(idents == NULL) + return RenderDoc_LastCaptureNetworkPort-RenderDoc_FirstCaptureNetworkPort+1; + + wstring s = L"localhost"; + if(host != NULL && host[0] != L'\0') + s = host; + + uint32_t numIdents = 0; + + for(uint16_t ident = RenderDoc_FirstCaptureNetworkPort; ident <= RenderDoc_LastCaptureNetworkPort; ident++) + { + Network::Socket *sock = Network::CreateClientSocket(s.c_str(), ident, 250); + + if(sock) + { + *idents = (uint32_t)ident; + idents++; + numIdents++; + SAFE_DELETE(sock); + } + } + + return numIdents; +} + +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_SpawnReplayHost(volatile bool *killReplay) +{ + bool dummy = false; + + if(killReplay == NULL) killReplay = &dummy; + + RenderDoc::Inst().BecomeReplayHost(*killReplay); +} diff --git a/renderdoc/replay/gl_pipestate.h b/renderdoc/replay/gl_pipestate.h new file mode 100644 index 0000000000..8bb78e2f59 --- /dev/null +++ b/renderdoc/replay/gl_pipestate.h @@ -0,0 +1,93 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +struct GLPipelineState +{ + GLPipelineState() {} + + struct VertexInput + { + VertexInput() : Topology(eTopology_Unknown) {} + + struct VertexAttribute + { + VertexAttribute() : BufferSlot(0), RelativeOffset(0) {} + bool32 Enabled; + ResourceFormat Format; + uint32_t BufferSlot; + uint32_t RelativeOffset; + }; + rdctype::array attributes; + + struct VertexBuffer + { + VertexBuffer() : Buffer(), Stride(0), Offset(0), PerInstance(false), Divisor(0) {} + ResourceId Buffer; + uint32_t Stride; + uint32_t Offset; + bool32 PerInstance; + uint32_t Divisor; + }; + rdctype::array vbuffers; + + struct IndexBuffer + { + IndexBuffer() : Buffer(), Offset(0) {} + ResourceId Buffer; + ResourceFormat Format; + uint32_t Offset; + } ibuffer; + + PrimitiveTopology Topology; + } m_VtxIn; + + struct ShaderStage + { + ShaderStage() : Shader(), ShaderDetails(NULL) {} + ResourceId Shader; + ShaderReflection *ShaderDetails; + + ShaderStageType stage; + } m_VS, m_TCS, m_TES, m_GS, m_FS, m_CS; + + struct Texture + { + ResourceId Resource; + uint32_t FirstSlice; + }; + rdctype::array Textures; + + struct FrameBuffer + { + FrameBuffer() : FBO(), Depth(), Stencil() {} + + ResourceId FBO; + + rdctype::array Color; + ResourceId Depth; + ResourceId Stencil; + } m_FB; +}; \ No newline at end of file diff --git a/renderdoc/replay/renderdoc.h b/renderdoc/replay/renderdoc.h new file mode 100644 index 0000000000..e5cec3e7ab --- /dev/null +++ b/renderdoc/replay/renderdoc.h @@ -0,0 +1,265 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include +#include + +#include "basic_types.h" + +#ifdef WIN32 + +#ifdef RENDERDOC_EXPORTS +#define RENDERDOC_API __declspec(dllexport) +#else +#define RENDERDOC_API __declspec(dllimport) +#endif +#define RENDERDOC_CC __cdecl + +#elif defined(LINUX) + +#ifdef RENDERDOC_EXPORTS +#define RENDERDOC_API __attribute__ ((visibility ("default"))) +#else +#define RENDERDOC_API +#endif + +#define RENDERDOC_CC + +#else + +#error "Unknown platform" + +#endif + +#include "capture_options.h" + +#include "replay_enums.h" + +#include "shader_types.h" +#include "data_types.h" +#include "control_types.h" + +#include "d3d11_pipestate.h" +#include "gl_pipestate.h" + +#ifdef RENDERDOC_EXPORTS +struct ReplayOutput; +#else +struct ReplayOutput { }; +#endif + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetOutputConfig(ReplayOutput *output, const OutputConfig &o); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetTextureDisplay(ReplayOutput *output, const TextureDisplay &o); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetMeshDisplay(ReplayOutput *output, const MeshDisplay &o); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_ClearThumbnails(ReplayOutput *output); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_AddThumbnail(ReplayOutput *output, void *wnd, ResourceId texID); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_Display(ReplayOutput *output); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetPixelContext(ReplayOutput *output, void *wnd); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetPixelContextLocation(ReplayOutput *output, uint32_t x, uint32_t y); +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayOutput_DisablePixelContext(ReplayOutput *output); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_PickPixel(ReplayOutput *output, ResourceId texID, bool customShader, + uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, PixelValue *val); + +#ifdef RENDERDOC_EXPORTS +struct ReplayRenderer; +#else +struct ReplayRenderer { }; +#endif + +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(ReplayRenderer *rend, APIProperties *props); + +extern "C" RENDERDOC_API ReplayOutput* RENDERDOC_CC ReplayRenderer_CreateOutput(ReplayRenderer *rend, void *handle); +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend); +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_HasCallstacks(ReplayRenderer *rend); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_InitResolver(ReplayRenderer *rend); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_SetContextFilter(ReplayRenderer *rend, ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_SetFrameEvent(ReplayRenderer *rend, uint32_t frameID, uint32_t eventID); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetD3D11PipelineState(ReplayRenderer *rend, D3D11PipelineState *state); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetGLPipelineState(ReplayRenderer *rend, GLPipelineState *state); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::wstr *errors); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_FreeCustomShader(ReplayRenderer *rend, ResourceId id); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::wstr *errors); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_ReplaceResource(ReplayRenderer *rend, ResourceId from, ResourceId to); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_RemoveReplacement(ReplayRenderer *rend, ResourceId id); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_FreeTargetResource(ReplayRenderer *rend, ResourceId id); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetFrameInfo(ReplayRenderer *rend, rdctype::array *frame); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, bool includeTimes, rdctype::array *draws); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetTextures(ReplayRenderer *rend, rdctype::array *texs); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array *bufs); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetResolve(ReplayRenderer *rend, uint64_t *callstack, uint32_t callstackLen, rdctype::array *trace); +extern "C" RENDERDOC_API ShaderReflection* RENDERDOC_CC ReplayRenderer_GetShaderDetails(ReplayRenderer *rend, ResourceId shader); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_VSGetDebugStates(ReplayRenderer *rend, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_PSGetDebugStates(ReplayRenderer *rend, uint32_t x, uint32_t y, ShaderDebugTrace *trace); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_CSGetDebugStates(ReplayRenderer *rend, uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetUsage(ReplayRenderer *rend, ResourceId id, rdctype::array *usage); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetCBufferVariableContents(ReplayRenderer *rend, ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array *vars); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_SaveTexture(ReplayRenderer *rend, ResourceId texID, uint32_t mip, const wchar_t *path); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, MeshDataStage stage, PostVSMeshData *data); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetMinMax(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, PixelValue *minval, PixelValue *maxval); +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetHistogram(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], rdctype::array *histogram); + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetBufferData(ReplayRenderer *rend, ResourceId buff, uint32_t offset, uint32_t len, rdctype::array *data); + +#ifdef RENDERDOC_EXPORTS +struct RemoteAccess; +#else +struct RemoteAccess { }; +#endif + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_Shutdown(RemoteAccess *access); + +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RemoteAccess_GetTarget(RemoteAccess *access); +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RemoteAccess_GetAPI(RemoteAccess *access); +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RemoteAccess_GetBusyClient(RemoteAccess *access); + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_TriggerCapture(RemoteAccess *access); +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_QueueCapture(RemoteAccess *access, uint32_t frameNumber); +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_CopyCapture(RemoteAccess *access, uint32_t remoteID, const wchar_t *localpath); + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_ReceiveMessage(RemoteAccess *access, RemoteMessage *msg); + +#ifdef RENDERDOC_EXPORTS +struct RemoteRenderer; +#else +struct RemoteRenderer { }; +#endif + +extern "C" RENDERDOC_API void RENDERDOC_CC RemoteRenderer_Shutdown(RemoteRenderer *remote); + +extern "C" RENDERDOC_API bool RENDERDOC_CC RemoteRenderer_LocalProxies(RemoteRenderer *remote, rdctype::array *out); +extern "C" RENDERDOC_API bool RENDERDOC_CC RemoteRenderer_RemoteSupportedReplays(RemoteRenderer *remote, rdctype::array *out); + +extern "C" RENDERDOC_API ReplayCreateStatus RENDERDOC_CC RemoteRenderer_CreateProxyRenderer(RemoteRenderer *remote, uint32_t proxyid, const wchar_t *logfile, float *progress, ReplayRenderer **rend); + +////////////////////////////////////////////////////////////////////////// +// Maths/format related exports +////////////////////////////////////////////////////////////////////////// + +extern "C" RENDERDOC_API float RENDERDOC_CC Maths_HalfToFloat(uint16_t half); +extern "C" RENDERDOC_API uint16_t RENDERDOC_CC Maths_FloatToHalf(float f); + +extern "C" RENDERDOC_API void RENDERDOC_CC Maths_CameraArcball(float dist, const FloatVector &rot, FloatVector *pos, FloatVector *fwd, FloatVector *right); +extern "C" RENDERDOC_API void RENDERDOC_CC Maths_CameraFPSLook(const FloatVector &lookpos, const FloatVector &rot, FloatVector *pos, FloatVector *fwd, FloatVector *right); + +////////////////////////////////////////////////////////////////////////// +// Create a replay renderer, for playback and analysis. +// +// Takes the filename of the log. Returns NULL in the case of any error. +////////////////////////////////////////////////////////////////////////// + +extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_SupportLocalReplay(const wchar_t *logfile, rdctype::wstr *driverName); +typedef bool (RENDERDOC_CC *pRENDERDOC_SupportLocalReplay)(const wchar_t *logfile, rdctype::wstr *driverName); + +extern "C" RENDERDOC_API ReplayCreateStatus RENDERDOC_CC RENDERDOC_CreateReplayRenderer(const wchar_t *logfile, float *progress, ReplayRenderer **rend); +typedef ReplayCreateStatus (RENDERDOC_CC *pRENDERDOC_CreateReplayRenderer)(const wchar_t *logfile, float *progress, ReplayRenderer **rend); + +////////////////////////////////////////////////////////////////////////// +// Injection/voluntary capture functions. +// +// InjectAndExecute takes an exe path, destination filename and capture options. +// It will launch the exe and then call... +// +// InjectIntoProcess will inject RenderDoc and its dependent dlls into the target process +// if it's able to, and pass in the given options. NOTE: RenderDoc automatically hooks +// any app the dll is loaded into, except where explicitly disallowed or disabled. +// +// SetLogfile and SetCaptureOptions will set the destination filename of any capture +// and the configuration options, respectively. +// +// Takes the filename of the log. Returns NULL in the case of any error. +////////////////////////////////////////////////////////////////////////// + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetLogFile(const wchar_t *logfile); +typedef void (RENDERDOC_CC *pRENDERDOC_SetLogFile)(const wchar_t *logfile); + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetCaptureOptions(const CaptureOptions *opts); +typedef void (RENDERDOC_CC *pRENDERDOC_SetCaptureOptions)(const CaptureOptions *opts); + +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_ExecuteAndInject(const wchar_t *app, const wchar_t *workingDir, const wchar_t *cmdLine, + const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit); +typedef uint32_t (RENDERDOC_CC *pRENDERDOC_ExecuteAndInject)(const wchar_t *app, const wchar_t *workingDir, const wchar_t *cmdLine, + const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit); + +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit); +typedef uint32_t (RENDERDOC_CC *pRENDERDOC_InjectIntoProcess)(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool waitForExit); + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerCapture(); +typedef void (RENDERDOC_CC *pRENDERDOC_TriggerCapture)(); + +////////////////////////////////////////////////////////////////////////// +// Remote access and control +////////////////////////////////////////////////////////////////////////// + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_InitRemoteAccess(uint32_t *ident); +typedef void (RENDERDOC_CC *pRENDERDOC_InitRemoteAccess)(uint32_t *ident); + +extern "C" RENDERDOC_API RemoteAccess* RENDERDOC_CC RENDERDOC_CreateRemoteAccessConnection(const wchar_t *host, uint32_t ident, const wchar_t *clientName, bool forceConnection); +typedef RemoteAccess* (RENDERDOC_CC *pRENDERDOC_CreateRemoteAccessConnection)(const wchar_t *host, uint32_t ident, const wchar_t *clientName, bool forceConnection); + +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteConnections(const wchar_t *host, uint32_t *idents); +typedef uint32_t (RENDERDOC_CC *pRENDERDOC_EnumerateRemoteConnections)(const wchar_t *host, uint32_t *idents); + +extern "C" RENDERDOC_API ReplayCreateStatus RENDERDOC_CC RENDERDOC_CreateRemoteReplayConnection(const wchar_t *host, RemoteRenderer **rend); +typedef ReplayCreateStatus (RENDERDOC_CC *pRENDERDOC_CreateRemoteReplayConnection)(const wchar_t *host, RemoteRenderer **rend); + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SpawnReplayHost(volatile bool *killReplay); +typedef void (RENDERDOC_CC *pRENDERDOC_SpawnReplayHost)(volatile bool *killReplay); + +////////////////////////////////////////////////////////////////////////// +// Miscellaneous! +////////////////////////////////////////////////////////////////////////// + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerExceptionHandler(void *exceptionPtrs, bool crashed); +typedef void (RENDERDOC_CC *pRENDERDOC_TriggerExceptionHandler)(void *exceptionPtrs, bool crashed); + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_LogText(const wchar_t *text); +typedef void (RENDERDOC_CC *pRENDERDOC_LogText)(const wchar_t *text); + +extern "C" RENDERDOC_API const wchar_t* RENDERDOC_CC RENDERDOC_GetLogFilename(); +typedef const wchar_t* (RENDERDOC_CC *pRENDERDOC_GetLogFilename)(); + +extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_GetThumbnail(const wchar_t *filename, byte *buf, uint32_t &len); +typedef bool (RENDERDOC_CC *pRENDERDOC_GetThumbnail)(const wchar_t *filename, byte *buf, uint32_t &len); + +extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_FreeArrayMem(const void *mem); +typedef void (RENDERDOC_CC *pRENDERDOC_FreeArrayMem)(const void *mem); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h new file mode 100644 index 0000000000..53c8114092 --- /dev/null +++ b/renderdoc/replay/replay_driver.h @@ -0,0 +1,144 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "maths/vec.h" +#include "replay/renderdoc.h" +#include "replay/replay_driver.h" +#include "core/core.h" + +struct FetchFrameRecord +{ + FetchFrameInfo frameInfo; + + rdctype::array drawcallList; +}; + +// these two interfaces define what an API driver implementation must provide +// to the replay. At minimum it must implement IRemoteDriver which contains +// all of the functionality that cannot be achieved elsewhere. An IReplayDriver +// is more powerful and can be used as a local replay (with an IRemoteDriver +// proxied elsewhere if necessary). +// +// In this sense, IRemoteDriver is a strict subset of IReplayDriver functionality. +// Wherever at all possible functionality should be added as part of IReplayDriver, +// *not* as part of IRemoteDriver, to keep the burden on remote drivers to a minimum. + +class IRemoteDriver +{ + public: + virtual void Shutdown() = 0; + + virtual APIProperties GetAPIProperties() = 0; + + virtual vector GetBuffers() = 0; + virtual FetchBuffer GetBuffer(ResourceId id) = 0; + + virtual vector GetTextures() = 0; + virtual FetchTexture GetTexture(ResourceId id) = 0; + + virtual ShaderReflection *GetShader(ResourceId id) = 0; + + virtual vector GetUsage(ResourceId id) = 0; + + virtual void SavePipelineState() = 0; + virtual D3D11PipelineState GetD3D11PipelineState() = 0; + virtual GLPipelineState GetGLPipelineState() = 0; + + virtual vector GetFrameRecord() = 0; + + + virtual void ReadLogInitialisation() = 0; + virtual void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) = 0; + virtual void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType) = 0; + + virtual void InitPostVSBuffers(uint32_t frameID, uint32_t eventID) = 0; + + virtual ResourceId GetLiveID(ResourceId id) = 0; + + virtual PostVSMeshData GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) = 0; + + virtual vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) = 0; + virtual byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, size_t &dataSize) = 0; + + virtual void BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) = 0; + virtual void ReplaceResource(ResourceId from, ResourceId to) = 0; + virtual void RemoveReplacement(ResourceId id) = 0; + virtual void FreeTargetResource(ResourceId id) = 0; + + virtual void TimeDrawcalls(rdctype::array &arr) = 0; + + virtual void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) = 0; + + virtual ShaderDebugTrace DebugVertex(uint32_t frameID, uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) = 0; + virtual ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) = 0; + virtual ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]) = 0; + + virtual ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID) = 0; + + virtual bool IsRenderOutput(ResourceId id) = 0; + + virtual void InitCallstackResolver() = 0; + virtual bool HasCallstacks() = 0; + virtual Callstack::StackResolver *GetCallstackResolver() = 0; +}; + +class IReplayDriver : public IRemoteDriver +{ + public: + virtual bool IsRemoteProxy() = 0; + + virtual uint64_t MakeOutputWindow(void *w, bool depth) = 0; + virtual void DestroyOutputWindow(uint64_t id) = 0; + virtual bool CheckResizeOutputWindow(uint64_t id) = 0; + virtual void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) = 0; + virtual void ClearOutputWindowColour(uint64_t id, float col[4]) = 0; + virtual void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil) = 0; + virtual void BindOutputWindow(uint64_t id, bool depth) = 0; + virtual bool IsOutputWindowVisible(uint64_t id) = 0; + virtual void FlipOutputWindow(uint64_t id) = 0; + + virtual bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, float *minval, float *maxval) = 0; + virtual bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], vector &histogram) = 0; + + virtual ResourceId CreateProxyTexture(FetchTexture templateTex) = 0; + virtual void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize) = 0; + + virtual bool SaveTexture(ResourceId tex, uint32_t saveMip, wstring path) = 0; + + virtual void RenderMesh(int frameID, vector eventID, MeshDisplay cfg) = 0; + virtual bool RenderTexture(TextureDisplay cfg) = 0; + + virtual void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) = 0; + virtual ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) = 0; + virtual void FreeCustomShader(ResourceId id) = 0; + + virtual void RenderCheckerboard(Vec3f light, Vec3f dark) = 0; + + virtual void RenderHighlightBox(float w, float h, float scale) = 0; + + virtual void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, float pixel[4]) = 0; +}; diff --git a/renderdoc/replay/replay_enums.h b/renderdoc/replay/replay_enums.h new file mode 100644 index 0000000000..9661bbe9bf --- /dev/null +++ b/renderdoc/replay/replay_enums.h @@ -0,0 +1,356 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +// replay_shader.h + +enum VarType +{ + eVar_Float = 0, + eVar_Int, + eVar_UInt, + eVar_Double, +}; + +enum FormatComponentType +{ + eCompType_None = 0, + eCompType_Float, + eCompType_UNorm, + eCompType_UNorm_SRGB, + eCompType_SNorm, + eCompType_UInt, + eCompType_SInt, + eCompType_Depth, + eCompType_Double, +}; + +enum ShaderResourceType +{ + eResType_None, + eResType_Buffer, + eResType_Texture1D, + eResType_Texture1DArray, + eResType_Texture2D, + eResType_Texture2DArray, + eResType_Texture2DMS, + eResType_Texture2DMSArray, + eResType_Texture3D, + eResType_TextureCube, + eResType_TextureCubeArray, +}; + +enum SystemAttribute +{ + eAttr_None = 0, + eAttr_Position, + eAttr_ClipDistance, + eAttr_CullDistance, + eAttr_RTIndex, + eAttr_ViewportIndex, + eAttr_VertexIndex, + eAttr_PrimitiveIndex, + eAttr_InstanceIndex, + eAttr_DispatchThreadIndex, + eAttr_GroupIndex, + eAttr_GroupFlatIndex, + eAttr_GroupThreadIndex, + eAttr_GSInstanceIndex, + eAttr_OutputControlPointIndex, + eAttr_DomainLocation, + eAttr_IsFrontFace, + eAttr_MSAACoverage, + eAttr_MSAASampleIndex, + eAttr_OuterTessFactor, + eAttr_InsideTessFactor, + eAttr_ColourOutput, + eAttr_DepthOutput, + eAttr_DepthOutputGreaterEqual, + eAttr_DepthOutputLessEqual, +}; + +// replay_render.h + +enum OutputType +{ + eOutputType_None = 0, + eOutputType_TexDisplay, + eOutputType_MeshDisplay, +}; + +enum MeshDataStage +{ + eMeshDataStage_Unknown = 0, + eMeshDataStage_VSIn, + eMeshDataStage_VSOut, + eMeshDataStage_GSOut, +}; + +enum TextureDisplayOverlay +{ + eTexOverlay_None = 0, + eTexOverlay_Drawcall, + eTexOverlay_Wireframe, + eTexOverlay_DepthBoth, + eTexOverlay_StencilBoth, + eTexOverlay_ViewportScissor, + eTexOverlay_NaN, + eTexOverlay_Clipping, +}; + +enum SpecialFormat +{ + eSpecial_Unknown = 0, + eSpecial_BC1, + eSpecial_BC2, + eSpecial_BC3, + eSpecial_BC4, + eSpecial_BC5, + eSpecial_BC6, + eSpecial_BC7, + eSpecial_R10G10B10A2, + eSpecial_R11G11B10, + eSpecial_B5G6R5, + eSpecial_B5G5R5A1, + eSpecial_R9G9B9E5, + eSpecial_B8G8R8A8, + eSpecial_B4G4R4A4, + eSpecial_D24S8, + eSpecial_D32S8, + eSpecial_YUV, +}; + +enum APIPipelineStateType +{ + ePipelineState_D3D11, + ePipelineState_OpenGL, +}; + +enum PrimitiveTopology +{ + eTopology_Unknown, + eTopology_PointList, + eTopology_LineList, + eTopology_LineStrip, + eTopology_LineLoop, + eTopology_TriangleList, + eTopology_TriangleStrip, + eTopology_TriangleFan, + eTopology_LineList_Adj, + eTopology_LineStrip_Adj, + eTopology_TriangleList_Adj, + eTopology_TriangleStrip_Adj, + eTopology_PatchList, + eTopology_PatchList_1CPs = eTopology_PatchList, + eTopology_PatchList_2CPs, + eTopology_PatchList_3CPs, + eTopology_PatchList_4CPs, + eTopology_PatchList_5CPs, + eTopology_PatchList_6CPs, + eTopology_PatchList_7CPs, + eTopology_PatchList_8CPs, + eTopology_PatchList_9CPs, + eTopology_PatchList_10CPs, + eTopology_PatchList_11CPs, + eTopology_PatchList_12CPs, + eTopology_PatchList_13CPs, + eTopology_PatchList_14CPs, + eTopology_PatchList_15CPs, + eTopology_PatchList_16CPs, + eTopology_PatchList_17CPs, + eTopology_PatchList_18CPs, + eTopology_PatchList_19CPs, + eTopology_PatchList_20CPs, + eTopology_PatchList_21CPs, + eTopology_PatchList_22CPs, + eTopology_PatchList_23CPs, + eTopology_PatchList_24CPs, + eTopology_PatchList_25CPs, + eTopology_PatchList_26CPs, + eTopology_PatchList_27CPs, + eTopology_PatchList_28CPs, + eTopology_PatchList_29CPs, + eTopology_PatchList_30CPs, + eTopology_PatchList_31CPs, + eTopology_PatchList_32CPs, +}; + +enum BufferCreationFlags +{ + eBufferCreate_VB = 0x1, + eBufferCreate_IB = 0x2, +}; + +enum TextureCreationFlags +{ + eTextureCreate_SRV = 0x1, + eTextureCreate_RTV = 0x2, + eTextureCreate_DSV = 0x4, + eTextureCreate_UAV = 0x8, + eTextureCreate_SwapBuffer = 0x10, +}; + +enum ShaderStageType +{ + eShaderStage_Vertex = 0, + + eShaderStage_Hull, + eShaderStage_Tess_Control = eShaderStage_Hull, + + eShaderStage_Domain, + eShaderStage_Tess_Eval = eShaderStage_Domain, + + eShaderStage_Geometry, + + eShaderStage_Pixel, + eShaderStage_Fragment = eShaderStage_Pixel, + + eShaderStage_Compute, +}; + +enum DebugMessageCategory +{ + eDbgCategory_Application_Defined = 0, + eDbgCategory_Miscellaneous, + eDbgCategory_Initialization, + eDbgCategory_Cleanup, + eDbgCategory_Compilation, + eDbgCategory_State_Creation, + eDbgCategory_State_Setting, + eDbgCategory_State_Getting, + eDbgCategory_Resource_Manipulation, + eDbgCategory_Execution, + eDbgCategory_Shaders, + eDbgCategory_Deprecated, + eDbgCategory_Undefined, + eDbgCategory_Portability, + eDbgCategory_Performance, +}; + +enum DebugMessageSeverity +{ + eDbgSeverity_Corruption = 0, + eDbgSeverity_Error, + eDbgSeverity_Warning, + eDbgSeverity_Info, +}; + +enum ResourceUsage +{ + eUsage_None, + + eUsage_IA_VB, + eUsage_IA_IB, + + eUsage_VS_CB, + eUsage_HS_CB, + eUsage_DS_CB, + eUsage_GS_CB, + eUsage_PS_CB, + eUsage_CS_CB, + + eUsage_SO, + + eUsage_VS_SRV, + eUsage_HS_SRV, + eUsage_DS_SRV, + eUsage_GS_SRV, + eUsage_PS_SRV, + eUsage_CS_SRV, + + eUsage_CS_UAV, + eUsage_PS_UAV, + + eUsage_OM_RTV, + eUsage_OM_DSV, + + eUsage_Clear, +}; + +enum DrawcallFlags +{ + // types + eDraw_Clear = 0x01, + eDraw_Drawcall = 0x02, + eDraw_Dispatch = 0x04, + eDraw_CmdList = 0x08, + eDraw_SetMarker = 0x10, + eDraw_PushMarker = 0x20, + eDraw_Present = 0x40, + + // flags + eDraw_UseIBuffer = 0x100, + eDraw_Instanced = 0x200, + eDraw_Auto = 0x400, + eDraw_Indirect = 0x800, +}; + +enum SolidShadeMode +{ + eShade_None = 0, + eShade_Solid, + eShade_Lit, + eShade_Tex, + eShade_VertCol, +}; + +enum TriangleFillMode +{ + eFill_Solid = 0, + eFill_Wireframe, +}; + +enum TriangleCullMode +{ + eCull_None = 0, + eCull_Front, + eCull_Back, +}; + +enum ReplayCreateStatus +{ + eReplayCreate_Success = 0, + eReplayCreate_UnknownError, + eReplayCreate_InternalError, + eReplayCreate_NetworkIOFailed, + eReplayCreate_FileIOFailed, + eReplayCreate_FileIncompatibleVersion, + eReplayCreate_FileCorrupted, + eReplayCreate_APIUnsupported, + eReplayCreate_APIInitFailed, + eReplayCreate_APIIncompatibleVersion, + eReplayCreate_APIHardwareUnsupported, +}; + +enum RemoteMessageType +{ + eRemoteMsg_Unknown = 0, + eRemoteMsg_Disconnected, + eRemoteMsg_Busy, + eRemoteMsg_Noop, + eRemoteMsg_NewCapture, + eRemoteMsg_CaptureCopied, + eRemoteMsg_RegisterAPI, +}; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp new file mode 100644 index 0000000000..05fcb53ba8 --- /dev/null +++ b/renderdoc/replay/replay_output.cpp @@ -0,0 +1,568 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "common/common.h" + +#include "replay_renderer.h" + +#include "common/string_utils.h" +#include "maths/matrix.h" + +ReplayOutput::ReplayOutput(ReplayRenderer *parent, void *w) +{ + m_pRenderer = parent; + + m_MainOutput.dirty = true; + + m_OverlayDirty = true; + + m_pDevice = parent->GetDevice(); + + m_OverlayResourceId = ResourceId(); + + m_PixelContext.wndHandle = 0; + m_PixelContext.outputID = 0; + m_PixelContext.texture = ResourceId(); + m_PixelContext.depthMode = false; + + m_ContextX = -1.0f; + m_ContextY = -1.0f; + + m_Config.m_Type = eOutputType_None; + + if(w) m_MainOutput.outputID = m_pDevice->MakeOutputWindow(w, true); + else m_MainOutput.outputID = 0; + m_MainOutput.texture = ResourceId(); + + m_pDevice->GetOutputWindowDimensions(m_MainOutput.outputID, m_Width, m_Height); + + m_FirstDeferredEvent = 0; + m_LastDeferredEvent = 0; + + m_CustomShaderResourceId = ResourceId(); +} + +ReplayOutput::~ReplayOutput() +{ + m_pDevice->DestroyOutputWindow(m_MainOutput.outputID); + m_pDevice->DestroyOutputWindow(m_PixelContext.outputID); + + m_CustomShaderResourceId = ResourceId(); + + ClearThumbnails(); +} + +bool ReplayOutput::SetOutputConfig( const OutputConfig &o ) +{ + m_OverlayDirty = true; + m_Config = o; + m_MainOutput.dirty = true; + return true; +} + +bool ReplayOutput::SetTextureDisplay(const TextureDisplay &o) +{ + if(o.overlay != m_RenderData.texDisplay.overlay) + m_OverlayDirty = true; + m_RenderData.texDisplay = o; + m_MainOutput.dirty = true; + return true; +} + +bool ReplayOutput::SetMeshDisplay(const MeshDisplay &o) +{ + m_RenderData.meshDisplay = o; + m_MainOutput.dirty = true; + return true; +} + +void ReplayOutput::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ + m_FirstDeferredEvent = firstDefEv; + m_LastDeferredEvent = lastDefEv; +} + +void ReplayOutput::SetFrameEvent(int frameID, int eventID) +{ + m_FrameID = frameID; + m_EventID = eventID; + + m_OverlayDirty = true; + m_MainOutput.dirty = true; + + for(size_t i=0; i < m_Thumbnails.size(); i++) + m_Thumbnails[i].dirty = true; + + RefreshOverlay(); +} + +void ReplayOutput::RefreshOverlay() +{ + FetchDrawcall *draw = m_pRenderer->GetDrawcallByEID(m_EventID, m_LastDeferredEvent); + + if(m_Config.m_Type == eOutputType_TexDisplay && m_RenderData.texDisplay.overlay != eTexOverlay_None) + { + if(draw && m_pDevice->IsRenderOutput(m_RenderData.texDisplay.texid)) + { + m_OverlayResourceId = m_pDevice->RenderOverlay(m_pDevice->GetLiveID(m_RenderData.texDisplay.texid), m_RenderData.texDisplay.overlay, m_FrameID, m_EventID); + m_OverlayDirty = false; + } + } + + if(m_Config.m_Type == eOutputType_MeshDisplay && m_OverlayDirty) + { + m_OverlayDirty = false; + + if(draw == NULL || (draw->flags & eDraw_Drawcall) == 0) + return; + + if(m_RenderData.meshDisplay.thisDrawOnly) + { + m_pDevice->InitPostVSBuffers(m_FrameID, draw->eventID); + } + else + { + FetchDrawcall *start = draw; + while(start->previous != 0 && (m_pRenderer->GetDrawcallByDrawID((uint32_t)start->previous)->flags & eDraw_Clear) == 0) + start = m_pRenderer->GetDrawcallByDrawID((uint32_t)start->previous); + + m_pDevice->ReplayLog(m_FrameID, 0, start->eventID, eReplay_WithoutDraw); + + uint32_t prev = start->eventID; + + while(start) + { + if(start->flags & eDraw_Drawcall) + { + if(prev != start->eventID) + { + m_pDevice->ReplayLog(m_FrameID, prev, start->eventID, eReplay_WithoutDraw); + + prev = start->eventID; + } + + m_pDevice->InitPostVSBuffers(m_FrameID, start->eventID); + } + + if(start == draw) + break; + + start = m_pRenderer->GetDrawcallByDrawID((uint32_t)start->next); + } + + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_WithoutDraw); + } + } +} + +bool ReplayOutput::ClearThumbnails() +{ + for(size_t i=0; i < m_Thumbnails.size(); i++) + m_pDevice->DestroyOutputWindow(m_Thumbnails[i].outputID); + + m_Thumbnails.clear(); + + return true; +} + +bool ReplayOutput::SetPixelContext(void *wnd) +{ + m_PixelContext.wndHandle = wnd; + m_PixelContext.outputID = m_pDevice->MakeOutputWindow(m_PixelContext.wndHandle, false); + m_PixelContext.texture = ResourceId(); + m_PixelContext.depthMode = false; + + RDCASSERT(m_PixelContext.outputID > 0); + + return true; +} + +bool ReplayOutput::AddThumbnail(void *wnd, ResourceId texID) +{ + OutputPair p; + + RDCASSERT(wnd); + + rdctype::array texs; + m_pRenderer->GetTextures(&texs); + + bool depthMode = false; + + for(int32_t t=0; t < texs.count; t++) + if(texs[t].ID == texID) + depthMode = (texs[t].creationFlags & eTextureCreate_DSV) > 0; + + for(size_t i=0; i < m_Thumbnails.size(); i++) + { + if(m_Thumbnails[i].wndHandle == wnd) + { + m_Thumbnails[i].texture = texID; + + m_Thumbnails[i].depthMode = depthMode; + + m_Thumbnails[i].dirty = true; + + return true; + } + } + + p.wndHandle = wnd; + p.outputID = m_pDevice->MakeOutputWindow(p.wndHandle, false); + p.texture = texID; + p.depthMode = depthMode; + p.dirty = true; + + RDCASSERT(p.outputID > 0); + + m_Thumbnails.push_back(p); + + return true; +} + +bool ReplayOutput::PickPixel(ResourceId tex, bool customShader, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, PixelValue *ret) +{ + if(ret == NULL || tex == ResourceId()) return false; + + RDCEraseEl(ret->value_f); + + if(customShader && m_RenderData.texDisplay.CustomShader != ResourceId() && m_CustomShaderResourceId != ResourceId()) + { + tex = m_CustomShaderResourceId; + } + + m_pDevice->PickPixel(m_pDevice->GetLiveID(tex), x, y, sliceFace, mip, ret->value_f); + + return true; +} + +bool ReplayOutput::SetPixelContextLocation(uint32_t x, uint32_t y) +{ + m_ContextX = RDCMAX((float)x, 0.0f); + m_ContextY = RDCMAX((float)y, 0.0f); + + DisplayContext(); + + return true; +} + +void ReplayOutput::DisablePixelContext() +{ + m_ContextX = -1.0f; + m_ContextY = -1.0f; + + DisplayContext(); +} + +void ReplayOutput::DisplayContext() +{ + if(m_PixelContext.outputID == 0) return; + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pDevice->BindOutputWindow(m_PixelContext.outputID, false); + m_pDevice->ClearOutputWindowColour(m_PixelContext.outputID, color); + + if(m_Config.m_Type != eOutputType_TexDisplay) return; + if(m_ContextX < 0.0f && m_ContextY < 0.0f) return; + if(m_RenderData.texDisplay.texid == ResourceId()) return; + + TextureDisplay disp = m_RenderData.texDisplay; + disp.rawoutput = false; + disp.CustomShader = ResourceId(); + + if(m_RenderData.texDisplay.CustomShader != ResourceId()) + disp.texid = m_CustomShaderResourceId; + + disp.scale = 8.0f; + + int32_t width = 0, height = 0; + m_pDevice->GetOutputWindowDimensions(m_PixelContext.outputID, width, height); + + float w = (float)width; + float h = (float)height; + + disp.offx = -m_ContextX*disp.scale; + disp.offy = -m_ContextY*disp.scale; + + disp.offx += w/2.0f; + disp.offy += h/2.0f; + + disp.texid = m_pDevice->GetLiveID(disp.texid); + + m_pDevice->RenderTexture(disp); + + m_pDevice->RenderHighlightBox(w, h, disp.scale); + + m_pDevice->FlipOutputWindow(m_PixelContext.outputID); +} + +bool ReplayOutput::Display() +{ + if(m_pDevice->CheckResizeOutputWindow(m_MainOutput.outputID)) + { + m_pDevice->GetOutputWindowDimensions(m_MainOutput.outputID, m_Width, m_Height); + m_MainOutput.dirty = true; + } + + for(size_t i=0; i < m_Thumbnails.size(); i++) + if(m_pDevice->CheckResizeOutputWindow(m_Thumbnails[i].outputID)) + m_Thumbnails[i].dirty = true; + + for(size_t i=0; i < m_Thumbnails.size(); i++) + { + if(!m_Thumbnails[i].dirty) + { + m_pDevice->FlipOutputWindow(m_Thumbnails[i].outputID); + continue; + } + if(!m_pDevice->IsOutputWindowVisible(m_Thumbnails[i].outputID)) + continue; + + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + if(m_Thumbnails[i].texture == ResourceId()) + { + m_pDevice->BindOutputWindow(m_Thumbnails[i].outputID, false); + + color[0] = 0.4f; + m_pDevice->ClearOutputWindowColour(m_Thumbnails[i].outputID, color); + + m_pDevice->FlipOutputWindow(m_Thumbnails[i].outputID); + continue; + } + + m_pDevice->BindOutputWindow(m_Thumbnails[i].outputID, false); + m_pDevice->ClearOutputWindowColour(m_Thumbnails[i].outputID, color); + + TextureDisplay disp; + + disp.Red = disp.Green = disp.Blue = true; + disp.Alpha = false; + disp.HDRMul = -1.0f; + disp.mip = 0; + disp.CustomShader = ResourceId(); + disp.texid = m_pDevice->GetLiveID(m_Thumbnails[i].texture); + disp.scale = -1.0f; + disp.rangemin = 0.0f; disp.rangemax = 1.0f; + disp.sliceFace = 0; + disp.rawoutput = false; + + if(m_Thumbnails[i].depthMode) + disp.Green = disp.Blue = false; + + m_pDevice->RenderTexture(disp); + + m_pDevice->FlipOutputWindow(m_Thumbnails[i].outputID); + + m_Thumbnails[i].dirty = false; + } + + if(m_pDevice->CheckResizeOutputWindow(m_PixelContext.outputID)) + m_MainOutput.dirty = true; + + if(!m_MainOutput.dirty) + { + m_pDevice->FlipOutputWindow(m_MainOutput.outputID); + m_pDevice->FlipOutputWindow(m_PixelContext.outputID); + return true; + } + + m_MainOutput.dirty = false; + + switch(m_Config.m_Type) + { + case eOutputType_MeshDisplay: + DisplayMesh(); + break; + case eOutputType_TexDisplay: + DisplayTex(); + break; + default: + RDCERR("Unexpected display type! %d", m_Config.m_Type); + break; + } + + m_pDevice->FlipOutputWindow(m_MainOutput.outputID); + + DisplayContext(); + + return true; +} + +void ReplayOutput::DisplayTex() +{ + FetchDrawcall *draw = m_pRenderer->GetDrawcallByEID(m_EventID, m_LastDeferredEvent); + + if(m_MainOutput.outputID == 0) return; + if(m_RenderData.texDisplay.texid == ResourceId()) + { + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pDevice->BindOutputWindow(m_MainOutput.outputID, false); + m_pDevice->ClearOutputWindowColour(m_MainOutput.outputID, color); + return; + } + if(m_Width <= 0 || m_Height <= 0) return; + + TextureDisplay texDisplay = m_RenderData.texDisplay; + texDisplay.rawoutput = false; + texDisplay.texid = m_pDevice->GetLiveID(texDisplay.texid); + + if(m_RenderData.texDisplay.overlay != eTexOverlay_None && draw) + { + if(m_OverlayDirty) + { + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_WithoutDraw); + RefreshOverlay(); + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_OnlyDraw); + } + } + + if(m_RenderData.texDisplay.CustomShader != ResourceId()) + { + m_CustomShaderResourceId = m_pDevice->ApplyCustomShader(m_RenderData.texDisplay.CustomShader, texDisplay.texid, texDisplay.mip); + + texDisplay.texid = m_pDevice->GetLiveID(m_CustomShaderResourceId); + texDisplay.CustomShader = ResourceId(); + texDisplay.sliceFace = 0; + texDisplay.mip = 0; + } + + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + m_pDevice->BindOutputWindow(m_MainOutput.outputID, false); + m_pDevice->ClearOutputWindowColour(m_MainOutput.outputID, color); + + if(m_RenderData.texDisplay.Alpha) + m_pDevice->RenderCheckerboard(Vec3f(texDisplay.lightBackgroundColour.x, texDisplay.lightBackgroundColour.y, texDisplay.lightBackgroundColour.z), + Vec3f(texDisplay.darkBackgroundColour.x, texDisplay.darkBackgroundColour.y, texDisplay.darkBackgroundColour.z)); + + m_pDevice->RenderTexture(texDisplay); + + if(m_RenderData.texDisplay.overlay != eTexOverlay_None && draw && m_pDevice->IsRenderOutput(m_RenderData.texDisplay.texid) && + m_RenderData.texDisplay.overlay != eTexOverlay_NaN && + m_RenderData.texDisplay.overlay != eTexOverlay_Clipping) + { + RDCASSERT(m_OverlayResourceId != ResourceId()); + texDisplay.texid = m_pDevice->GetLiveID(m_OverlayResourceId); + texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true; + texDisplay.rawoutput = false; + texDisplay.CustomShader = ResourceId(); + texDisplay.scale = m_RenderData.texDisplay.scale; + texDisplay.HDRMul = -1.0f; + texDisplay.rangemin = 0.0f; + texDisplay.rangemax = 1.0f; + + m_pDevice->RenderTexture(texDisplay); + } +} + +void ReplayOutput::DisplayMesh() +{ + FetchDrawcall *draw = m_pRenderer->GetDrawcallByEID(m_EventID, m_LastDeferredEvent); + + if(!draw) return; + if(m_MainOutput.outputID == 0) return; + if(m_Width <= 0 || m_Height <= 0) return; + if(m_RenderData.meshDisplay.type == eMeshDataStage_Unknown) return; + if((draw->flags & eDraw_Drawcall) == 0) return; + + vector events; + + if(draw && m_OverlayDirty) + { + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_WithoutDraw); + RefreshOverlay(); + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_OnlyDraw); + } + + if(m_RenderData.meshDisplay.type != eMeshDataStage_VSIn) + { + if(m_RenderData.meshDisplay.thisDrawOnly) + { + events.push_back(draw->eventID); + } + else + { + FetchDrawcall *start = draw; + while(start->previous != 0 && (m_pRenderer->GetDrawcallByDrawID((uint32_t)start->previous)->flags & eDraw_Clear) == 0) + start = m_pRenderer->GetDrawcallByDrawID((uint32_t)start->previous); + + while(start) + { + if(start->flags & eDraw_Drawcall) + { + events.push_back(start->eventID); + } + + if(start == draw) + break; + + start = m_pRenderer->GetDrawcallByDrawID((uint32_t)start->next); + } + } + } + + m_pDevice->BindOutputWindow(m_MainOutput.outputID, true); + m_pDevice->ClearOutputWindowDepth(m_MainOutput.outputID, 1.0f, 0); + + m_pDevice->RenderCheckerboard(Vec3f(0.666f, 0.666f, 0.666f), Vec3f(0.333f, 0.333f, 0.333f)); + + if(m_RenderData.meshDisplay.type == eMeshDataStage_VSIn) + { + events.clear(); + events.push_back(draw->eventID); + } + + RDCASSERT(!events.empty()); + + m_pDevice->ClearOutputWindowDepth(m_MainOutput.outputID, 1.0f, 0); + + m_pDevice->RenderMesh(m_FrameID, events, m_RenderData.meshDisplay); +} + + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetOutputConfig(ReplayOutput *output, const OutputConfig &o) +{ return output->SetOutputConfig(o); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetTextureDisplay(ReplayOutput *output, const TextureDisplay &o) +{ return output->SetTextureDisplay(o); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetMeshDisplay(ReplayOutput *output, const MeshDisplay &o) +{ return output->SetMeshDisplay(o); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_ClearThumbnails(ReplayOutput *output) +{ return output->ClearThumbnails(); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_AddThumbnail(ReplayOutput *output, void *wnd, ResourceId texID) +{ return output->AddThumbnail(wnd, texID); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_Display(ReplayOutput *output) +{ return output->Display(); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetPixelContext(ReplayOutput *output, void *wnd) +{ return output->SetPixelContext(wnd); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_SetPixelContextLocation(ReplayOutput *output, uint32_t x, uint32_t y) +{ return output->SetPixelContextLocation(x, y); } +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayOutput_DisablePixelContext(ReplayOutput *output) +{ output->DisablePixelContext(); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayOutput_PickPixel(ReplayOutput *output, ResourceId texID, bool customShader, + uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, PixelValue *val) +{ return output->PickPixel(texID, customShader, x, y, sliceFace, mip, val); } diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp new file mode 100644 index 0000000000..4615036a43 --- /dev/null +++ b/renderdoc/replay/replay_renderer.cpp @@ -0,0 +1,722 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "replay_renderer.h" + +#include +#include + +#include "common/string_utils.h" +#include "os/os_specific.h" + +#include "serialise/serialiser.h" + +ReplayRenderer::ReplayRenderer() +{ + m_pDevice = NULL; + + m_FrameID = 0; + m_EventID = 100000; + + m_DeferredCtx = ResourceId(); + m_FirstDeferredEvent = 0; + m_LastDeferredEvent = 0; +} + +ReplayRenderer::~ReplayRenderer() +{ + for(size_t i=0; i < m_Outputs.size(); i++) + SAFE_DELETE(m_Outputs[i]); + + m_Outputs.clear(); + + for(auto it=m_CustomShaders.begin(); it != m_CustomShaders.end(); ++it) + m_pDevice->FreeCustomShader(*it); + + m_CustomShaders.clear(); + + for(auto it=m_TargetResources.begin(); it != m_TargetResources.end(); ++it) + m_pDevice->FreeTargetResource(*it); + + m_TargetResources.clear(); + + if(m_pDevice) + m_pDevice->Shutdown(); + m_pDevice = NULL; +} + +bool ReplayRenderer::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ + if(m_DeferredCtx == ResourceId() && id == ResourceId()) + return true; + + m_pDevice->SetContextFilter(id, firstDefEv, lastDefEv); + + m_DeferredCtx = id; + m_FirstDeferredEvent = firstDefEv; + m_LastDeferredEvent = lastDefEv; + + for(size_t i=0; i < m_Outputs.size(); i++) + m_Outputs[i]->SetContextFilter(id, firstDefEv, lastDefEv); + + SetFrameEvent(m_FrameID, m_EventID, true); + + return true; +} + +bool ReplayRenderer::SetFrameEvent(uint32_t frameID, uint32_t eventID) +{ + return SetFrameEvent(frameID, eventID, false); +} + +bool ReplayRenderer::SetFrameEvent(uint32_t frameID, uint32_t eventID, bool force) +{ + if(m_FrameID != frameID || eventID != m_EventID || force) + { + m_FrameID = frameID; + m_EventID = eventID; + + m_pDevice->ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw); + + FetchPipelineState(); + + for(size_t i=0; i < m_Outputs.size(); i++) + m_Outputs[i]->SetFrameEvent(frameID, eventID); + + m_pDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + } + + return true; +} + +bool ReplayRenderer::GetD3D11PipelineState(D3D11PipelineState *state) +{ + if(state) + { + *state = m_D3D11PipelineState; + return true; + } + + return false; +} + +bool ReplayRenderer::GetGLPipelineState(GLPipelineState *state) +{ + if(state) + { + *state = m_GLPipelineState; + return true; + } + + return false; +} + +bool ReplayRenderer::GetFrameInfo(rdctype::array *arr) +{ + if(arr == NULL) return false; + + create_array_uninit(*arr, m_FrameRecord.size()); + for(size_t i=0; i < m_FrameRecord.size(); i++) + arr->elems[i] = m_FrameRecord[i].frameInfo; + + return true; +} + +struct drawcall_eventID : public std::unary_function +{ + drawcall_eventID(const uint32_t e) : evID(e) {} + bool operator() (const FetchDrawcall *arg) { return arg ? arg->eventID == evID : false; } + uint32_t evID; +}; + +FetchDrawcall *ReplayRenderer::GetDrawcallByDrawID(uint32_t drawID) +{ + if(drawID < m_Drawcalls.size()) + return m_Drawcalls[drawID]; + + return NULL; +} + +FetchDrawcall *ReplayRenderer::GetDrawcallByEID(uint32_t eventID, uint32_t defEventID) +{ + FetchDrawcall *ret = NULL; + + FetchDrawcall ev; + ev.eventID = defEventID > 0 ? defEventID : eventID; + + // can't guarantee ordering for std::upper_bound, since deferred contexts can + // break ordering + auto it = std::find_if(m_Drawcalls.begin(), m_Drawcalls.end(), drawcall_eventID(ev.eventID)); + + if(it != m_Drawcalls.end()) + ret = *it; + + return ret; +} + +bool ReplayRenderer::GetDrawcalls(uint32_t frameID, bool includeTimes, rdctype::array *draws) +{ + if(frameID >= (uint32_t)m_FrameRecord.size() || draws == NULL) + return false; + + if(includeTimes) + { + RDCDEBUG("Timing drawcalls..."); + + m_pDevice->TimeDrawcalls(m_FrameRecord[frameID].m_DrawCallList); + } + + *draws = m_FrameRecord[frameID].m_DrawCallList; + return true; +} + +bool ReplayRenderer::GetBuffers(rdctype::array *out) +{ + if(m_Buffers.empty()) + { + vector ids = m_pDevice->GetBuffers(); + + m_Buffers.resize(ids.size()); + + for(size_t i=0; i < ids.size(); i++) + m_Buffers[i] = m_pDevice->GetBuffer(ids[i]); + } + + if(out) + { + *out = m_Buffers; + return true; + } + + return false; +} + +bool ReplayRenderer::GetTextures(rdctype::array *out) +{ + if(m_Textures.empty()) + { + vector ids = m_pDevice->GetTextures(); + + m_Textures.resize(ids.size()); + + for(size_t i=0; i < ids.size(); i++) + m_Textures[i] = m_pDevice->GetTexture(ids[i]); + } + + if(out) + { + *out = m_Textures; + return true; + } + + return false; +} + +bool ReplayRenderer::GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array *arr) +{ + if(arr == NULL || callstack == NULL || callstackLen == 0) return false; + + Callstack::StackResolver *resolv = m_pDevice->GetCallstackResolver(); + + if(resolv == NULL) + { + create_array_uninit(*arr, 1); + arr->elems[0] = L""; + return true; + } + + create_array_uninit(*arr, callstackLen); + for(size_t i=0; i < callstackLen; i++) + { + Callstack::AddressDetails info = resolv->GetAddr(callstack[i]); + arr->elems[i] = info.formattedString(); + } + + return true; +} + +bool ReplayRenderer::GetUsage(ResourceId id, rdctype::array *usage) +{ + if(usage) + { + *usage = m_pDevice->GetUsage(m_pDevice->GetLiveID(id)); + return true; + } + + return false; +} + +bool ReplayRenderer::GetPostVSData(MeshDataStage stage, PostVSMeshData *data) +{ + if(data == NULL) return false; + + FetchDrawcall *draw = GetDrawcallByEID(m_EventID, m_LastDeferredEvent); + + PostVSMeshData ret; + ret.numVerts = 0; + ret.topo = eTopology_Unknown; + + if(draw == NULL || (draw->flags & eDraw_Drawcall) == 0) return false; + + *data = m_pDevice->GetPostVSBuffers(m_FrameID, draw->eventID, stage); + + return true; +} + +bool ReplayRenderer::GetMinMax(ResourceId tex, uint32_t sliceFace, uint32_t mip, PixelValue *minval, PixelValue *maxval) +{ + PixelValue *a = minval; + PixelValue *b = maxval; + + PixelValue dummy; + + if(a == NULL) a = &dummy; + if(b == NULL) b = &dummy; + + return m_pDevice->GetMinMax(m_pDevice->GetLiveID(tex), sliceFace, mip, &a->value_f[0], &b->value_f[0]); +} + +bool ReplayRenderer::GetHistogram(ResourceId tex, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], rdctype::array *histogram) +{ + if(histogram == NULL) return false; + + vector hist; + + bool ret = m_pDevice->GetHistogram(m_pDevice->GetLiveID(tex), sliceFace, mip, minval, maxval, channels, hist); + + if(ret) + *histogram = hist; + + return ret; +} + +bool ReplayRenderer::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len, rdctype::array *data) +{ + if(data == NULL) return false; + + *data = m_pDevice->GetBufferData(m_pDevice->GetLiveID(buff), offset, len); + + return true; +} + +bool ReplayRenderer::SaveTexture(ResourceId tex, uint32_t saveMip, const wchar_t *path) +{ + return m_pDevice->SaveTexture(m_pDevice->GetLiveID(tex), saveMip, path); +} + +bool ReplayRenderer::VSGetDebugStates(uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace) +{ + if(trace == NULL) return false; + + *trace = m_pDevice->DebugVertex(m_FrameID, m_EventID, vertid, instid, idx, instOffset, vertOffset); + + SetFrameEvent(m_FrameID, m_EventID, true); + + return true; +} + +bool ReplayRenderer::PSGetDebugStates(uint32_t x, uint32_t y, ShaderDebugTrace *trace) +{ + if(trace == NULL) return false; + + *trace = m_pDevice->DebugPixel(m_FrameID, m_EventID, x, y); + + SetFrameEvent(m_FrameID, m_EventID, true); + + return true; +} + +bool ReplayRenderer::CSGetDebugStates(uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace) +{ + if(trace == NULL) return false; + + *trace = m_pDevice->DebugThread(m_FrameID, m_EventID, groupid, threadid); + + SetFrameEvent(m_FrameID, m_EventID, true); + + return true; +} + +bool ReplayRenderer::GetCBufferVariableContents(ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array *vars) +{ + if(vars == NULL) return false; + + vector data; + if(buffer != ResourceId()) + data = m_pDevice->GetBufferData(m_pDevice->GetLiveID(buffer), offs, 0); + + vector v; + + m_pDevice->FillCBufferVariables(m_pDevice->GetLiveID(shader), cbufslot, v, data); + + *vars = v; + + return true; +} + +ShaderReflection *ReplayRenderer::GetShaderDetails(ResourceId shader) +{ + return m_pDevice->GetShader(m_pDevice->GetLiveID(shader)); +} + +ReplayOutput *ReplayRenderer::CreateOutput(void *wndhandle) +{ + ReplayOutput *out = new ReplayOutput(this, wndhandle); + + m_Outputs.push_back(out); + + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_WithoutDraw); + + out->SetFrameEvent(m_FrameID, m_EventID); + + m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_OnlyDraw); + + return out; +} + +ResourceId ReplayRenderer::BuildTargetShader(const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, rdctype::wstr *errors) +{ + ResourceId id; + string errs; + + switch(type) + { + case eShaderStage_Vertex: + case eShaderStage_Hull: + case eShaderStage_Domain: + case eShaderStage_Geometry: + case eShaderStage_Pixel: + case eShaderStage_Compute: + break; + default: + RDCERR("Unexpected type in BuildShader!"); + return ResourceId(); + } + + m_pDevice->BuildTargetShader(narrow(source), narrow(entry), compileFlags, type, &id, &errs); + + if(id != ResourceId()) + m_TargetResources.insert(id); + + if(errors) *errors = widen(errs); + + return id; +} + +ResourceId ReplayRenderer::BuildCustomShader(const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, rdctype::wstr *errors) +{ + ResourceId id; + string errs; + + switch(type) + { + case eShaderStage_Vertex: + case eShaderStage_Hull: + case eShaderStage_Domain: + case eShaderStage_Geometry: + case eShaderStage_Pixel: + case eShaderStage_Compute: + break; + default: + RDCERR("Unexpected type in BuildShader!"); + return ResourceId(); + } + + m_pDevice->BuildCustomShader(narrow(source), narrow(entry), compileFlags, type, &id, &errs); + + if(id != ResourceId()) + m_CustomShaders.insert(id); + + if(errors) *errors = widen(errs); + + return id; +} + +bool ReplayRenderer::FreeTargetResource(ResourceId id) +{ + m_TargetResources.erase(id); + m_pDevice->FreeTargetResource(id); + + return true; +} + +bool ReplayRenderer::FreeCustomShader(ResourceId id) +{ + m_CustomShaders.erase(id); + m_pDevice->FreeCustomShader(id); + + return true; +} + +bool ReplayRenderer::ReplaceResource(ResourceId from, ResourceId to) +{ + m_pDevice->ReplaceResource(from, to); + + SetFrameEvent(m_FrameID, m_EventID, true); + + for(size_t i=0; i < m_Outputs.size(); i++) + if(m_Outputs[i]->GetType() != eOutputType_None) + m_Outputs[i]->Display(); + + return true; +} + +bool ReplayRenderer::RemoveReplacement(ResourceId id) +{ + m_pDevice->RemoveReplacement(id); + + SetFrameEvent(m_FrameID, m_EventID, true); + + for(size_t i=0; i < m_Outputs.size(); i++) + if(m_Outputs[i]->GetType() != eOutputType_None) + m_Outputs[i]->Display(); + + return true; +} + +ReplayCreateStatus ReplayRenderer::CreateDevice(const wchar_t *logfile) +{ + RDCLOG("Creating replay device for %ls", logfile); + + RDCDriver driverType = RDC_Unknown; + wstring driverName = L""; + auto status = RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, NULL); + + if(driverType == RDC_Unknown || driverName == L"" || status != eReplayCreate_Success) + { + RDCERR("Couldn't get device type from log"); + return status; + } + + IReplayDriver *driver = NULL; + status = RenderDoc::Inst().CreateReplayDriver(driverType, logfile, &driver); + + if(driver && status == eReplayCreate_Success) + { + RDCLOG("Created replay driver."); + return PostCreateInit(driver); + } + + RDCERR("Couldn't create a replay device :(."); + return status; +} + +ReplayCreateStatus ReplayRenderer::SetDevice(IReplayDriver *device) +{ + if(device) + { + RDCLOG("Got replay driver."); + return PostCreateInit(device); + } + + RDCERR("Given invalid replay driver."); + return eReplayCreate_InternalError; +} + +ReplayCreateStatus ReplayRenderer::PostCreateInit(IReplayDriver *device) +{ + m_pDevice = device; + + m_pDevice->ReadLogInitialisation(); + + FetchPipelineState(); + + vector fr = m_pDevice->GetFrameRecord(); + + m_FrameRecord.reserve(fr.size()); + for(size_t i=0; i < fr.size(); i++) + { + m_FrameRecord.push_back(FrameRecord()); + m_FrameRecord.back().frameInfo = fr[i].frameInfo; + m_FrameRecord.back().m_DrawCallList = fr[i].drawcallList; + + SetupDrawcallPointers(fr[i].frameInfo, m_FrameRecord.back().m_DrawCallList, NULL, NULL); + } + + return eReplayCreate_Success; +} + +FetchDrawcall *ReplayRenderer::SetupDrawcallPointers(FetchFrameInfo frame, rdctype::array &draws, FetchDrawcall *parent, FetchDrawcall *previous) +{ + FetchDrawcall *ret = NULL; + + for(int32_t i=0; i < draws.count; i++) + { + FetchDrawcall *draw = &draws[i]; + + draw->parent = parent ? parent->drawcallID : 0; + + if(draw->children.count > 0) + { + ret = previous = SetupDrawcallPointers(frame, draw->children, draw, previous); + } + else if(draw->flags & (eDraw_PushMarker|eDraw_SetMarker|eDraw_Present)) + { + // don't want to set up previous/next links for markers + } + else + { + if(previous != NULL) + previous->next = draw->drawcallID; + draw->previous = previous ? previous->drawcallID : 0; + + RDCASSERT(m_Drawcalls.empty() || draw->eventID > m_Drawcalls.back()->eventID || draw->context != frame.immContextId); + m_Drawcalls.resize(RDCMAX(m_Drawcalls.size(), size_t(draw->drawcallID+1))); + m_Drawcalls[draw->drawcallID] = draw; + + ret = previous = draw; + } + } + + return ret; +} + +bool ReplayRenderer::HasCallstacks() +{ + return m_pDevice->HasCallstacks(); +} + +APIProperties ReplayRenderer::GetAPIProperties() +{ + return m_pDevice->GetAPIProperties(); +} + +bool ReplayRenderer::InitResolver() +{ + m_pDevice->InitCallstackResolver(); + return m_pDevice->GetCallstackResolver() != NULL; +} + +void ReplayRenderer::FetchPipelineState() +{ + m_pDevice->SavePipelineState(); + + m_D3D11PipelineState = m_pDevice->GetD3D11PipelineState(); + m_GLPipelineState = m_pDevice->GetGLPipelineState(); + + { + D3D11PipelineState::ShaderStage *stage = &m_D3D11PipelineState.m_VS; + for(int i=0; i < 6; i++) + if(stage[i].Shader != ResourceId()) + stage[i].ShaderDetails = m_pDevice->GetShader(m_pDevice->GetLiveID(stage[i].Shader)); + } + + { + GLPipelineState::ShaderStage *stage = &m_GLPipelineState.m_VS; + for(int i=0; i < 6; i++) + if(stage[i].Shader != ResourceId()) + stage[i].ShaderDetails = m_pDevice->GetShader(m_pDevice->GetLiveID(stage[i].Shader)); + } +} + +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(ReplayRenderer *rend, APIProperties *props) +{ if(props) *props = rend->GetAPIProperties(); } + +extern "C" RENDERDOC_API ReplayOutput* RENDERDOC_CC ReplayRenderer_CreateOutput(ReplayRenderer *rend, void *handle) +{ return rend->CreateOutput(handle); } +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend) +{ delete rend; } +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output) +{ RDCUNIMPLEMENTED("destroying individual outputs"); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_HasCallstacks(ReplayRenderer *rend) +{ return rend->HasCallstacks(); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_InitResolver(ReplayRenderer *rend) +{ return rend->InitResolver(); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_SetContextFilter(ReplayRenderer *rend, ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) +{ return rend->SetContextFilter(id, firstDefEv, lastDefEv); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_SetFrameEvent(ReplayRenderer *rend, uint32_t frameID, uint32_t eventID) +{ return rend->SetFrameEvent(frameID, eventID); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetD3D11PipelineState(ReplayRenderer *rend, D3D11PipelineState *state) +{ return rend->GetD3D11PipelineState(state); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetGLPipelineState(ReplayRenderer *rend, GLPipelineState *state) +{ return rend->GetGLPipelineState(state); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::wstr *errors) +{ + if(shaderID == NULL) return false; + + *shaderID = rend->BuildCustomShader(entry, source, compileFlags, type, errors); + + return (*shaderID != ResourceId()); +} +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_FreeCustomShader(ReplayRenderer *rend, ResourceId id) +{ return rend->FreeCustomShader(id); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::wstr *errors) +{ + if(shaderID == NULL) return false; + + *shaderID = rend->BuildTargetShader(entry, source, compileFlags, type, errors); + + return (*shaderID != ResourceId()); +} +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_ReplaceResource(ReplayRenderer *rend, ResourceId from, ResourceId to) +{ return rend->ReplaceResource(from, to); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_RemoveReplacement(ReplayRenderer *rend, ResourceId id) +{ return rend->RemoveReplacement(id); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_FreeTargetResource(ReplayRenderer *rend, ResourceId id) +{ return rend->FreeTargetResource(id); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetFrameInfo(ReplayRenderer *rend, rdctype::array *frame) +{ return rend->GetFrameInfo(frame); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, bool includeTimes, rdctype::array *draws) +{ return rend->GetDrawcalls(frameID, includeTimes, draws); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetTextures(ReplayRenderer *rend, rdctype::array *texs) +{ return rend->GetTextures(texs); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array *bufs) +{ return rend->GetBuffers(bufs); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetResolve(ReplayRenderer *rend, uint64_t *callstack, uint32_t callstackLen, rdctype::array *trace) +{ return rend->GetResolve(callstack, callstackLen, trace); } +extern "C" RENDERDOC_API ShaderReflection* RENDERDOC_CC ReplayRenderer_GetShaderDetails(ReplayRenderer *rend, ResourceId shader) +{ return rend->GetShaderDetails(shader); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_VSGetDebugStates(ReplayRenderer *rend, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace) +{ return rend->VSGetDebugStates(vertid, instid, idx, instOffset, vertOffset, trace); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_PSGetDebugStates(ReplayRenderer *rend, uint32_t x, uint32_t y, ShaderDebugTrace *trace) +{ return rend->PSGetDebugStates(x, y, trace); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_CSGetDebugStates(ReplayRenderer *rend, uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace) +{ return rend->CSGetDebugStates(groupid, threadid, trace); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetUsage(ReplayRenderer *rend, ResourceId id, rdctype::array *usage) +{ return rend->GetUsage(id, usage); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetCBufferVariableContents(ReplayRenderer *rend, ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array *vars) +{ return rend->GetCBufferVariableContents(shader, cbufslot, buffer, offs, vars); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_SaveTexture(ReplayRenderer *rend, ResourceId texID, uint32_t mip, const wchar_t *path) +{ return rend->SaveTexture(texID, mip, path); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, MeshDataStage stage, PostVSMeshData *data) +{ return rend->GetPostVSData(stage, data); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetMinMax(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, PixelValue *minval, PixelValue *maxval) +{ return rend->GetMinMax(tex, sliceFace, mip, minval, maxval); } +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetHistogram(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], rdctype::array *histogram) +{ return rend->GetHistogram(tex, sliceFace, mip, minval, maxval, channels, histogram); } + +extern "C" RENDERDOC_API bool RENDERDOC_CC ReplayRenderer_GetBufferData(ReplayRenderer *rend, ResourceId buff, uint32_t offset, uint32_t len, rdctype::array *data) +{ return rend->GetBufferData(buff, offset, len, data); } diff --git a/renderdoc/replay/replay_renderer.h b/renderdoc/replay/replay_renderer.h new file mode 100644 index 0000000000..c9c20ca9ae --- /dev/null +++ b/renderdoc/replay/replay_renderer.h @@ -0,0 +1,217 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "common/common.h" +#include "core/core.h" +#include "replay/renderdoc.h" +#include "replay/replay_driver.h" + +#include +#include + +#include "type_helpers.h" + +struct ReplayRenderer; + +struct ReplayOutput +{ +public: + bool SetOutputConfig(const OutputConfig &o); + bool SetTextureDisplay(const TextureDisplay &o); + bool SetMeshDisplay(const MeshDisplay &o); + + bool ClearThumbnails(); + bool AddThumbnail(void *wnd, ResourceId texID); + + bool Display(); + + OutputType GetType() { return m_Config.m_Type; } + + bool SetPixelContext(void *wnd); + bool SetPixelContextLocation(uint32_t x, uint32_t y); + void DisablePixelContext(); + + bool PickPixel(ResourceId texID, bool customShader, + uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, + PixelValue *val); +private: + ReplayOutput(ReplayRenderer *parent, void *w); + ~ReplayOutput(); + + void SetFrameEvent(int frameID, int eventID); + void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); + + void RefreshOverlay(); + + + void DisplayContext(); + void DisplayTex(); + + + void DisplayMesh(); + + ReplayRenderer *m_pRenderer; + size_t m_ID; + + bool m_OverlayDirty; + + IReplayDriver *m_pDevice; + + uint32_t m_TexWidth, m_TexHeight; + + struct OutputPair + { + ResourceId texture; + bool depthMode; + void *wndHandle; + uint64_t outputID; + + bool dirty; + } m_MainOutput; + + ResourceId m_OverlayResourceId; + ResourceId m_CustomShaderResourceId; + + std::vector m_Thumbnails; + + float m_ContextX; + float m_ContextY; + OutputPair m_PixelContext; + + uint32_t m_FrameID; + uint32_t m_EventID; + uint32_t m_FirstDeferredEvent; + uint32_t m_LastDeferredEvent; + OutputConfig m_Config; + + int32_t m_Width; + int32_t m_Height; + + struct + { + TextureDisplay texDisplay; + MeshDisplay meshDisplay; + } m_RenderData; + + friend struct ReplayRenderer; +}; + +struct ReplayRenderer +{ + public: + ReplayRenderer(); + ~ReplayRenderer(); + + APIProperties GetAPIProperties(); + + ReplayCreateStatus CreateDevice(const wchar_t *logfile); + ReplayCreateStatus SetDevice(IReplayDriver *device); + + bool HasCallstacks(); + bool InitResolver(); + + bool SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv); + bool SetFrameEvent(uint32_t frameID, uint32_t eventID); + bool SetFrameEvent(uint32_t frameID, uint32_t eventID, bool force); + + void FetchPipelineState(); + + bool GetD3D11PipelineState(D3D11PipelineState *state); + bool GetGLPipelineState(GLPipelineState *state); + + ResourceId BuildCustomShader(const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, rdctype::wstr *errors); + bool FreeCustomShader(ResourceId id); + + ResourceId BuildTargetShader(const wchar_t *entry, const wchar_t *source, const uint32_t compileFlags, ShaderStageType type, rdctype::wstr *errors); + bool ReplaceResource(ResourceId from, ResourceId to); + bool RemoveReplacement(ResourceId id); + bool FreeTargetResource(ResourceId id); + + bool GetFrameInfo(rdctype::array *frame); + bool GetDrawcalls(uint32_t frameID, bool includeTimes, rdctype::array *draws); + bool GetTextures(rdctype::array *texs); + bool GetBuffers(rdctype::array *bufs); + bool GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array *trace); + ShaderReflection *GetShaderDetails(ResourceId shader); + + bool VSGetDebugStates(uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace); + bool PSGetDebugStates(uint32_t x, uint32_t y, ShaderDebugTrace *trace); + bool CSGetDebugStates(uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace); + + bool GetPostVSData(MeshDataStage stage, PostVSMeshData *data); + + bool GetMinMax(ResourceId tex, uint32_t sliceFace, uint32_t mip, PixelValue *minval, PixelValue *maxval); + bool GetHistogram(ResourceId tex, uint32_t sliceFace, uint32_t mip, float minval, float maxval, bool channels[4], rdctype::array *histogram); + + bool GetUsage(ResourceId id, rdctype::array *usage); + + bool GetBufferData(ResourceId buff, uint32_t offset, uint32_t len, rdctype::array *data); + + bool SaveTexture(ResourceId tex, uint32_t saveMip, const wchar_t *path); + + bool GetCBufferVariableContents(ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array *vars); + + ReplayOutput *CreateOutput(void *handle); + private: + ReplayCreateStatus PostCreateInit(IReplayDriver *device); + + FetchDrawcall *GetDrawcallByEID(uint32_t eventID, uint32_t defEventID); + FetchDrawcall *GetDrawcallByDrawID(uint32_t drawID); + FetchDrawcall *SetupDrawcallPointers(FetchFrameInfo frame, rdctype::array &draws, FetchDrawcall *parent, FetchDrawcall *previous); + + IReplayDriver *GetDevice() { return m_pDevice; } + + struct FrameRecord + { + FetchFrameInfo frameInfo; + + rdctype::array m_DrawCallList; + }; + vector m_FrameRecord; + vector m_Drawcalls; + + uint32_t m_FrameID; + uint32_t m_EventID; + ResourceId m_DeferredCtx; + uint32_t m_FirstDeferredEvent; + uint32_t m_LastDeferredEvent; + + D3D11PipelineState m_D3D11PipelineState; + GLPipelineState m_GLPipelineState; + + std::vector m_Outputs; + + std::vector m_Buffers; + std::vector m_Textures; + + IReplayDriver *m_pDevice; + + std::set m_TargetResources; + std::set m_CustomShaders; + + friend struct ReplayOutput; +}; diff --git a/renderdoc/replay/shader_types.h b/renderdoc/replay/shader_types.h new file mode 100644 index 0000000000..bb9ce2321e --- /dev/null +++ b/renderdoc/replay/shader_types.h @@ -0,0 +1,206 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "basic_types.h" + +#include "replay_enums.h" + +struct ShaderVariable +{ + ShaderVariable() + { + name = ""; rows = columns = 0; + type = eVar_Float; + for(int i=0; i < 16; i++) value.uv[i] = 0; + } + ShaderVariable(const char *n, float x, float y, float z, float w) + { + name = n; rows = 1; columns = 4; + for(int i=0; i < 16; i++) value.uv[i] = 0; + type = eVar_Float; + value.f.x = x; value.f.y = y; value.f.z = z; value.f.w = w; + } + ShaderVariable(const char *n, int x, int y, int z, int w) + { + name = n; rows = 1; columns = 4; + for(int i=0; i < 16; i++) value.uv[i] = 0; + type = eVar_Int; + value.i.x = x; value.i.y = y; value.i.z = z; value.i.w = w; + } + ShaderVariable(const char *n, uint32_t x, uint32_t y, uint32_t z, uint32_t w) + { + name = n; rows = 1; columns = 4; + for(int i=0; i < 16; i++) value.uv[i] = 0; + type = eVar_UInt; + value.u.x = x; value.u.y = y; value.u.z = z; value.u.w = w; + } + + uint32_t rows, columns; + rdctype::str name; + + VarType type; + + union + { + struct + { + float x, y, z, w; + } f; + float fv[16]; + + struct + { + int32_t x, y, z, w; + } i; + int32_t iv[16]; + + struct + { + uint32_t x, y, z, w; + } u; + uint32_t uv[16]; + } value; + + rdctype::array members; +}; + +struct ShaderDebugState +{ + rdctype::array registers; + rdctype::array outputs; + + uint32_t nextInstruction; +}; + +struct ShaderDebugTrace +{ + rdctype::array inputs; + rdctype::array< rdctype::array > cbuffers; + + rdctype::array states; +}; + +struct SigParameter +{ + SigParameter() + : semanticIndex(0), needSemanticIndex(false), regIndex(0), + systemValue(eAttr_None), compType(eCompType_Float), + regChannelMask(0), channelUsedMask(0), compCount(0), stream(0) + { } + + rdctype::str varName; + rdctype::str semanticName; + uint32_t semanticIndex; + rdctype::str semanticIdxName; + + bool32 needSemanticIndex; + + uint32_t regIndex; + SystemAttribute systemValue; + + FormatComponentType compType; + + uint8_t regChannelMask; + uint8_t channelUsedMask; + uint32_t compCount; + uint32_t stream; +}; + +struct ShaderConstant; + +struct ShaderVariableType +{ + struct + { + uint32_t rows; + uint32_t cols; + uint32_t elements; + rdctype::str name; + } descriptor; + + rdctype::array members; +}; + +struct ShaderConstant +{ + rdctype::str name; + struct + { + uint32_t vec; + uint32_t comp; + } reg; + ShaderVariableType type; +}; + +struct ConstantBlock +{ + rdctype::str name; + rdctype::array variables; + int32_t bufferAddress; +}; + +struct ShaderResource +{ + bool32 IsSampler; + bool32 IsTexture; + bool32 IsSRV; + bool32 IsUAV; + + ShaderResourceType resType; + + rdctype::str name; + ShaderVariableType variableType; + uint32_t variableAddress; + uint32_t bindPoint; +}; + +struct ShaderDebugChunk +{ + ShaderDebugChunk() : compileFlags(0) {} + + rdctype::str entryFunc; + + uint32_t compileFlags; + + rdctype::array< rdctype::pair > files; // +}; + +struct ShaderReflection +{ + ShaderDebugChunk DebugInfo; + rdctype::str Disassembly; + + rdctype::array InputSig; + rdctype::array OutputSig; + + rdctype::array ConstantBlocks; // sparse - index indicates bind point + + rdctype::array Resources; // non-sparse, since bind points can overlap. + + // TODO expand this to encompass shader subroutines. + rdctype::array Interfaces; +}; diff --git a/renderdoc/replay/type_helpers.cpp b/renderdoc/replay/type_helpers.cpp new file mode 100644 index 0000000000..b92418c883 --- /dev/null +++ b/renderdoc/replay/type_helpers.cpp @@ -0,0 +1,42 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "type_helpers.h" + +#include +#include +#include "serialise/serialiser.h" +#include "common/string_utils.h" + +template<> +string ToStrHelper::Get(const rdctype::str &el) +{ + return string(el.elems, el.elems+el.count); +} + +template<> +string ToStrHelper::Get(const rdctype::wstr &el) +{ + return narrow(wstring(el.elems, el.elems+el.count)); +} diff --git a/renderdoc/replay/type_helpers.h b/renderdoc/replay/type_helpers.h new file mode 100644 index 0000000000..3842e8b0a6 --- /dev/null +++ b/renderdoc/replay/type_helpers.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "basic_types.h" + +#include + +namespace rdctype +{ +#pragma warning(push) +#pragma warning(disable: 4345) // behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized + +template +void create_array(array &ret, size_t count) +{ + ret.elems = (T*)ret.allocate(sizeof(T)*count); + ret.count = (int32_t)count; + for(int32_t i=0; i < ret.count; i++) + new (ret.elems+i) T(); +} + +#pragma warning(pop) + +template +void create_array_uninit(array &ret, size_t count) +{ + ret.elems = (T*)ret.allocate(sizeof(T)*count); + ret.count = (int32_t)count; + memset(ret.elems, 0, sizeof(T)*count); +} + +}; // namespace rdctype \ No newline at end of file diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp new file mode 100644 index 0000000000..9e89880938 --- /dev/null +++ b/renderdoc/serialise/serialiser.cpp @@ -0,0 +1,1165 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include "serialiser.h" + +#include "core/core.h" + +#include "common/string_utils.h" + +#if !defined(RELEASE) + +int64_t Chunk::m_LiveChunks = 0; +int64_t Chunk::m_TotalMem = 0; +int64_t Chunk::m_MaxChunks = 0; + +#endif + +const uint32_t Serialiser::MAGIC_HEADER = MAKE_FOURCC('R', 'D', 'O', 'C'); +const size_t Serialiser::BufferAlignment = 16; + +Chunk::Chunk(Serialiser *ser, uint32_t chunkType, bool temporary) +{ + m_Length = (uint32_t)ser->GetOffset(); + + RDCASSERT(ser->GetOffset() < 0xffffffff); + + m_ChunkType = chunkType; + + m_Temporary = temporary; + + if(ser->HasAlignedData()) + { + m_Data = Serialiser::AllocAlignedBuffer(m_Length); + m_AlignedData = true; + } + else + { + m_Data = new byte[m_Length]; + m_AlignedData = false; + } + + memcpy(m_Data, ser->GetRawPtr(0), m_Length); + + m_DebugStr = ser->GetDebugStr(); + + ser->Rewind(); + +#if !defined(RELEASE) + int64_t newval = Atomic::Inc64(&m_LiveChunks); + Atomic::ExchAdd64(&m_TotalMem, m_Length); + + if(newval > m_MaxChunks) + { + int breakpointme=0; + } + + m_MaxChunks = RDCMAX(newval, m_MaxChunks); +#endif +} + +Chunk::~Chunk() +{ +#if !defined(RELEASE) + Atomic::Dec64(&m_LiveChunks); + Atomic::ExchAdd64(&m_TotalMem, -int64_t(m_Length)); +#endif + + if(m_AlignedData) + { + if(m_Data) + Serialiser::FreeAlignedBuffer(m_Data); + + m_Data = NULL; + } + else + { + SAFE_DELETE_ARRAY(m_Data); + } +} + +void Serialiser::Reset() +{ + if(m_ResolverThread != 0) + { + m_ResolverThreadKillSignal = true; + + Threading::JoinThread(m_ResolverThread); + Threading::CloseThread(m_ResolverThread); + m_ResolverThread = 0; + } + + m_DebugText = ""; + + m_HasError = false; + m_ErrorCode = eSerError_None; + + m_Mode = NONE; + + m_Indent = 0; + + SAFE_DELETE_ARRAY(m_pCallstack); + SAFE_DELETE_ARRAY(m_pResolver); + if(m_Buffer) + { + FreeAlignedBuffer(m_Buffer); + m_Buffer = NULL; + } + + m_ChunkLookup = NULL; + + m_HasResolver = false; + + m_AlignedData = false; + + m_ReadFileHandle = NULL; + + m_Buffer = NULL; + m_BufferSize = 0; + m_BufferHead = NULL; +} + +Serialiser::Serialiser(size_t length, const byte *memoryBuf, bool fileheader) + : m_pCallstack(NULL), m_pResolver(NULL), m_Buffer(NULL) +{ + m_ResolverThread = 0; + + Reset(); + + m_DebugTextWriting = false; + + m_Mode = READING; + m_DebugEnabled = false; + + if(!fileheader) + { + m_HasResolver = false; + + m_FileStartOffset = 0; + + m_BufferSize = length; + m_CurrentBufferSize = (size_t)m_BufferSize; + m_BufferHead = m_Buffer = AllocAlignedBuffer(m_CurrentBufferSize); + m_ReadOffset = 0; + + memcpy(m_Buffer, memoryBuf + m_FileStartOffset, m_CurrentBufferSize); + return; + } + + DebuggerHeader *header = (DebuggerHeader *)memoryBuf; + + if(length < sizeof(DebuggerHeader)) + { + RDCERR("Can't read from in-memory buffer, truncated header"); + m_ErrorCode = eSerError_Corrupt; + m_HasError = true; + return; + } + + if(header->magic != MAGIC_HEADER) + { + char magicRef[5] = { 0 }; + char magicFile[5] = { 0 }; + memcpy(magicRef, &MAGIC_HEADER, sizeof(uint32_t)); + memcpy(magicFile, &header->magic, sizeof(uint32_t)); + RDCERR("Invalid in-memory buffer. Expected magic %hs, got %hs", magicRef, magicFile); + + m_ErrorCode = eSerError_Corrupt; + m_HasError = true; + return; + } + + if(header->version != SERIALISE_VERSION) + { + RDCERR("Capture file from wrong version. This program is on logfile version %llu, file is logfile version %llu", SERIALISE_VERSION, header->version); + + m_ErrorCode = eSerError_UnsupportedVersion; + m_HasError = true; + return; + } + + if(header->fileSize < length) + { + RDCERR("Overlong in-memory buffer. Expected length 0x016llx, got 0x016llx", header->fileSize, length); + + m_ErrorCode = eSerError_Corrupt; + m_HasError = true; + return; + } + + m_HasResolver = header->resolveDBSize > 0; + + m_FileStartOffset = AlignUp16(sizeof(DebuggerHeader) + header->resolveDBSize); + + m_BufferSize = length-m_FileStartOffset; + m_CurrentBufferSize = (size_t)m_BufferSize; + m_BufferHead = m_Buffer = AllocAlignedBuffer(m_CurrentBufferSize); + m_ReadOffset = 0; + + memcpy(m_Buffer, memoryBuf + m_FileStartOffset, m_CurrentBufferSize); +} + +Serialiser::Serialiser(const wchar_t *path, Mode mode, bool debugMode) + : m_pCallstack(NULL), m_pResolver(NULL), m_Buffer(NULL) +{ + m_ResolverThread = 0; + + Reset(); + + m_Filename = path ? path : L""; + + m_DebugTextWriting = false; + + m_Mode = mode; + m_DebugEnabled = debugMode; + + DebuggerHeader header; + + if(mode == READING) + { + m_ReadFileHandle = FileIO::fopen(m_Filename.c_str(), L"rb"); + + if(!m_ReadFileHandle) + { + RDCERR("Can't open capture file '%ls' for read - errno %d", m_Filename.c_str(), errno); + m_ErrorCode = eSerError_FileIO; + m_HasError = true; + return; + } + + RDCDEBUG("Opened capture file for read"); + + FileIO::fread(&header, 1, sizeof(DebuggerHeader), m_ReadFileHandle); + + if(header.magic != MAGIC_HEADER) + { + char magicRef[5] = { 0 }; + char magicFile[5] = { 0 }; + memcpy(magicRef, &MAGIC_HEADER, sizeof(uint32_t)); + memcpy(magicFile, &header.magic, sizeof(uint32_t)); + RDCERR("Invalid capture file. Expected magic %hs, got %hs", magicRef, magicFile); + + m_ErrorCode = eSerError_Corrupt; + m_HasError = true; + FileIO::fclose(m_ReadFileHandle); + m_ReadFileHandle = 0; + return; + } + + if(header.version != SERIALISE_VERSION) + { + RDCERR("Capture file from wrong version. This program is logfile version %llu, file is logfile version %llu", SERIALISE_VERSION, header.version); + + m_ErrorCode = eSerError_UnsupportedVersion; + m_HasError = true; + FileIO::fclose(m_ReadFileHandle); + m_ReadFileHandle = 0; + return; + } + + FileIO::fseek64(m_ReadFileHandle, 0, SEEK_END); + + uint64_t realLength = FileIO::ftell64(m_ReadFileHandle); + if(header.fileSize != realLength) + { + RDCERR("Truncated/overlong capture file. Expected length 0x016llx, got 0x016llx", header.fileSize, realLength); + + m_ErrorCode = eSerError_Corrupt; + m_HasError = true; + FileIO::fclose(m_ReadFileHandle); + m_ReadFileHandle = 0; + return; + } + + m_HasResolver = header.resolveDBSize > 0; + + m_FileStartOffset = AlignUp16(sizeof(DebuggerHeader) + header.resolveDBSize); + + m_BufferSize = realLength-m_FileStartOffset; + m_CurrentBufferSize = (size_t)RDCMIN(m_BufferSize, (uint64_t)64*1024); + m_BufferHead = m_Buffer = AllocAlignedBuffer(m_CurrentBufferSize); + m_ReadOffset = 0; + + ReadFromFile(0, m_CurrentBufferSize); + } + else + { + m_pResolver = NULL; + + if(m_Filename != L"") + { + m_BufferSize = 0; + m_BufferHead = m_Buffer = NULL; + } + else + { + m_BufferSize = 128*1024; + m_BufferHead = m_Buffer = AllocAlignedBuffer((size_t)m_BufferSize); + } + + m_ReadOffset = 0; + m_FileStartOffset = 0; + } +} + +void Serialiser::ReadFromFile(uint64_t destOffs, size_t chunkLen) +{ + RDCASSERT(m_ReadFileHandle); + + if(m_ReadFileHandle == NULL) + return; + + FileIO::fseek64(m_ReadFileHandle, m_FileStartOffset+destOffs, SEEK_SET); + FileIO::fread(m_Buffer + destOffs - m_ReadOffset, 1, chunkLen, m_ReadFileHandle); +} + +byte *Serialiser::AllocAlignedBuffer(size_t size) +{ + byte *rawAlloc = NULL; + +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) + try +#endif + { + rawAlloc = new byte[size+sizeof(byte*)+16]; + } +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) + catch(std::bad_alloc&) + { + rawAlloc = NULL; + } +#endif + + if(rawAlloc == NULL) + RDCFATAL("Allocation for %llu bytes failed", (uint64_t)size); + + RDCASSERT(rawAlloc); + + byte *alignedAlloc = (byte *)AlignUp16((size_t)(rawAlloc+sizeof(byte*))); + + byte **realPointer = (byte **)alignedAlloc; + realPointer[-1] = rawAlloc; + + return alignedAlloc; +} + +void Serialiser::FreeAlignedBuffer(byte *buf) +{ + byte **realPointer = (byte **)buf; + byte *rawAlloc = realPointer[-1]; + + delete[] rawAlloc; +} + +void Serialiser::InitCallstackResolver() +{ + if(m_pResolver == NULL && m_ResolverThread == 0) + { + m_ResolverThreadKillSignal = false; + m_ResolverThread = Threading::CreateThread(&Serialiser::CreateResolver, (void *)this); + } +} + +void Serialiser::SetCallstack(uint64_t *levels, size_t numLevels) +{ + SAFE_DELETE(m_pCallstack); + + if(levels != NULL && numLevels != 0) + m_pCallstack = Callstack::Load(levels, numLevels); +} + +void Serialiser::CreateResolver(void *ths) +{ + Serialiser *ser = (Serialiser *)ths; + FILE *binFile = FileIO::fopen(ser->m_Filename.c_str(), L"rb"); + + if(!binFile) + { + RDCERR("Can't open capture file '%ls' for read - errno %d", ser->m_Filename.c_str(), errno); + return; + } + + DebuggerHeader header; + FileIO::fread(&header, 1, sizeof(DebuggerHeader), binFile); + + if(header.magic != MAGIC_HEADER) + { + RDCERR("Invalid capture file. Expected 0x%08lx, got 0x%08llx", MAGIC_HEADER, header.magic); + FileIO::fclose(binFile); + return; + } + + if(header.version != SERIALISE_VERSION) + { + RDCERR("Capture file from wrong version. This program is logfile version %llu, file is logfile version %llu", SERIALISE_VERSION, header.version); + FileIO::fclose(binFile); + return; + } + + FileIO::fseek64(binFile, 0, SEEK_END); + + uint64_t realLength = FileIO::ftell64(binFile); + if(header.fileSize != realLength) + { + RDCERR("Truncated/overlong capture file. Expected length 0x08llx, got 0x08lx", header.fileSize, realLength); + FileIO::fclose(binFile); + return; + } + + if(header.resolveDBSize == 0) + { + RDCWARN("Trying to create resolver when no resolve DB is in the capture file"); + FileIO::fclose(binFile); + return; + } + + FileIO::fseek64(binFile, sizeof(DebuggerHeader), SEEK_SET); + + RDCASSERT(header.resolveDBSize < 0xffffffff); + + char *resolveDB = new char[(size_t)header.resolveDBSize]; + + FileIO::fread(resolveDB, 1, (size_t)header.resolveDBSize, binFile); + + FileIO::fclose(binFile); + + wstring dir = dirname(wstring(ser->m_Filename)); + + Callstack::StackResolver *resolver = Callstack::MakeResolver(resolveDB, (size_t)header.resolveDBSize, dir, &ser->m_ResolverThreadKillSignal); + + ser->m_pResolver = resolver; + + SAFE_DELETE_ARRAY(resolveDB); +} + +uint64_t Serialiser::FlushToDisk() +{ + if(m_Filename != L"" && !m_HasError && m_Mode == WRITING) + { + RDCDEBUG("writing capture files"); + + if(m_DebugEnabled && !m_DebugText.empty()) + { + FILE *dbgFile = FileIO::fopen((m_Filename + L".txt").c_str(), L"wb"); + + if(!dbgFile) + { + RDCERR("Can't open debug capture file '%ls'", (m_Filename + L".txt").c_str()); + } + else + { + FileIO::fwrite(m_DebugText.c_str(), 1, m_DebugText.length(), dbgFile); + + FileIO::fclose(dbgFile); + } + } + + FILE *binFile = FileIO::fopen(m_Filename.c_str(), L"wb"); + + if(!binFile) + { + RDCERR("Can't open capture file '%ls' for write, errno %d", m_Filename.c_str(), errno); + m_ErrorCode = eSerError_FileIO; + m_HasError = true; + return 0; + } + + RDCDEBUG("Opened capture file for write"); + + DebuggerHeader header; + + char *symbolDB = NULL; + size_t symbolDBSize = 0; + + if(RenderDoc::Inst().GetCaptureOptions().CaptureCallstacks || + RenderDoc::Inst().GetCaptureOptions().CaptureCallstacksOnlyDraws) + { + // get symbol database + Callstack::GetLoadedModules(symbolDB, symbolDBSize); + + symbolDB = new char[symbolDBSize]; + symbolDBSize = 0; + + Callstack::GetLoadedModules(symbolDB, symbolDBSize); + } + + header.resolveDBSize = symbolDBSize; + + // write header + FileIO::fwrite(&header, 1, sizeof(DebuggerHeader), binFile); + + // write symbol database + if(symbolDBSize > 0) + FileIO::fwrite(symbolDB, 1, symbolDBSize, binFile); + + static const byte padding[BufferAlignment] = {0}; + + size_t offs = sizeof(DebuggerHeader) + symbolDBSize; + size_t alignedoffs = AlignUp16(offs); + + FileIO::fwrite(padding, 1, alignedoffs-offs, binFile); + + offs = alignedoffs; + + // write serialise contents + for(size_t i=0; i < m_Chunks.size(); i++) + { + Chunk *chunk = m_Chunks[i]; + + size_t alignedoffs = AlignUp16(offs); + + if(offs != alignedoffs && chunk->IsAligned()) + { + uint16_t chunkIdx = 0; // write a '0' chunk that indicates special behaviour + FileIO::fwrite(&chunkIdx, sizeof(chunkIdx), 1, binFile); + offs += sizeof(chunkIdx); + + uint8_t controlByte = 0; // control byte 0 indicates padding + FileIO::fwrite(&controlByte, sizeof(controlByte), 1, binFile); + offs += sizeof(controlByte); + + offs++; // we will have to write out a byte indicating how much padding exists, so add 1 + alignedoffs = AlignUp16(offs); + + RDCCOMPILE_ASSERT(BufferAlignment < 0x100, "Buffer alignment must be less than 256"); // with a byte at most indicating how many bytes to pad, + // this is our maximal representable alignment + + uint8_t padLength = (alignedoffs-offs)&0xff; + FileIO::fwrite(&padLength, sizeof(padLength), 1, binFile); + + // we might have padded with the control bytes, so only write some bytes if we need to + if(padLength > 0) + { + FileIO::fwrite(padding, 1, alignedoffs-offs, binFile); + offs += alignedoffs-offs; + } + } + + FileIO::fwrite(chunk->GetData(), 1, chunk->GetLength(), binFile); + + offs += chunk->GetLength(); + + if(chunk->IsTemporary()) + SAFE_DELETE(chunk); + } + + m_Chunks.clear(); + + header.fileSize = offs; + + FileIO::fseek64(binFile, 0, SEEK_SET); + + // write header with correct filesize (accounting for all padding) + FileIO::fwrite(&header, 1, sizeof(DebuggerHeader), binFile); + + FileIO::fclose(binFile); + + SAFE_DELETE_ARRAY(symbolDB); + + return header.fileSize; + } + + return 0; +} + +Serialiser::~Serialiser() +{ + if(m_ResolverThread != 0) + { + m_ResolverThreadKillSignal = true; + Threading::JoinThread(m_ResolverThread); + Threading::CloseThread(m_ResolverThread); + m_ResolverThread = 0; + } + + if(m_ReadFileHandle) + { + FileIO::fclose(m_ReadFileHandle); + m_ReadFileHandle = 0; + } + + for(size_t i=0; i < m_Chunks.size(); i++) + { + if(m_Chunks[i]->IsTemporary()) + SAFE_DELETE(m_Chunks[i]); + } + + m_Chunks.clear(); + + SAFE_DELETE(m_pResolver); + SAFE_DELETE(m_pCallstack); + if(m_Buffer) + { + FreeAlignedBuffer(m_Buffer); + m_Buffer = NULL; + } + m_Buffer = NULL; + m_BufferHead = NULL; +} + +void Serialiser::DebugPrint(const char *fmt, ...) +{ + if(m_HasError) + { + RDCERR("Debug printing with error state serialiser"); + return; + } + + char tmpBuf[1024]; + + va_list args; + va_start(args, fmt); + StringFormat::vsnprintf( tmpBuf, 1023, fmt, args ); + tmpBuf[1023] = '\0'; + va_end(args); + + m_DebugText += GetIndent(); + m_DebugText += tmpBuf; + +#ifdef DEBUG_TEXT_SERIALISER + FILE *f = FileIO::fopen(m_Filename.c_str(), L"ab"); + + if(f) + { + FileIO::fwrite(tmpBuf, 1, strlen(tmpBuf), f); + + FileIO::fclose(f); + } +#endif +} + +uint32_t Serialiser::PushContext(const char *name, uint32_t chunkIdx, bool smallChunk) +{ + // if writing, and chunkidx isn't 0 (debug non-scope), then either we're nested + // or we should be writing into the start of the serialiser. A serialiser should + // only ever have one chunk in it + RDCASSERT(m_Mode < WRITING || m_Indent > 0 || GetOffset() == 0 || chunkIdx == 0); + + // we should not be pushing contexts directly into a file serialiser + RDCASSERT(m_Mode < WRITING || m_Filename.empty()); + + if(m_Mode >= WRITING) + { + if(chunkIdx > 0) + { + uint16_t c = chunkIdx&0x3fff; + RDCASSERT(chunkIdx <= 0x3fff); + + ///////////////// + + Callstack::Stackwalk *call = NULL; + + if(m_Indent == 0) + { + if(RenderDoc::Inst().GetCaptureOptions().CaptureCallstacks && + !RenderDoc::Inst().GetCaptureOptions().CaptureCallstacksOnlyDraws) + { + call = Callstack::Collect(); + + RDCASSERT(call->NumLevels() < 0xff); + } + } + + if(call) + c |= 0x8000; + if(smallChunk) + c |= 0x4000; + + WriteFrom(c); + + if(call) + { + uint8_t numLevels = call->NumLevels()&0xff; + WriteFrom(numLevels); + + if(call->NumLevels()) + { + WriteBytes((byte *)call->GetAddrs(), sizeof(uint64_t)*numLevels); + } + + SAFE_DELETE(call); + } + + // will be fixed up in PopContext + if(smallChunk) + { + uint16_t chunkSize = 0xbeeb; + m_ChunkFixups.push_back(0x8000000000000000ULL | GetOffset()); + WriteFrom(chunkSize); + } + else + { + uint32_t chunkSize = 0xbeebfeed; + m_ChunkFixups.push_back(GetOffset() & ~0x8000000000000000ULL); + WriteFrom(chunkSize); + } + } + + if(m_DebugTextWriting) + { + DebugPrint("%hs (%d)\n", name, chunkIdx); + DebugPrint("{\n"); + } + } + else + { + // reset debug text + m_DebugText = ""; + + if(chunkIdx > 0) + { + uint16_t c = 0; + ReadInto(c); + + // chunk index 0 is not allowed in normal situations. + // allows us to indicate some control bytes + while(c == 0) + { + uint8_t *controlByte = (uint8_t *)ReadBytes(1); + + if(*controlByte == 0x0) + { + // padding + uint8_t *padLength = (uint8_t *)ReadBytes(1); + + // might have padded with these 5 control bytes, + // so a pad length of 0 IS VALID. + if(*padLength > 0) + { + ReadBytes((size_t)*padLength); + } + } + else + { + RDCERR("Unexpected control byte: %x", (uint32_t)*controlByte); + } + + ReadInto(c); + } + + chunkIdx = c&0x3fff; + bool callstack = (c&0x8000) > 0; + bool smallchunk = (c&0x4000) > 0; + + ///////////////// + + if(m_Indent == 0) + { + if(callstack) + { + uint8_t callLen = 0; + ReadInto(callLen); + + uint64_t *calls = (uint64_t *)ReadBytes(callLen*sizeof(uint64_t)); + SetCallstack(calls, callLen); + } + else + { + SetCallstack(NULL, 0); + } + } + + ///////////////// + + if(smallchunk) + { + uint16_t miniSize = 0xbeeb; + ReadInto(miniSize); + + m_LastChunkLen = miniSize; + } + else + { + uint32_t chunkSize = 0xbeebfeed; + ReadInto(chunkSize); + + m_LastChunkLen = chunkSize; + } + } + + if(!name && m_ChunkLookup) + name = m_ChunkLookup(chunkIdx); + + if(m_DebugTextWriting) + { + DebugPrint("%hs\n", name ? name : "Unknown"); + DebugPrint("{\n"); + } + } + + m_Indent++; + + return chunkIdx; +} + +void Serialiser::PopContext(const char *name, uint32_t chunkIdx) +{ + m_Indent = RDCMAX(m_Indent-1, 0); + + if(m_Mode >= WRITING) + { + if(chunkIdx > 0 && m_Mode == WRITING) + { + // fix up the latest PushContext (guaranteed to match this one as Pushes and Pops match) + RDCASSERT(!m_ChunkFixups.empty()); + + uint64_t chunkOffset = m_ChunkFixups.back();m_ChunkFixups.pop_back(); + + bool smallchunk = (chunkOffset & 0x8000000000000000ULL) > 0; + chunkOffset &= ~0x8000000000000000ULL; + + uint64_t curOffset = GetOffset(); + + RDCASSERT(curOffset > chunkOffset); + + uint64_t chunkLength = (curOffset-chunkOffset) - (smallchunk ? sizeof(uint16_t) : sizeof(uint32_t)); + + RDCASSERT(chunkLength < 0xffffffff); + + uint32_t chunklen = (uint32_t)chunkLength; + + byte *head = m_BufferHead; + SetOffset(chunkOffset); + if(smallchunk) + { + uint16_t miniSize = (chunklen&0xffff); + RDCASSERT(chunklen <= 0xffff); + WriteFrom(miniSize); + } + else + { + WriteFrom(chunklen); + } + m_BufferHead = head; + } + + if(m_DebugTextWriting) + DebugPrint("} // %hs\n", name); + } + else + { + if(m_DebugTextWriting) + DebugPrint("}\n"); + } +} + +///////////////////////////////////////////////////////////// +// Serialise functions + +///////////////////////////////////////////////////////////// +// generic + +void Serialiser::SerialiseString(const char *name, string &el) +{ + uint32_t len = (uint32_t)el.length(); + + Serialise(NULL, len); + + if(m_Mode == READING) + el.resize(len); + + if(m_Mode >= WRITING) + { + WriteBytes((byte *)el.c_str(), len); + + if(m_DebugTextWriting) + { + string s = el; + if(s.length() > 64) + s = s.substr(0, 60) + "..."; + DebugPrint("%hs: \"%hs\"\n", name, s.c_str()); + } + } + else + { + memcpy(&el[0], ReadBytes(len), len); + + if(m_DebugTextWriting) + { + string s = el; + if(s.length() > 64) + s = s.substr(0, 60) + "..."; + DebugPrint("%hs: \"%hs\"\n", name, s.c_str()); + } + } +} + +void Serialiser::SerialiseString(const char *name, wstring &el) +{ + string utf8str; + if(m_Mode >= WRITING) + utf8str = StringFormat::Wide2UTF8(el); + + SerialiseString(name, utf8str); + + if(m_Mode == READING) + el = StringFormat::UTF82Wide(utf8str); +} + +void Serialiser::Insert(Chunk *chunk) +{ + m_Chunks.push_back(chunk); + + m_DebugText += chunk->GetDebugString(); +} + +void Serialiser::SkipBuffer() +{ + RDCASSERT(m_Mode < WRITING); + + uint32_t len; + ReadInto(len); + + // ensure byte alignment + uint64_t offs = GetOffset(); + uint64_t alignedoffs = AlignUp16(offs); + + if(offs != alignedoffs) + { + ReadBytes((size_t)(alignedoffs-offs)); + } + + ReadBytes(len); +} + +void Serialiser::SerialiseBuffer(const char *name, byte *&buf, size_t &len) +{ + uint32_t bufLen = (uint32_t)len; + + if(m_Mode >= WRITING) + { + WriteFrom(bufLen); + + // ensure byte alignment + uint64_t offs = GetOffset(); + uint64_t alignedoffs = AlignUp16(offs); + + if(offs != alignedoffs) + { + static const byte padding[BufferAlignment] = {0}; + WriteBytes(&padding[0], (size_t)(alignedoffs-offs)); + } + + RDCASSERT((GetOffset()%BufferAlignment)==0); + + WriteBytes(buf, bufLen); + + m_AlignedData = true; + } + else + { + ReadInto(bufLen); + + // ensure byte alignment + uint64_t offs = GetOffset(); + uint64_t alignedoffs = AlignUp16(offs); + + if(offs != alignedoffs) + { + ReadBytes((size_t)(alignedoffs-offs)); + } + + if(buf == NULL) + buf = new byte[bufLen]; + memcpy(buf, ReadBytes(bufLen), bufLen); + } + + len = (size_t)bufLen; + + if(m_DebugTextWriting) + { + const char *ellipsis = "..."; + + float *fbuf = new float[4]; + fbuf[0] = fbuf[1] = fbuf[2] = fbuf[3] = 0.0f; + uint32_t *lbuf = (uint32_t *)fbuf; + + memcpy(fbuf, buf, RDCMIN(len, 4*sizeof(float))); + + if(bufLen <= 16) + { + ellipsis = " "; + } + + DebugPrint("%hs: RawBuffer % 5d:< 0x%08x 0x%08x 0x%08x 0x%08x %hs % 8.4ff % 8.4ff % 8.4ff % 8.4ff %hs >\n" + , name + , bufLen, lbuf[0], lbuf[1], lbuf[2], lbuf[3], ellipsis + , fbuf[0], fbuf[1], fbuf[2], fbuf[3], ellipsis); + + SAFE_DELETE_ARRAY(fbuf); + } + +} + +template<> void Serialiser::Serialise(const char *name, string &el) +{ + SerialiseString(name, el); +} + +template<> void Serialiser::Serialise(const char *name, wstring &el) +{ + SerialiseString(name, el); +} + +// floats need aligned reads +template<> void Serialiser::ReadInto(float &f) +{ + if(m_HasError) + { + RDCERR("Reading into with error state serialiser"); + return; + } + + char *data = (char *)ReadBytes(sizeof(float)); + + memcpy(&f, data, sizeof(float)); +} + +///////////////////////////////////////////////////////////// +// String conversions for debug log. + +///////////////////////////////////////////////////////////// +// Basic types + +template<> +string ToStrHelper::Get(void* const &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "0x%X", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const ResourceId &el) +{ + char tostrBuf[256] = {0}; + + StringFormat::snprintf(tostrBuf, 255, "Resource ID %llu", el.id); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const uint64_t &el) +{ + char tostrBuf[256] = {0}; + + StringFormat::snprintf(tostrBuf, 255, "%llu", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const uint32_t &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%u", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const char &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "'%c'", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const wchar_t &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "'%lc'", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const byte &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%d%d%d%d%d%d%d%d" + , (el&0x80)?1:0, (el&0x40)?1:0, (el&0x20)?1:0, (el&0x10)?1:0 + , (el&0x8)?1:0, (el&0x4)?1:0, (el&0x2)?1:0, (el&0x1)?1:0); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const uint16_t &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%04d", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const int &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%d", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const short &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%04d", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const float &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%0.4f", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const double &el) +{ + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "%0.4lf", el); + + return tostrBuf; +} + +template<> +string ToStrHelper::Get(const bool &el) +{ + if(el) + return "True"; + + return "False"; +} diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h new file mode 100644 index 0000000000..b64ffa8e3d --- /dev/null +++ b/renderdoc/serialise/serialiser.h @@ -0,0 +1,883 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#pragma once + +#include "common/common.h" +#include "os/os_specific.h" +#include "replay/basic_types.h" + +#include "replay/type_helpers.h" + +#include +#include + +#include +#include +#include +#include +#include +using std::set; +using std::string; +using std::wstring; + +// template helpers +template +struct is_pointer +{ + enum {value = false}; +}; + +template +struct is_pointer +{ + enum {value = true}; +}; + +template +struct is_pointer +{ + enum {value = true}; +}; + +template +struct ToStrHelper +{ + static string Get(const T &el); +}; + +struct ToStr +{ + template + static string Get(const T &el) + { + return ToStrHelper::value, T>::Get(el); + } +}; + +typedef const char *(*ChunkLookup)(uint32_t chunkType); + +class Serialiser; +class ScopedContext; + +// holds the memory, length and type for a given chunk, so that it can be +// passed around and moved between owners before being serialised out +class Chunk +{ + public: + ~Chunk(); + + const char *GetDebugString() { return m_DebugStr.c_str(); } + byte *GetData() { return m_Data; } + uint32_t GetLength() { return m_Length; } + uint32_t GetChunkType() { return m_ChunkType; } + + bool IsAligned() { return m_AlignedData; } + bool IsTemporary() { return m_Temporary; } + +#if !defined(RELEASE) + static uint64_t NumLiveChunks() { return m_LiveChunks; } + static uint64_t TotalMem() { return m_TotalMem; } +#else + static uint64_t NumLiveChunks() { return 0; } + static uint64_t TotalMem() { return 0; } +#endif + + // grab current contents of the serialiser into this chunk + Chunk(Serialiser *ser, uint32_t chunkType, bool temp); + + private: + // no copy semantics + Chunk(const Chunk &); + Chunk &operator =(const Chunk &); + + friend class ScopedContext; + + bool m_AlignedData; + bool m_Temporary; + + uint32_t m_ChunkType; + + uint32_t m_Length; + byte *m_Data; + string m_DebugStr; + +#if !defined(RELEASE) + static int64_t m_LiveChunks, m_MaxChunks, m_TotalMem; +#endif +}; + +// this class has a few functions. It can be used to serialise chunks - on writing it enforces +// that we only ever write a single chunk, then pull out the data into a Chunk class and erase +// the contents of the serialiser ready to serialise the next (see the RDCASSERT at the start +// of PushContext). +// +// We use this functionality for sending and receiving data across the network as well as saving +// out to the capture logfile format. +// +// It's also used on reading where it will contain the stream of chunks that were written out +// to the logfile on capture. +// +// When reading, the Serialiser allocates a window of memory and scans through the file by reading +// data into that window and moving along through the file. The window will expand to accomodate +// whichever is the biggest single element within a chunk that's read (so that you can always guarantee +// while reading that the element you're interested in is always in memory). +class Serialiser +{ + public: + enum Mode + { + NONE = 0, + READING, + WRITING, + DEBUGWRITING, + }; + + enum SerialiserError + { + eSerError_None = 0, + eSerError_FileIO, + eSerError_Corrupt, + eSerError_UnsupportedVersion, + }; + + // version number of overall file format or chunk organisation. If the contents/meaning/order of + // chunks have changed this does not need to be bumped, there are version numbers within each + // API that interprets the stream that can be bumped. + static const uint64_t SERIALISE_VERSION = 0x00000031; + + ////////////////////////////////////////// + // Init and error handling + + Serialiser(size_t length, const byte *memoryBuf, bool fileheader); + Serialiser(const wchar_t *path, Mode mode, bool debugMode = false); + ~Serialiser(); + + bool HasError() { return m_HasError; } + SerialiserError ErrorCode() { return m_ErrorCode; } + + ////////////////////////////////////////// + // Utility functions + + bool AtEnd() + { + return GetOffset() >= m_BufferSize; + } + + bool HasAlignedData() + { + return m_AlignedData; + } + + uint64_t GetOffset() const + { + if(m_HasError) + { + RDCERR("Getting offset with error state serialiser"); + return 0; + } + + RDCASSERT(m_BufferHead && m_Buffer && m_BufferHead >= m_Buffer); + return m_BufferHead - m_Buffer + m_ReadOffset; + } + + uint64_t GetSize() + { + if(m_Mode == READING) + return m_BufferSize; + + return m_BufferHead - m_Buffer; + } + + byte *GetRawPtr(size_t offs) const + { + return m_Buffer+offs; + } + + // Set up the base pointer and size. Serialiser will allocate enough for + // the rest of the file and keep it all in memory (useful to keep everything + // in actual frame data resident in memory). + void SetBase(uint64_t offs) + { + FreeAlignedBuffer(m_Buffer); + + RDCASSERT(m_BufferSize - offs < 0xffffffff); + + m_CurrentBufferSize = (size_t)(m_BufferSize - offs); + m_BufferHead = m_Buffer = AllocAlignedBuffer(m_CurrentBufferSize); + m_ReadOffset = offs; + + ReadFromFile(offs, m_CurrentBufferSize); + FileIO::fclose(m_ReadFileHandle); + m_ReadFileHandle = 0; + } + + void SetOffset(uint64_t offs) + { + if(m_HasError) + { + RDCERR("Setting offset with error state serialiser"); + return; + } + + // if we're jumping back before our in-memory window just reset the window + // and load it all in from scratch. + if(m_Mode == READING && offs < m_ReadOffset) + { + FreeAlignedBuffer(m_Buffer); + + m_CurrentBufferSize = (size_t)RDCMIN(m_BufferSize, (uint64_t)64*1024); + m_BufferHead = m_Buffer = AllocAlignedBuffer(m_CurrentBufferSize); + m_ReadOffset = offs; + + ReadFromFile(offs, m_CurrentBufferSize); + } + + RDCASSERT(m_BufferHead && m_Buffer && offs <= GetSize()); + m_BufferHead = m_Buffer + offs - m_ReadOffset; + m_Indent = 0; + } + + void Rewind() + { + m_DebugText = ""; + m_Indent = 0; + m_AlignedData = false; + SetOffset(0); + } + + // assumes buffer head is sitting before a chunk (ie. pushcontext will be valid) + void SkipToChunk(uint32_t chunkIdx) + { + do + { + size_t offs = m_BufferHead-m_Buffer + (size_t)m_ReadOffset; + + uint32_t c = PushContext(NULL, 1, false); + + // found + if(c == chunkIdx) + { + m_Indent--; + m_BufferHead = (m_Buffer+offs)-(size_t)m_ReadOffset; + return; + } + else + { + SkipCurrentChunk(); + PopContext(NULL, 1); + } + + } while(!AtEnd()); + } + + // assumes buffer head is sitting in a chunk (ie. immediately after a pushcontext) + void SkipCurrentChunk() + { + ReadBytes(m_LastChunkLen); + } + + void InitCallstackResolver(); + bool HasCallstacks() { return m_HasResolver; } + + // get callstack resolver, created with the DB in the file + Callstack::StackResolver *GetCallstackResolver() + { + return m_pResolver; + } + + void SetCallstack(uint64_t *levels, size_t numLevels); + + // get the callstack associated with the last scope + Callstack::Stackwalk *GetLastCallstack() + { + return m_pCallstack; + } + + ////////////////////////////////////////// + // Public serialisation interface + + int GetContextLevel() { return m_Indent; } + uint32_t PushContext(const char *name, uint32_t chunkIdx, bool smallChunk); + void PopContext(const char *name, uint32_t chunkIdx); + + // Write a chunk to disk + void Insert(Chunk *el); + + // serialise a fixed-size array. + template + void Serialise(const char *name, T *el) + { + size_t n = Num; + Serialise(name, el, n); + } + + // serialise a normal array. Typically this should be a small array, + // for large buffers use SerialiseBuffer which is optimised for that + // + // If serialising in, el must either be NULL in which case allocated + // memory will be returned, or it must be already large enough. + template + void Serialise(const char *name, T *&el, size_t &Num) + { + uint32_t numElems = (uint32_t)Num; + + if(m_Mode == WRITING) + { + WriteFrom(numElems); + WriteBytes((byte *)el, sizeof(T)*numElems); + } + else if(m_Mode == READING) + { + ReadInto(numElems); + + if(el == NULL) el = new T[numElems]; + + size_t length = numElems*sizeof(T); + + memcpy(el, ReadBytes(length), length); + } + + Num = (size_t)numElems; + + if(name != NULL && m_DebugTextWriting) + { + for(size_t i=0; i < Num; i++) + DebugPrint("%hs[%d] = %hs\n", name, i, ToStr::Get(el[i]).c_str()); + } + } + + // serialise a single element + template void Serialise(const char *name, T &el) + { + if(m_Mode == WRITING) + { + WriteFrom(el); + } + else if(m_Mode == READING) + { + ReadInto(el); + } + + if(name != NULL && m_DebugTextWriting) + DebugPrint("%hs: %hs\n", name, ToStr::Get(el).c_str()); + } + + template + void Serialise(const char *name, std::vector &el) + { + uint64_t sz = el.size(); + Serialise(name, sz); + if(m_Mode == WRITING) + { + for(size_t i=0; i < sz; i++) + Serialise("[]", el[i]); + } + else + { + el.clear(); + el.reserve((size_t)sz); + for(size_t i=0; i < sz; i++) + { + X x = X(); + Serialise("", x); + el.push_back(x); + } + } + } + + template + void Serialise(const char *name, rdctype::array &el) + { + int32_t sz = el.count; + Serialise(name, sz); + if(m_Mode == WRITING) + { + for(int32_t i=0; i < sz; i++) + Serialise("[]", el.elems[i]); + } + else + { + create_array_uninit(el, sz); + for(int32_t i=0; i < sz; i++) + Serialise("", el.elems[i]); + } + } + + void Serialise(const char *name, rdctype::wstr &el) + { + int32_t sz = el.count; + Serialise(name, sz); + if(m_Mode == WRITING) + { + for(int32_t i=0; i < sz; i++) + Serialise("[]", el.elems[i]); + } + else + { + create_array_uninit(el, sz); + for(int32_t i=0; i < sz; i++) + Serialise("", el.elems[i]); + } + } + + void Serialise(const char *name, rdctype::str &el) + { + int32_t sz = el.count; + Serialise(name, sz); + if(m_Mode == WRITING) + { + for(int32_t i=0; i < sz; i++) + Serialise("[]", el.elems[i]); + } + else + { + create_array_uninit(el, sz); + for(int32_t i=0; i < sz; i++) + Serialise("", el.elems[i]); + } + } + + template + void Serialise(const char *name, std::pair &el) + { + Serialise(name, el.first); + Serialise(name, el.second); + } + + template + void Serialise(const char *name, rdctype::pair &el) + { + Serialise(name, el.first); + Serialise(name, el.second); + } + + template + void Serialise(const char *name, std::list &el) + { + uint64_t sz = el.size(); + Serialise(name, sz); + if(m_Mode == WRITING) + { + for(auto it=el.begin(); it != el.end(); ++it) + Serialise("[]", *it); + } + else + { + el.clear(); + for(uint64_t i=0; i < sz; i++) + { + X x = X(); + Serialise("", x); + el.push_back(x); + } + } + } + + // not sure if I still neeed these specialisations anymore. + void SerialiseString(const char *name, string &el); + void SerialiseString(const char *name, wstring &el); + + // serialise a buffer. + // + // If serialising in, buf must either be NULL in which case allocated + // memory will be returned, or it must be already large enough. + void SerialiseBuffer(const char *name, byte *&buf, size_t &len); + void SkipBuffer(); + + // NOT recommended interface. Useful for specific situations if e.g. you have + // a buffer of data that is not arbitrary in size and can be determined by a 'type' or + // similar elsewhere in the stream, so you want to skip the type-safety of the above + // and write directly into the stream. Must be matched by a RawReadBytes. + void RawWriteBytes(const void *data, size_t bytes) + { + WriteBytes((const byte *)data, bytes); + } + + const void *RawReadBytes(size_t bytes) + { + return ReadBytes(bytes); + } + + // prints to the debug output log + void DebugPrint(const char *fmt, ...); + + static byte *AllocAlignedBuffer(size_t size); + static void FreeAlignedBuffer(byte *buf); + + uint64_t FlushToDisk(); + + // set a function used when serialising a text representation + // of the chunks + void SetChunkNameLookup(ChunkLookup lookup) + { + m_ChunkLookup = lookup; + } + + void SetDebugText(bool enabled) + { + m_DebugTextWriting = enabled; + } + + bool GetDebugText() + { + return m_DebugTextWriting; + } + + string GetDebugStr() + { + return m_DebugText; + } + + // debug-only output must be locked since it's global across all serialisers + // essentially, which might not be thread safe in the normal flow + void DebugLock() + { + m_DebugLock.Lock(); + } + + void DebugUnlock() + { + m_DebugLock.Unlock(); + } + + private: + ////////////////////////////////////////// + // Raw memory buffer read/write + + void WriteBytes(const byte *buf, size_t nBytes) + { +#ifdef DEBUG_TEXT_SERIALISER + if(m_Mode == DEBUGWRITING) + return; +#endif + + if(m_HasError) + { + RDCERR("Writing bytes with error state serialiser"); + return; + } + + if(m_Buffer+m_BufferSize < m_BufferHead+nBytes+8) + { + // reallocate + while(m_Buffer+m_BufferSize < m_BufferHead+nBytes+8) + { + m_BufferSize += 128*1024; + } + + byte *newBuf = AllocAlignedBuffer((size_t)m_BufferSize); + + size_t curUsed = m_BufferHead-m_Buffer; + + memcpy(newBuf, m_Buffer, curUsed); + + FreeAlignedBuffer(m_Buffer); + + m_Buffer = newBuf; + m_BufferHead = newBuf + curUsed; + } + + memcpy(m_BufferHead, buf, nBytes); + + m_BufferHead += nBytes; + } + void *ReadBytes(size_t nBytes) + { + if(m_HasError) + { + RDCERR("Reading bytes with error state serialiser"); + return NULL; + } + + // if we would read off the end of our current window + if(m_BufferHead+nBytes > m_Buffer+m_CurrentBufferSize) + { + size_t BufferOffset = m_BufferHead-m_Buffer; + + if(nBytes+64 > m_CurrentBufferSize) + { + FreeAlignedBuffer(m_Buffer); + m_CurrentBufferSize = nBytes+64; + m_Buffer = AllocAlignedBuffer(m_CurrentBufferSize); + } + + if(BufferOffset > 64) + { + m_ReadOffset += BufferOffset-64; + m_BufferHead = m_Buffer+64; + } + else + { + m_BufferHead = m_Buffer+BufferOffset; + } + + // if there's anything left of the file to read in, do so now + ReadFromFile(m_ReadOffset, RDCMIN(m_CurrentBufferSize, (size_t)(m_BufferSize-m_ReadOffset))); + } + + void *ret = m_BufferHead; + + m_BufferHead += nBytes; + + RDCASSERT(m_BufferHead <= m_Buffer+m_CurrentBufferSize); + + return ret; + } + + void ReadFromFile(uint64_t destOffs, size_t chunkLen); + + template void WriteFrom(const T &f) + { + WriteBytes((byte *)&f, sizeof(T)); + } + + template void ReadInto(T &f) + { + if(m_HasError) + { + RDCERR("Reading into with error state serialiser"); + return; + } + + char *data = (char *)ReadBytes(sizeof(T)); + f = *((T *)data); + } + + // no copies + Serialiser(const Serialiser &other); + + static void CreateResolver(void *ths); + + // clean out for before constructor and after destructor (and other times probably) + void Reset(); + + string GetIndent() + { + if(m_Mode == READING) + return string(m_Indent > 0 ? 4 : 0, ' '); + + return string((size_t)m_Indent*4, ' '); + } + + ////////////////////////////////////////// + + static const uint32_t MAGIC_HEADER; + + static const size_t BufferAlignment; + + struct DebuggerHeader + { + DebuggerHeader() + { + magic = MAGIC_HEADER; + version = SERIALISE_VERSION; + } + + uint64_t magic; + uint64_t version; + uint64_t fileSize; + uint64_t resolveDBSize; + }; + + ////////////////////////////////////////// + + Mode m_Mode; + + SerialiserError m_ErrorCode; + bool m_HasError; + bool m_DebugEnabled; + + int m_Indent; + + bool m_HasResolver; + Callstack::Stackwalk *m_pCallstack; + Callstack::StackResolver *m_pResolver; + Threading::ThreadHandle m_ResolverThread; + volatile bool m_ResolverThreadKillSignal; + + wstring m_Filename; + + // raw binary buffer + uint64_t m_BufferSize; + byte *m_Buffer; + byte *m_BufferHead; + size_t m_LastChunkLen; + bool m_AlignedData; + vector m_ChunkFixups; + + // reading from file: + + // where in the actual on-disk file does the data start (ie. after header and symbol DB) + uint64_t m_FileStartOffset; + + // where does our in-memory window point to in the data stream. ie. m_pBuffer[0] is + // m_ReadOffset into the disk stream + uint64_t m_ReadOffset; + + // how big is the current in-memory window + size_t m_CurrentBufferSize; + + // the file pointer to read from + FILE *m_ReadFileHandle; + + // writing to file + vector m_Chunks; + + // a database of strings read from the file, useful when serialised structures + // expect a char* to return and point to static memory + set m_StringDB; + + // debug buffer + bool m_DebugTextWriting; + string m_DebugText; + ChunkLookup m_ChunkLookup; + + Threading::CriticalSection m_DebugLock; +}; + +template<> void Serialiser::Serialise(const char *name, string &el); +template<> void Serialiser::Serialise(const char *name, wstring &el); + +// floats need aligned reads +template<> void Serialiser::ReadInto(float &f); + +class ScopedContext +{ + public: + ScopedContext(Serialiser *s, Serialiser *debugser, const char *n, const char *t, uint32_t i, bool smallChunk) + : m_Idx(i), m_Ser(s), m_Ended(false) +#ifdef DEBUG_TEXT_SERIALISER + , m_DebugSer(debugser) +#endif + { + m_Name = string(n) + " = " + t; + m_Ser->PushContext(m_Name.c_str(), m_Idx, smallChunk); + +#ifdef DEBUG_TEXT_SERIALISER + if(m_DebugSer) + { + m_DebugSer->DebugLock(); + m_DebugSer->PushContext(m_Name.c_str(), m_Idx, smallChunk); + } +#endif + } + ScopedContext(Serialiser *s, Serialiser *debugser, const char *n, uint32_t i, bool smallChunk) + : m_Idx(i), m_Ser(s), m_Ended(false) +#ifdef DEBUG_TEXT_SERIALISER + , m_DebugSer(debugser) +#endif + { + m_Name = n; + m_Ser->PushContext(m_Name.c_str(), m_Idx, smallChunk); + +#ifdef DEBUG_TEXT_SERIALISER + if(m_DebugSer) + { + m_DebugSer->DebugLock(); + m_DebugSer->PushContext(m_Name.c_str(), m_Idx, smallChunk); + } +#endif + } + ~ScopedContext() + { + if(!m_Ended) + End(); + } + + Chunk *Get(bool temporary = false) + { + End(); + return new Chunk(m_Ser, m_Idx, temporary); + } + private: + std::string m_Name; + uint32_t m_Idx; + Serialiser *m_Ser; +#ifdef DEBUG_TEXT_SERIALISER + Serialiser *m_DebugSer; +#endif + + bool m_Ended; + + void End() + { + RDCASSERT(!m_Ended); + + m_Ser->PopContext(m_Name.c_str(), m_Idx); + +#ifdef DEBUG_TEXT_SERIALISER + if(m_DebugSer) + { + m_DebugSer->PopContext(m_Name.c_str(), m_Idx); + m_DebugSer->DebugUnlock(); + } +#endif + + m_Ended = true; + } +}; + +#ifdef DEBUG_TEXT_SERIALISER +#define SCOPED_SERIALISE_CONTEXT(n) ScopedContext scope(m_pSerialiser, m_pDebugSerialiser, GetChunkName(n), n, false); +#define SCOPED_SERIALISE_SMALL_CONTEXT(n) ScopedContext scope(m_pSerialiser, m_pDebugSerialiser, GetChunkName(n), n, true); + +#define SERIALISE_ELEMENT(type, name, inValue) type name; if(m_State >= WRITING) name = (inValue); m_pSerialiser->Serialise(#name, name); m_pDebugSerialiser->Serialise(#name, name); +#define SERIALISE_ELEMENT_OPT(type, name, inValue, Condition) type name = type(); if(Condition) { if(m_State >= WRITING) name = (inValue); m_pSerialiser->Serialise(#name, name); m_pDebugSerialiser->Serialise(#name, name); } +#define SERIALISE_ELEMENT_ARR(type, name, inValues, count) type *name = new type[count]; for(size_t serialiseIdx=0; serialiseIdx < count; serialiseIdx++) { if(m_State >= WRITING) name[serialiseIdx] = (inValues)[serialiseIdx]; m_pSerialiser->Serialise(#name, name[serialiseIdx]); m_pDebugSerialiser->Serialise(#name, name[serialiseIdx]); } +#define SERIALISE_ELEMENT_ARR_OPT(type, name, inValues, count, Condition) type *name = NULL; if(Condition) { name = new type[count]; for(size_t serialiseIdx=0; serialiseIdx < count; serialiseIdx++) { if(m_State >= WRITING) name[serialiseIdx] = (inValues)[serialiseIdx]; m_pSerialiser->Serialise(#name, name[serialiseIdx]); m_pDebugSerialiser->Serialise(#name, name[serialiseIdx]); } } +#define SERIALISE_ELEMENT_PTR(type, name, inValue) type name; if(inValue && m_State >= WRITING) name = *(inValue); m_pSerialiser->Serialise(#name, name); m_pDebugSerialiser->Serialise(#name, name); +#define SERIALISE_ELEMENT_PTR_OPT(type, name, inValue, Condition) type name; if(Condition) { if(inValue && m_State >= WRITING) name = *(inValue); m_pSerialiser->Serialise(#name, name); m_pDebugSerialiser->Serialise(#name, name); } +#define SERIALISE_ELEMENT_BUF(type, name, inBuf, Len) type name = (type)NULL; if(m_State >= WRITING) name = (type)(inBuf); size_t CONCAT(buflen, __LINE__) = Len; m_pSerialiser->SerialiseBuffer(#name, name, CONCAT(buflen, __LINE__)); m_pDebugSerialiser->SerialiseBuffer(#name, name, CONCAT(buflen, __LINE__)); +#define SERIALISE_ELEMENT_BUF_OPT(type, name, inBuf, Len, Condition) type name = (type)NULL; if(Condition) { if(m_State >= WRITING) name = (type)(inBuf); size_t CONCAT(buflen, __LINE__) = Len; m_pSerialiser->SerialiseBuffer(#name, name, CONCAT(buflen, __LINE__)); m_pDebugSerialiser->SerialiseBuffer(#name, name, CONCAT(buflen, __LINE__)); } +#else +#define SCOPED_SERIALISE_CONTEXT(n) ScopedContext scope(m_pSerialiser, NULL, GetChunkName(n), n, false); +#define SCOPED_SERIALISE_SMALL_CONTEXT(n) ScopedContext scope(m_pSerialiser, NULL, GetChunkName(n), n, true); + +#define SERIALISE_ELEMENT(type, name, inValue) type name; if(m_State >= WRITING) name = (inValue); m_pSerialiser->Serialise(#name, name); +#define SERIALISE_ELEMENT_OPT(type, name, inValue, Condition) type name = type(); if(Condition) { if(m_State >= WRITING) name = (inValue); m_pSerialiser->Serialise(#name, name); } +#define SERIALISE_ELEMENT_ARR(type, name, inValues, count) type *name = new type[count]; for(size_t serialiseIdx=0; serialiseIdx < count; serialiseIdx++) { if(m_State >= WRITING) name[serialiseIdx] = (inValues)[serialiseIdx]; m_pSerialiser->Serialise(#name, name[serialiseIdx]); } +#define SERIALISE_ELEMENT_ARR_OPT(type, name, inValues, count, Condition) type *name = NULL; if(Condition) { name = new type[count]; for(size_t serialiseIdx=0; serialiseIdx < count; serialiseIdx++) { if(m_State >= WRITING) name[serialiseIdx] = (inValues)[serialiseIdx]; m_pSerialiser->Serialise(#name, name[serialiseIdx]); } } +#define SERIALISE_ELEMENT_PTR(type, name, inValue) type name; if(inValue && m_State >= WRITING) name = *(inValue); m_pSerialiser->Serialise(#name, name); +#define SERIALISE_ELEMENT_PTR_OPT(type, name, inValue, Condition) type name; if(Condition) { if(inValue && m_State >= WRITING) name = *(inValue); m_pSerialiser->Serialise(#name, name); } +#define SERIALISE_ELEMENT_BUF(type, name, inBuf, Len) type name = (type)NULL; if(m_State >= WRITING) name = (type)(inBuf); size_t CONCAT(buflen, __LINE__) = Len; m_pSerialiser->SerialiseBuffer(#name, name, CONCAT(buflen, __LINE__)); +#define SERIALISE_ELEMENT_BUF_OPT(type, name, inBuf, Len, Condition) type name = (type)NULL; if(Condition) { if(m_State >= WRITING) name = (type)(inBuf); size_t CONCAT(buflen, __LINE__) = Len; m_pSerialiser->SerialiseBuffer(#name, name, CONCAT(buflen, __LINE__)); } +#endif + +// forward declare generic pointer version to void* +template +struct ToStrHelper +{ + static string Get(const T &el) + { + void *ptr = (void *)el; + return ToStrHelper::Get(ptr); + } +}; + +#define TOSTR_CASE_STRINGIZE(a) case a: return #a; +#define TOSTR_CASE_STRINGIZE_CONCAT(a, b) case CONCAT(a, b): return #b; +#define TOSTR_CASE_STRINGIZE_NAMESPACE(a, b) case a::b: return #b; + diff --git a/renderdoccmd/Makefile b/renderdoccmd/Makefile new file mode 100644 index 0000000000..61c4747f4b --- /dev/null +++ b/renderdoccmd/Makefile @@ -0,0 +1,29 @@ +CC=gcc +CPP=g++ +MACROS=-DLINUX \ + -DRENDERDOC_PLATFORM=linux \ + -DRENDERDOC_EXPORTS \ + -DGIT_COMMIT_HASH='"'$$(git rev-parse HEAD)'"' \ + -DRENDERDOC_VERSION_STRING='"0.20"' +CFLAGS=-c -Wall -Werror -fPIC $(MACROS) -I. +CPPFLAGS=-std=c++11 -g -Wno-unused -Wno-unknown-pragmas -Wno-reorder +LDFLAGS=-L../renderdoc -lrenderdoc +OBJECTS=linux_specific.o + +all: bin/renderdoccmd + +%.o: %.cpp + $(CPP) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +../renderdoc/librenderdoc.so: + +bin/renderdoccmd: $(OBJECTS) $(SOURCES) ../renderdoc/librenderdoc.so + mkdir -p bin/ + g++ -o bin/renderdoccmd $(LDFLAGS) $(OBJECTS) + +clean: + find -type f -iname \*.o -exec rm '{}' \; + rm -f bin/renderdoccmd diff --git a/renderdoccmd/linux_specific.cpp b/renderdoccmd/linux_specific.cpp new file mode 100644 index 0000000000..d9fb558fee --- /dev/null +++ b/renderdoccmd/linux_specific.cpp @@ -0,0 +1,31 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include + +int main() +{ + puts("foo"); + return 0; +} diff --git a/renderdoccmd/miniz.c b/renderdoccmd/miniz.c new file mode 100644 index 0000000000..ec9e344f47 --- /dev/null +++ b/renderdoccmd/miniz.c @@ -0,0 +1,4838 @@ +/* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated May 20, 2012 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Change History + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. + Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). + Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. + Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. + Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. + Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) + Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a + Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). + Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. + Refactored the compression code for better readability and maintainability. + Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#pragma warning(disable: 4996) + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or +// get/set file times. +//#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +#define MZ_VERSION "9.1.14" +#define MZ_VERNUM 0x91E0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 14 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). +enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s +{ + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. +// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + typedef unsigned char Byte; + typedef unsigned int uInt; + typedef mz_ulong uLong; + typedef Byte Bytef; + typedef uInt uIntf; + typedef char charf; + typedef int intf; + typedef void *voidpf; + typedef uLong uLongf; + typedef void *voidp; + typedef void *const voidpc; + #define Z_NULL 0 + #define Z_NO_FLUSH MZ_NO_FLUSH + #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH + #define Z_SYNC_FLUSH MZ_SYNC_FLUSH + #define Z_FULL_FLUSH MZ_FULL_FLUSH + #define Z_FINISH MZ_FINISH + #define Z_BLOCK MZ_BLOCK + #define Z_OK MZ_OK + #define Z_STREAM_END MZ_STREAM_END + #define Z_NEED_DICT MZ_NEED_DICT + #define Z_ERRNO MZ_ERRNO + #define Z_STREAM_ERROR MZ_STREAM_ERROR + #define Z_DATA_ERROR MZ_DATA_ERROR + #define Z_MEM_ERROR MZ_MEM_ERROR + #define Z_BUF_ERROR MZ_BUF_ERROR + #define Z_VERSION_ERROR MZ_VERSION_ERROR + #define Z_PARAM_ERROR MZ_PARAM_ERROR + #define Z_NO_COMPRESSION MZ_NO_COMPRESSION + #define Z_BEST_SPEED MZ_BEST_SPEED + #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION + #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION + #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY + #define Z_FILTERED MZ_FILTERED + #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY + #define Z_RLE MZ_RLE + #define Z_FIXED MZ_FIXED + #define Z_DEFLATED MZ_DEFLATED + #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS + #define alloc_func mz_alloc_func + #define free_func mz_free_func + #define internal_state mz_internal_state + #define z_stream mz_stream + #define deflateInit mz_deflateInit + #define deflateInit2 mz_deflateInit2 + #define deflateReset mz_deflateReset + #define deflate mz_deflate + #define deflateEnd mz_deflateEnd + #define deflateBound mz_deflateBound + #define compress mz_compress + #define compress2 mz_compress2 + #define compressBound mz_compressBound + #define inflateInit mz_inflateInit + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define uncompress mz_uncompress + #define crc32 mz_crc32 + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 + #define zError mz_error + #define ZLIB_VERSION MZ_VERSION + #define ZLIB_VERNUM MZ_VERNUM + #define ZLIB_VER_MAJOR MZ_VER_MAJOR + #define ZLIB_VER_MINOR MZ_VER_MINOR + #define ZLIB_VER_REVISION MZ_VER_REVISION + #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION + #define zlibVersion mz_version + #define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER + #define MZ_MACRO_END while (0, 0) +#else + #define MZ_MACRO_END while (0) +#endif + +// ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + +enum +{ + MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 +}; + +typedef struct +{ + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum +{ + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef enum +{ + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 +} mz_zip_flags; + +// ZIP archive reading + +// Inits a ZIP archive reader. +// These functions read and validate the archive's central directory. +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +#endif + +// Returns the total number of files in the archive. +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// Returns detailed information about an archive file entry. +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +// Determines if an archive file entry is a directory entry. +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +// Retrieves the filename of an archive file entry. +// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +// Attempts to locates a file in the archive's central directory. +// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH +// Returns -1 if the file cannot be found. +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + +// Extracts a archive file to a memory buffer using no memory allocation. +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +// Extracts a archive file to a memory buffer. +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +// Extracts a archive file to a dynamically allocated heap buffer. +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +// Extracts a archive file using a callback function to output the file's data. +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +// Extracts a archive file to a disk file and sets its last accessed and modified times. +// This function only extracts files, not archive directory records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); +#endif + +// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +// ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// Inits a ZIP archive writer. +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +#endif + +// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. +// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. +// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). +// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. +// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before +// the archive is finalized the file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); + +// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. +// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO +// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +#endif + +// Adds a file to an archive by fully cloning the data from another archive. +// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); + +// Finalizes the archive by writing the central directory records followed by the end of central directory record. +// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). +// An archive must be manually finalized by calling this function for it to be valid. +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); + +// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. +// Note for the archive to be valid, it must have been finalized before ending. +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +// Misc. high-level helper functions: + +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +// Reads a single file from an archive into a heap block. +// Returns NULL on failure. +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). +enum +{ + TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#else +enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#endif + +// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. +typedef enum +{ + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum +{ + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; + +#include +#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) (void)x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) malloc(x) + #define MZ_FREE(x) free(x) + #define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER + #define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define MZ_FORCEINLINE __attribute__((__always_inline__)) +#else + #define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +// ------------------- zlib-style API's + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } + return ~crcu32; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } +static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } +static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; + for ( ; ; ) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for ( ; ; ) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + else if (flush == MZ_FINISH) + { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) +{ + static struct { int m_err; const char *m_pDesc; } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, + { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif //MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, + 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, + 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, + 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, + 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, + 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, + 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, + 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7 }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. +typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32* pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next=1; next < n-1; next++) + { + if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; + avbl = 1; used = dpth = 0; root = n-2; next = n-1; + while (avbl>0) + { + while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } + while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } + avbl = 2*used; dpth++; used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; mz_uint32 total = 0; if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) do { \ + mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ +} MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ +} rle_repeat_count = 0; } } + +#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ +} rle_z_count = 0; } } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64*)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) + { + mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } + } + else + { + mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + if (!probe_len) + { + *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; + if (probe_len > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) + { + int n; + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; + d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; + do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); + pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; + } + memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; + *pOut_len = out_buf.m_size; return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; + return out_buf.m_size; +} + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif //MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + y * bpl, bpl, TDEFL_NO_FLUSH); } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + // write real header + *pLen_out = out_buf.m_size-41; + { + mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,"\0\0\04\02\06"[num_chans],0,0,0,0,0,0,0, + (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; + c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; +} + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +// ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef MINIZ_NO_STDIO + #define MZ_FILE void * +#else + #include + #include + #if defined(_MSC_VER) || defined(__MINGW64__) + #include + #define MZ_FILE FILE + #define MZ_FOPEN fopen + #define MZ_FWOPEN _wfopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 _ftelli64 + #define MZ_FSEEK64 _fseeki64 + #define MZ_FILE_STAT_STRUCT _stat + #define MZ_FILE_STAT _stat + #define MZ_WFILE_STAT_STRUCT _stat + #define MZ_WFILE_STAT _wstat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN freopen + #define MZ_DELETE_FILE remove + #elif defined(__MINGW32__) + #include + #define MZ_FILE FILE + #define MZ_FOPEN fopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello64 + #define MZ_FSEEK64 fseeko64 + #define MZ_FILE_STAT_STRUCT _stat + #define MZ_FILE_STAT _stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN freopen + #define MZ_DELETE_FILE remove + #else + #include + #define MZ_FILE FILE + #define MZ_FOPEN fopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello + #define MZ_FSEEK64 fseeko + #define MZ_FILE_STAT_STRUCT stat + #define MZ_FILE_STAT stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN freopen + #define MZ_DELETE_FILE remove + #endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. +enum +{ + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; + pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; + memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ + struct tm *tm = localtime(&time); + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif + +#ifndef MINIZ_NO_STDIO +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef MINIZ_NO_TIME + (void)pFilename; *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} + +static mz_bool mz_zip_get_wfile_modified_time(const wchar_t *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef MINIZ_NO_TIME + (void)pFilename; *pDOS_date = *pDOS_time = 0; +#else + struct MZ_WFILE_STAT_STRUCT file_stat; if (MZ_WFILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) +{ +#ifndef MINIZ_NO_TIME + struct utimbuf t; t.actime = access_time; t.modtime = modified_time; + return !utime(pFilename, &t); +#else + pFilename, access_time, modified_time; + return MZ_TRUE; +#endif // #ifndef MINIZ_NO_TIME +} +#endif + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END + +// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) + { + int child, root = start; + for ( ; ; ) + { + if ((child = (root << 1) + 1) >= size) + break; + child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + } + start--; + } + + end = size - 1; + while (end > 0) + { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for ( ; ; ) + { + if ((child = (root << 1) + 1) >= end) + break; + child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) +{ + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end towards the beginning. + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for ( ; ; ) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + break; + if (i >= 0) + { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return MZ_FALSE; + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + return MZ_FALSE; + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; + + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) + { + mz_uint i, n; + // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return MZ_FALSE; + + // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) + return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return MZ_FALSE; + n -= total_header_size; p += total_header_size; + } + } + + if ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) +{ + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pMem = (void *)pMem; + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + return MZ_FALSE; + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, internal_attr, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + + internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((!internal_attr) && ((external_attr & 0x10) != 0)) + return MZ_TRUE; + + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + return MZ_FALSE; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) + return MZ_FALSE; + + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; + + return MZ_TRUE; +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) + { + int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint file_index; size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_p)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((buf_size) && (!pBuf)) + return MZ_FALSE; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if (!file_stat.m_comp_size) + return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + + // Decompress the file either directly from memory or from a file input buffer. + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + // Use a user provided read buffer. + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_uncomp_size; + } + else + { + // Temporarily allocate a read buffer. + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) + *pSize = 0; + if (!p) + return NULL; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if (!file_stat.m_comp_size) + return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + // Decompress the file either directly from memory or from a file input buffer. + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) + { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return MZ_FALSE; + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) + return MZ_FALSE; +#ifndef MINIZ_NO_TIME + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + return status; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} +#endif + +// ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (pZip->m_file_offset_alignment) + { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; +} + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_xfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 size_to_reserve_at_beginning) +{ + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + MZ_FILE *pFile; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) + return MZ_FALSE; + return mz_zip_writer_init_xfile(pZip, pFile, size_to_reserve_at_beginning); +} + +mz_bool mz_zip_writer_init_wfile(mz_zip_archive *pZip, const wchar_t *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + MZ_FILE *pFile; + if (NULL == (pFile = MZ_FWOPEN(pFilename, L"wb"))) + return MZ_FALSE; + return mz_zip_writer_init_xfile(pZip, pFile, size_to_reserve_at_beginning); +} + +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max size + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + pFilename; return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + if (!pFilename) + return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } + else if (pState->m_pMem) + { + // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; + + // Start writing new files at the archive's current central directory location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. + if (*pArchive_name == '/') + return MZ_FALSE; + while (*pArchive_name) + { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) + return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + +#ifndef MINIZ_NO_TIME + { + time_t cur_time; time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) + return MZ_FALSE; + } + + // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + method = MZ_DEFLATED; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_xfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + if (uncomp_size > 0xFFFFFFFF) + { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (uncomp_size) + { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!level) + { + while (uncomp_remaining) + { + mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + for ( ; ; ) + { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; + + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + break; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + MZ_FCLOSE(pSrc_file); pSrc_file = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_uint16 dos_time = 0, dos_date = 0; + MZ_FILE *pSrc_file = NULL; + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return MZ_FALSE; + + return mz_zip_writer_add_xfile(pZip, pArchive_name, pSrc_file, pComment, comment_size, level_and_flags, dos_time, dos_date); +} + +mz_bool mz_zip_writer_add_wfile(mz_zip_archive *pZip, const char *pArchive_name, const wchar_t *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_uint16 dos_time = 0, dos_date = 0; + MZ_FILE *pSrc_file = NULL; + + if (!mz_zip_get_wfile_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FWOPEN(pSrc_filename, L"rb"); + if (!pSrc_file) + return MZ_FALSE; + + return mz_zip_writer_add_xfile(pZip, pArchive_name, pSrc_file, pComment, comment_size, level_and_flags, dos_time, dos_date); +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; const mz_uint8 *pSrc_central_header; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) + return MZ_FALSE; + + while (comp_bytes_remaining) + { + n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + + comp_bytes_remaining -= n; + } + + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) + return MZ_FALSE; + + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + if (pState->m_central_dir.m_size > 0xFFFFFFFF) + return MZ_FALSE; + n = (mz_uint32)pState->m_central_dir.m_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + + pState = pZip->m_pState; + + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } + + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return MZ_FALSE; +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_archive_size += sizeof(hdr); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) + return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) + return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } + else + { + // Append to an existing archive. + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) + { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) + status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) + status = MZ_FALSE; + if ((!status) && (created_new_archive)) + { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + return NULL; + + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; + + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + + mz_zip_reader_end(&zip_archive); + return p; +} + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff --git a/renderdoccmd/miniz.h b/renderdoccmd/miniz.h new file mode 100644 index 0000000000..e427fbe1ce --- /dev/null +++ b/renderdoccmd/miniz.h @@ -0,0 +1,87 @@ + +// little header to include forward declarations for miniz.c + +#pragma once + +extern "C" { + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + +typedef enum +{ + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +mz_bool mz_zip_writer_init_wfile(mz_zip_archive *pZip, const wchar_t *pFilename, mz_uint64 size_to_reserve_at_beginning); +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_add_wfile(mz_zip_archive *pZip, const char *pArchive_name, const wchar_t *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +}; // extern "C" \ No newline at end of file diff --git a/renderdoccmd/renderdoccmd.config b/renderdoccmd/renderdoccmd.config new file mode 100644 index 0000000000..8cec188b38 --- /dev/null +++ b/renderdoccmd/renderdoccmd.config @@ -0,0 +1 @@ +// ADD PREDEFINED MACROS HERE! diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp new file mode 100644 index 0000000000..152bc822ab --- /dev/null +++ b/renderdoccmd/renderdoccmd.cpp @@ -0,0 +1,679 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +#include + +#include "resource.h" + +// breakpad +#include "common/windows/http_upload.h" +#include "client/windows/crash_generation/client_info.h" +#include "client/windows/crash_generation/crash_generation_server.h" + +#include "miniz.h" + +using std::string; +using std::wstring; +using std::vector; +using google_breakpad::ClientInfo; +using google_breakpad::CrashGenerationServer; + +bool exitServer = false; + +static HINSTANCE CrashHandlerInst = 0; +static HWND CrashHandlerWnd = 0; + +bool uploadReport = false; +bool uploadDump = false; +bool uploadLog = false; +string reproSteps = ""; + +wstring dump = L""; +vector customInfo; +wstring logpath = L""; + + +INT_PTR CALLBACK CrashHandlerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + HANDLE hIcon = LoadImage(CrashHandlerInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0); + + if(hIcon) + { + SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + } + + SetDlgItemTextW(hDlg, IDC_WELCOMETEXT, + L"RenderDoc has encountered an unhandled exception or other similar unrecoverable error.\n\n" \ + L"If you had captured but not saved a logfile it should still be available in %TEMP% and will not be deleted," \ + L"you can try loading it again.\n\n" \ + L"A minidump has been created and the RenderDoc diagnostic log (NOT any capture logfile) is available if you would like " \ + L"to send them back to be analysed. The path for both is found below if you would like to inspect their contents and censor as appropriate.\n\n" \ + L"Neither contains any significant private information, the minidump has some internal states and local memory at the time of the " \ + L"crash & thread stacks, etc. The diagnostic log contains diagnostic messages like warnings and errors.\n\n" \ + L"The only other information sent is the version of RenderDoc, C# exception callstack, and any notes you include.\n\n" \ + L"Any repro steps or notes would be helpful to include with the report. If you'd like to be contacted about the bug " \ + L"e.g. for updates about its status just include your email & name. Thank you!\n\n" \ + L"Baldur (renderdoc@crytek.com)"); + + SetDlgItemTextW(hDlg, IDC_DUMPPATH, dump.c_str()); + SetDlgItemTextW(hDlg, IDC_LOGPATH, logpath.c_str()); + + CheckDlgButton(hDlg, IDC_SENDDUMP, BST_CHECKED); + CheckDlgButton(hDlg, IDC_SENDLOG, BST_CHECKED); + } + + case WM_SHOWWINDOW: + { + + { + RECT r; + GetClientRect(hDlg, &r); + + int xPos = (GetSystemMetrics(SM_CXSCREEN) - r.right)/2; + int yPos = (GetSystemMetrics(SM_CYSCREEN) - r.bottom)/2; + + SetWindowPos(hDlg, NULL, xPos, yPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE); + } + + return (INT_PTR)TRUE; + } + + case WM_COMMAND: + { + int ID = LOWORD(wParam); + + if(ID == IDC_DONTSEND) + { + EndDialog(hDlg, 0); + return (INT_PTR)TRUE; + } + else if(ID == IDC_SEND) + { + uploadReport = true; + uploadDump = (IsDlgButtonChecked(hDlg, IDC_SENDDUMP) != 0); + uploadLog = (IsDlgButtonChecked(hDlg, IDC_SENDLOG) != 0); + + char notes[4097] = {0}; + + GetDlgItemTextA(hDlg, IDC_NAME, notes, 4096); + notes[4096] = 0; + + reproSteps = "Name: "; + reproSteps += notes; + reproSteps += "\n"; + + memset(notes, 0, 4096); + GetDlgItemTextA(hDlg, IDC_EMAIL, notes, 4096); + notes[4096] = 0; + + reproSteps += "Email: "; + reproSteps += notes; + reproSteps += "\n\n"; + + memset(notes, 0, 4096); + GetDlgItemTextA(hDlg, IDC_REPRO, notes, 4096); + notes[4096] = 0; + + reproSteps += notes; + + EndDialog(hDlg, 0); + return (INT_PTR)TRUE; + } + } + break; + + case WM_QUIT: + case WM_DESTROY: + case WM_CLOSE: + { + EndDialog(hDlg, 0); + return (INT_PTR)TRUE; + } + break; + } + return (INT_PTR)FALSE; +} + +static void _cdecl OnClientCrashed(void* context, const ClientInfo* client_info, const wstring* dump_path) +{ + if(dump_path) + { + dump = *dump_path; + + google_breakpad::CustomClientInfo custom = client_info->GetCustomInfo(); + + for(size_t i=0; i < custom.count; i++) + customInfo.push_back(custom.entries[i]); + } + + exitServer = true; +} + +static void _cdecl OnClientExited(void* context, const ClientInfo* client_info) +{ + exitServer = true; +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if(msg == WM_CLOSE) { DestroyWindow(hwnd); return 0; } + if(msg == WM_DESTROY) { PostQuitMessage(0); return 0; } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +void DisplayRendererPreview(ReplayRenderer *renderer, HINSTANCE hInstance) +{ + if(renderer == NULL) return; + + HWND wnd = 0; + + wnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdoccmd", L"renderdoccmd", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, + NULL, NULL, hInstance, NULL); + + if(wnd == NULL) + { + return; + } + + ShowWindow(wnd, SW_SHOW); + UpdateWindow(wnd); + + rdctype::array texs; + ReplayRenderer_GetTextures(renderer, &texs); + + ReplayOutput *out = ReplayRenderer_CreateOutput(renderer, wnd); + + ReplayRenderer_SetFrameEvent(renderer, 0, 10000000); + + OutputConfig c; + c.m_Type = eOutputType_TexDisplay; + + ReplayOutput_SetOutputConfig(out, c); + + for(int32_t i=0; i < texs.count; i++) + { + wstring name(texs[i].name.elems, texs[i].name.elems+texs[i].name.count); + if(name.find(L"Swap") != wstring::npos) + { + TextureDisplay d; + d.texid = texs[i].ID; + d.mip = 0; + d.overlay = eTexOverlay_None; + d.CustomShader = ResourceId(); + d.HDRMul = -1.0f; + d.rangemin = 0.0f; + d.rangemax = 1.0f; + d.scale = 1.0f; + d.offx = 0.0f; + d.offy = 0.0f; + d.sliceFace = 0; + d.rawoutput = false; + d.Red = d.Green = d.Blue = true; + d.Alpha = false; + + ReplayOutput_SetTextureDisplay(out, d); + + break; + } + } + + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + while(true) + { + // Check to see if any messages are waiting in the queue + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + // Translate the message and dispatch it to WindowProc() + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // If the message is WM_QUIT, exit the while loop + if(msg.message == WM_QUIT) + break; + + ReplayRenderer_SetFrameEvent(renderer, 0, 10000000+rand()%1000); + + ReplayOutput_SetOutputConfig(out, c); + + ReplayOutput_Display(out); + + Sleep(40); + } +} + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) +{ + LPWSTR *argv; + int argc; + + argv = CommandLineToArgvW(GetCommandLine(), &argc); + + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = L"renderdoccmd"; + wc.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON)); + + if(!RegisterClassEx(&wc)) + { + return 1; + } + + CrashGenerationServer *crashServer = NULL; + + if(argc == 2 && !_wcsicmp(argv[1], L"crashhandle")) + { + wchar_t tempPath[MAX_PATH] = {0}; + GetTempPathW(MAX_PATH-1, tempPath); + + Sleep(100); + + wstring dumpFolder = tempPath; + dumpFolder += L"RenderDocDumps"; + + CreateDirectoryW(dumpFolder.c_str(), NULL); + + crashServer = new CrashGenerationServer(L"\\\\.\\pipe\\RenderDocBreakpadServer", + NULL, NULL, NULL, OnClientCrashed, NULL, + OnClientExited, NULL, NULL, NULL, true, + &dumpFolder); + + if (!crashServer->Start()) { + delete crashServer; + crashServer = NULL; + return 1; + } + + CrashHandlerInst = hInstance; + + CrashHandlerWnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdoccmd", L"renderdoccmd", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 10, 10, + NULL, NULL, hInstance, NULL); + + HANDLE hIcon = LoadImage(CrashHandlerInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0); + + if(hIcon) + { + SendMessage(CrashHandlerWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + SendMessage(CrashHandlerWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + } + + ShowWindow(CrashHandlerWnd, SW_HIDE); + + HANDLE readyEvent = CreateEventA(NULL, TRUE, FALSE, "RENDERDOC_CRASHHANDLE"); + + if(readyEvent != NULL) + { + SetEvent(readyEvent); + + CloseHandle(readyEvent); + } + + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + while(!exitServer) + { + // Check to see if any messages are waiting in the queue + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + // Translate the message and dispatch it to WindowProc() + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // If the message is WM_QUIT, exit the while loop + if(msg.message == WM_QUIT) + break; + + Sleep(100); + } + + delete crashServer; + crashServer = NULL; + + if(!dump.empty()) + { + logpath = L""; + + string report = ""; + + for(size_t i=0; i < customInfo.size(); i++) + { + wstring name = customInfo[i].name; + wstring val = customInfo[i].value; + + if(name == L"logpath") + { + logpath = val; + } + else if(name == L"ptime") + { + // breakpad uptime, ignore. + } + else + { + report += string(name.begin(), name.end()) + ": " + string(val.begin(), val.end()) + "\n"; + } + } + + DialogBox(CrashHandlerInst, MAKEINTRESOURCE(IDD_CRASH_HANDLER), CrashHandlerWnd, (DLGPROC)CrashHandlerProc); + + report += "\n\nRepro steps/Notes:\n\n" + reproSteps; + + { + FILE *f = NULL; + _wfopen_s(&f, logpath.c_str(), L"r"); + if(f) + { + fseek(f, 0, SEEK_END); + long filesize = ftell(f); + fseek(f, 0, SEEK_SET); + + if(filesize > 10) + { + char *error_log = new char[filesize+1]; + memset(error_log, 0, filesize+1); + + fread(error_log, 1, filesize, f); + + char *managed_callstack = strstr(error_log, "--- Begin C# Exception Data ---"); + if(managed_callstack) + { + report += managed_callstack; + report += "\n\n"; + } + + delete[] error_log; + } + + fclose(f); + } + } + + if(uploadReport) + { + mz_zip_archive zip; + ZeroMemory(&zip, sizeof(zip)); + + wstring destzip = dumpFolder + L"\\report.zip"; + + DeleteFileW(destzip.c_str()); + + mz_zip_writer_init_wfile(&zip, destzip.c_str(), 0); + mz_zip_writer_add_mem(&zip, "report.txt", report.c_str(), report.length(), MZ_BEST_COMPRESSION); + + if(uploadDump && !dump.empty()) + mz_zip_writer_add_wfile(&zip, "minidump.dmp", dump.c_str(), NULL, 0, MZ_BEST_COMPRESSION); + + if(uploadLog && !logpath.empty()) + mz_zip_writer_add_wfile(&zip, "error.log", logpath.c_str(), NULL, 0, MZ_BEST_COMPRESSION); + + mz_zip_writer_finalize_archive(&zip); + mz_zip_writer_end(&zip); + + int timeout = 10000; + wstring body = L""; + int code = 0; + + std::map params; + + google_breakpad::HTTPUpload::SendRequest(L"http://renderdoc.org/bugsubmit", params, + dumpFolder + L"\\report.zip", L"report", &timeout, &body, &code); + + DeleteFileW(destzip.c_str()); + } + } + + if(!dump.empty()) + DeleteFileW(dump.c_str()); + + if(!logpath.empty()) + DeleteFileW(logpath.c_str()); + + return 0; + } + + HMODULE renderdoc = LoadLibrary(_T("renderdoc.dll")); + + if(!renderdoc) + { + OutputDebugString(_T("Couldn't load library!")); + return 1; + } + + CaptureOptions opts; + opts.AllowFullscreen = false; + opts.AllowVSync = false; + opts.DelayForDebugger = 5; + opts.HookIntoChildren = true; + + if(argc == 2) + { + // if we were given an exe, inject into it + if(wcsstr(argv[1], L".exe") != NULL) + { + uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1], NULL, NULL, NULL, &opts, false); + + if(ident == 0) + printf("Failed to create & inject\n"); + else + printf("Created & injected as %d\n", ident); + + return ident; + } + // if we were given a logfile, load it and continually replay it. + else if(wcsstr(argv[1], L".rdc") != NULL) + { + float progress = 0.0f; + ReplayRenderer *renderer = NULL; + auto status = RENDERDOC_CreateReplayRenderer(argv[1], &progress, &renderer); + + if(renderer && status == eReplayCreate_Success) + DisplayRendererPreview(renderer, hInstance); + + delete renderer; + return 0; + } + else if(wcsstr(argv[1], L"-replayhost") != NULL) + { + RENDERDOC_SpawnReplayHost(NULL); + return 1; + } + } + else if(argc == 3) + { + if(!_wcsicmp(argv[1], L"-inject")) + { + wchar_t *pid = argv[2]; + while(*pid == L'"' || iswspace(*pid)) pid++; + + DWORD pidNum = (DWORD)_wtoi(pid); + + uint32_t ident = RENDERDOC_InjectIntoProcess(pidNum, NULL, &opts, false); + + if(ident == 0) + printf("Failed to inject\n"); + else + printf("Injected as %d\n", ident); + + return ident; + } + else + { + uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1], NULL, NULL, argv[2], &opts, false); + + if(ident == 0) + printf("Failed to create & inject\n"); + else + printf("Created & injected as %d\n", ident); + + return ident; + } + } + else if(argc == 4) + { + if(argc == 4 && wcsstr(argv[1], L"-replay") != NULL) + { + RemoteRenderer *remote = NULL; + auto status = RENDERDOC_CreateRemoteReplayConnection(argv[2], &remote); + + if(remote == NULL || status != eReplayCreate_Success) + return 1; + + float progress = 0.0f; + + ReplayRenderer *renderer = NULL; + status = RemoteRenderer_CreateProxyRenderer(remote, 0, argv[3], &progress, &renderer); + + if(renderer && status == eReplayCreate_Success) + DisplayRendererPreview(renderer, hInstance); + + RemoteRenderer_Shutdown(remote); + return 0; + } + } + else if(argc == 5) + { + if(!_wcsicmp(argv[1], L"-cap32for64")) + { + wchar_t *pid = argv[2]; + while(*pid == L'"' || iswspace(*pid)) pid++; + + DWORD pidNum = (DWORD)_wtoi(pid); + + wchar_t *log = argv[3]; + + CaptureOptions cmdopts; + + string optstring(&argv[4][0], &argv[4][0] + wcslen(argv[4])); + + cmdopts.FromString(optstring); + + return RENDERDOC_InjectIntoProcess(pidNum, log, &cmdopts, false); + } + else if(!_wcsicmp(argv[1], L"-remotecontrol")) + { + wchar_t *host = argv[2]; + wchar_t *ident = argv[3]; + while(*ident == L'"' || iswspace(*ident)) ident++; + bool force = argv[4][0] != '0'; + + DWORD identNum = (DWORD)_wtoi(ident); + + wchar_t username[256] = {0}; + DWORD usersize = 255; + GetEnvironmentVariableW(L"renderdoc_username", username, usersize); + + RemoteAccess *access = RENDERDOC_CreateRemoteAccessConnection(host, identNum, username, force); + + if(access == NULL) + { + printf("Failed to connect\n"); + } + else + { + printf("Target: %ls, API: %ls, Busy: %ls\n", RemoteAccess_GetTarget(access), RemoteAccess_GetAPI(access), RemoteAccess_GetBusyClient(access)); + + fflush(stdout); + + volatile bool run = true; + + while(run) + { + RemoteMessage msg; + RemoteAccess_ReceiveMessage(access, &msg); + + if(msg.Type == eRemoteMsg_Disconnected) + { + printf("Disconnected\n"); + RemoteAccess_Shutdown(access); + access = NULL; + break; + } + else if(msg.Type == eRemoteMsg_Busy) + { + printf("Busy: %ls\n", msg.Busy.ClientName.elems); + RemoteAccess_Shutdown(access); + access = NULL; + break; + } + else if(msg.Type == eRemoteMsg_Noop) + { + } + else if(msg.Type == eRemoteMsg_RegisterAPI) + { + printf("Updated - Target: %ls, API: %ls\n", RemoteAccess_GetTarget(access), RemoteAccess_GetAPI(access)); + } + else if(msg.Type == eRemoteMsg_NewCapture) + { + printf("Got capture - %d @ %llu, %d bytes of thumbnail\n", msg.NewCapture.ID, msg.NewCapture.timestamp, msg.NewCapture.thumbnail.count); + } + + fflush(stdout); + } + + if(access) + { + RemoteAccess_Shutdown(access); + access = NULL; + } + } + + fflush(stdout); + + return 0; + } + } + + MessageBoxW(NULL, L"renderdoccmd Usage:\n\n" \ + L"renderdoccmd.exe \"full path to exe\" [\"path to capture logfile to save to\"]\n" \ + L"renderdoccmd.exe \"full path to logfile to replay\"\n" \ + L"renderdoccmd.exe -inject \"Process ID\"\n", + L"renderdoccmd", MB_OK); + return 1; +} diff --git a/renderdoccmd/renderdoccmd.creator b/renderdoccmd/renderdoccmd.creator new file mode 100644 index 0000000000..e94cbbd302 --- /dev/null +++ b/renderdoccmd/renderdoccmd.creator @@ -0,0 +1 @@ +[General] diff --git a/renderdoccmd/renderdoccmd.files b/renderdoccmd/renderdoccmd.files new file mode 100644 index 0000000000..4e69ecc7ec --- /dev/null +++ b/renderdoccmd/renderdoccmd.files @@ -0,0 +1,3 @@ +miniz.c +miniz.h +linux_specific.cpp diff --git a/renderdoccmd/renderdoccmd.includes b/renderdoccmd/renderdoccmd.includes new file mode 100644 index 0000000000..bf8099b23c --- /dev/null +++ b/renderdoccmd/renderdoccmd.includes @@ -0,0 +1 @@ +/home/baldurk/renderdoc/renderdoccmd \ No newline at end of file diff --git a/renderdoccmd/renderdoccmd.rc b/renderdoccmd/renderdoccmd.rc new file mode 100644 index 0000000000..702b19a07f Binary files /dev/null and b/renderdoccmd/renderdoccmd.rc differ diff --git a/renderdoccmd/renderdoccmd.vcxproj b/renderdoccmd/renderdoccmd.vcxproj new file mode 100644 index 0000000000..cf818da9ce --- /dev/null +++ b/renderdoccmd/renderdoccmd.vcxproj @@ -0,0 +1,177 @@ + + + + + Profile + Win32 + + + Profile + x64 + + + Release + Win32 + + + Release + x64 + + + + {D03DF2F9-513C-4084-BBDD-1DEE8D9250D7} + Win32Proj + renderdoccmd + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\breakpad;$(IncludePath) + $(SolutionDir)\breakpad\lib32;$(LibraryPath) + $(SolutionDir)$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\breakpad;$(IncludePath) + $(SolutionDir)\breakpad\lib64;$(LibraryPath) + $(SolutionDir)\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\breakpad;$(IncludePath) + $(SolutionDir)\breakpad\lib32;$(LibraryPath) + $(SolutionDir)$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\breakpad;$(IncludePath) + $(SolutionDir)\breakpad\lib64;$(LibraryPath) + $(SolutionDir)\$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\renderdoc\replay\ + MultiThreadedDLL + + + Windows + true + $(OutDir)\renderdoc.lib;breakpad_common.lib;crash_generation_server.lib;ws2_32.lib;Wininet.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\renderdoc\replay\ + MultiThreadedDLL + + + Windows + true + $(OutDir)\renderdoc.lib;breakpad_common.lib;crash_generation_server.lib;ws2_32.lib;Wininet.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\renderdoc\replay\ + + + Windows + true + true + true + $(OutDir)\renderdoc.lib;breakpad_common.lib;crash_generation_server.lib;ws2_32.lib;Wininet.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\renderdoc\replay\ + + + Windows + true + true + true + $(OutDir)\renderdoc.lib;breakpad_common.lib;crash_generation_server.lib;ws2_32.lib;Wininet.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/renderdoccmd/renderdoccmd.vcxproj.filters b/renderdoccmd/renderdoccmd.vcxproj.filters new file mode 100644 index 0000000000..fd2a8acabf --- /dev/null +++ b/renderdoccmd/renderdoccmd.vcxproj.filters @@ -0,0 +1,31 @@ + + + + + + + + + Resources + + + Resources + + + + + + {3979a11e-8029-4886-a51e-a2a9bb91d69f} + + + + + Resources + + + + + Resources + + + diff --git a/renderdoccmd/resource.h b/renderdoccmd/resource.h new file mode 100644 index 0000000000..b03efd5ef3 Binary files /dev/null and b/renderdoccmd/resource.h differ diff --git a/renderdoccmd/targetver.h b/renderdoccmd/targetver.h new file mode 100644 index 0000000000..87c0086de7 --- /dev/null +++ b/renderdoccmd/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/renderdocui/Code/AppMain.cs b/renderdocui/Code/AppMain.cs new file mode 100644 index 0000000000..c9465dedfc --- /dev/null +++ b/renderdocui/Code/AppMain.cs @@ -0,0 +1,163 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Windows.Forms; +using renderdoc; + +namespace renderdocui.Code +{ + class AppMain + { + [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] + [STAThread] + static void Main(string[] args) + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); + AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); + + // command line arguments that we can call when we temporarily elevate the process + if(args.Contains("--registerRDCext")) + { + Helpers.InstallRDCAssociation(); + return; + } + + if(args.Contains("--registerCAPext")) + { + Helpers.InstallCAPAssociation(); + return; + } + + Win32PInvoke.LoadLibrary("renderdoc.dll"); + + string filename = ""; + + bool temp = false; + + // not real command line argument processing, but allow an argument to indicate we're being passed + // a temporary filename that we should take ownership of to delete when we're done (if the user doesn't + // save it) + foreach(var a in args) + { + if(a.ToLowerInvariant() == "--tempfile") + temp = true; + } + + if (args.Length > 0 && File.Exists(args[args.Length - 1])) + { + filename = args[args.Length - 1]; + } + + var cfg = new PersistantConfig(); + + // load up the config from user folder, handling errors if it's malformed and falling back to defaults + if (File.Exists(Core.ConfigFilename)) + { + try + { + cfg = PersistantConfig.Deserialize(Core.ConfigFilename); + } + catch (System.Xml.XmlException) + { + MessageBox.Show(String.Format("Error loading config file\n{0}\nA default config is loaded and will be saved out.", Core.ConfigFilename)); + } + catch (System.InvalidOperationException) + { + MessageBox.Show(String.Format("Error loading config file\n{0}\nA default config is loaded and will be saved out.", Core.ConfigFilename)); + } + } + + // propogate float formatting settings to the Formatter class used globally to format float values + cfg.SetupFormatter(); + + var core = new Core(filename, temp, cfg); + + try + { + Application.Run(core.AppWindow); + } + catch (Exception e) + { + HandleException(e); + } + + cfg.Serialize(Core.ConfigFilename); + } + + static void LogException(Exception ex) + { + StaticExports.LogText(ex.ToString()); + + if (ex.InnerException != null) + { + StaticExports.LogText("InnerException:"); + LogException(ex.InnerException); + } + } + + static void HandleException(Exception ex) + { + // we log out this string, which is matched against in renderdoccmd to pull out the callstack + // from the log even in the case where the user chooses not to submit the error log + StaticExports.LogText("--- Begin C# Exception Data ---"); + if (ex != null) + { + LogException(ex); + + StaticExports.TriggerExceptionHandler(System.Runtime.InteropServices.Marshal.GetExceptionPointers(), true); + } + else + { + StaticExports.LogText("Exception is NULL"); + + StaticExports.TriggerExceptionHandler(IntPtr.Zero, true); + } + + System.Diagnostics.Process.GetCurrentProcess().Kill(); + } + + static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception) + HandleException(e.ExceptionObject as Exception); + else + HandleException(null); + } + + static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) + { + HandleException(e.Exception); + } + } +} diff --git a/renderdocui/Code/Cameras.cs b/renderdocui/Code/Cameras.cs new file mode 100644 index 0000000000..d33729573c --- /dev/null +++ b/renderdocui/Code/Cameras.cs @@ -0,0 +1,303 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using renderdoc; + +namespace renderdocui.Code +{ + class TimedUpdate + { + public delegate void UpdateMethod(); + + public TimedUpdate(int msCount, UpdateMethod up) + { + m_Rate = msCount; + m_Update = up; + m_CameraTick = new System.Threading.Timer(TickCB, this as object, m_Rate, System.Threading.Timeout.Infinite); + } + + private int m_Rate; + private UpdateMethod m_Update; + private System.Threading.Timer m_CameraTick = null; + + private static void TickCB(object state) + { + var me = (TimedUpdate)state; + me.m_Update(); + me.m_CameraTick.Change(me.m_Rate, System.Threading.Timeout.Infinite); + } + } + + abstract class CameraControls + { + protected CameraControls(Camera c) + { + m_Camera = c; + } + + abstract public void MouseWheel(object sender, MouseEventArgs e); + + abstract public void Reset(Vec3f pos); + abstract public void Update(); + abstract public void Apply(); + + abstract public bool Dirty { get; } + abstract public Vec3f Position { get; } + abstract public Vec3f Rotation { get; } + + virtual public void MouseClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + m_DragStartPos = e.Location; + } + } + + virtual public void MouseMove(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + if (m_DragStartPos.X < 0) + { + m_DragStartPos = e.Location; + } + + m_DragStartPos = e.Location; + } + else + { + m_DragStartPos = new Point(-1, -1); + } + } + + virtual public void KeyUp(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.A || e.KeyCode == Keys.D) + m_CurrentMove[0] = 0; + if (e.KeyCode == Keys.Q || e.KeyCode == Keys.E) + m_CurrentMove[1] = 0; + if (e.KeyCode == Keys.W || e.KeyCode == Keys.S) + m_CurrentMove[2] = 0; + + if (e.Shift) + m_CurrentSpeed = 3.0f; + else + m_CurrentSpeed = 1.0f; + } + + virtual public void KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.W) + m_CurrentMove[2] = 1; + if (e.KeyCode == Keys.S) + m_CurrentMove[2] = -1; + if (e.KeyCode == Keys.Q) + m_CurrentMove[1] = 1; + if (e.KeyCode == Keys.E) + m_CurrentMove[1] = -1; + if (e.KeyCode == Keys.D) + m_CurrentMove[0] = 1; + if (e.KeyCode == Keys.A) + m_CurrentMove[0] = -1; + + if (e.Shift) + m_CurrentSpeed = 3.0f; + else + m_CurrentSpeed = 1.0f; + } + + private float m_CurrentSpeed = 1.0f; + private int[] m_CurrentMove = new int[3] { 0, 0, 0 }; + + public float SpeedMultiplier = 0.05f; + + protected int[] CurrentMove { get { return m_CurrentMove; } } + protected float CurrentSpeed { get { return m_CurrentSpeed * SpeedMultiplier; } } + + private Point m_DragStartPos = new Point(-1, -1); + protected Point DragStartPos { get { return m_DragStartPos; } } + + protected Camera m_Camera; + } + + class ArcballCamera : CameraControls + { + public ArcballCamera(Camera c) + : base(c) + { + } + + public override void Reset(Vec3f dist) + { + m_Distance = Math.Abs(dist.z); + m_Rotation = new Vec3f(); + } + + public override void Update() + { + } + + public override void Apply() + { + m_Camera.Arcball(m_Distance, Rotation); + } + + public override void MouseWheel(object sender, MouseEventArgs e) + { + float mod = (1.0f - (float)e.Delta / 2500.0f); + + m_Distance = Math.Max(1.0f, m_Distance * mod); + + ((HandledMouseEventArgs)e).Handled = true; + + m_Dirty = true; + } + + public override void MouseMove(object sender, MouseEventArgs e) + { + if (DragStartPos.X > 0 && e.Button == MouseButtons.Left) + { + m_Rotation.y += (float)(e.X - DragStartPos.X) / 300.0f; + m_Rotation.x += (float)(e.Y - DragStartPos.Y) / 300.0f; + + m_Dirty = true; + } + + base.MouseMove(sender, e); + } + + bool m_Dirty = false; + public override bool Dirty + { + get + { + bool ret = m_Dirty; + m_Dirty = false; + return ret; + } + } + + private float m_Distance = 10.0f; + private Vec3f m_Rotation = new Vec3f(); + public override Vec3f Position { get { return m_Camera.Position; } } + public override Vec3f Rotation { get { return m_Rotation; } } + } + + class FlyCamera : CameraControls + { + public FlyCamera(Camera c) + : base(c) + { + } + + public override void Reset(Vec3f pos) + { + m_Position = pos; + m_Rotation = new Vec3f(); + } + + public override void Update() + { + if (CurrentMove[0] != 0) + { + Vec3f dir = m_Camera.Right; + dir.Mul((float)CurrentMove[0]); + + m_Position.x += dir.x * CurrentSpeed; + m_Position.y += dir.y * CurrentSpeed; + m_Position.z += dir.z * CurrentSpeed; + + m_Dirty = true; + } + if (CurrentMove[1] != 0) + { + Vec3f dir = new Vec3f(0.0f, 1.0f, 0.0f); + //dir = m_Camera.GetUp(); + dir.Mul((float)CurrentMove[1]); + + m_Position.x += dir.x * CurrentSpeed; + m_Position.y += dir.y * CurrentSpeed; + m_Position.z += dir.z * CurrentSpeed; + + m_Dirty = true; + } + if (CurrentMove[2] != 0) + { + Vec3f dir = m_Camera.Forward; + dir.Mul((float)CurrentMove[2]); + + m_Position.x += dir.x * CurrentSpeed; + m_Position.y += dir.y * CurrentSpeed; + m_Position.z += dir.z * CurrentSpeed; + + m_Dirty = true; + } + } + + public override void Apply() + { + m_Camera.fpsLook(m_Position, m_Rotation); + } + + public override void MouseWheel(object sender, MouseEventArgs e) + { + } + + public override void MouseMove(object sender, MouseEventArgs e) + { + if (DragStartPos.X > 0 && e.Button == MouseButtons.Left) + { + m_Rotation.y -= (float)(e.X - DragStartPos.X) / 300.0f; + m_Rotation.x -= (float)(e.Y - DragStartPos.Y) / 300.0f; + + m_Dirty = true; + } + + base.MouseMove(sender, e); + } + + bool m_Dirty = false; + public override bool Dirty + { + get + { + bool ret = m_Dirty; + m_Dirty = false; + return ret; + } + } + + private Vec3f m_Position = new Vec3f(), + m_Rotation = new Vec3f(); + public override Vec3f Position { get { return m_Position; } } + public override Vec3f Rotation { get { return m_Rotation; } } + } +} diff --git a/renderdocui/Code/CommonPipelineState.cs b/renderdocui/Code/CommonPipelineState.cs new file mode 100644 index 0000000000..db3e4deebf --- /dev/null +++ b/renderdocui/Code/CommonPipelineState.cs @@ -0,0 +1,467 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using renderdoc; + +namespace renderdocui.Code +{ + public class CommonPipelineState + { + private D3D11PipelineState m_D3D11 = null; + private GLPipelineState m_GL = null; + private APIProperties m_APIProps = null; + + public CommonPipelineState() + { + } + + public void SetStates(APIProperties props, D3D11PipelineState d3d11, GLPipelineState gl) + { + m_APIProps = props; + m_D3D11 = d3d11; + m_GL = gl; + } + + private bool LogLoaded + { + get + { + return m_D3D11 != null || m_GL != null; + } + } + + private bool IsLogD3D11 + { + get + { + return LogLoaded && m_APIProps.pipelineType == APIPipelineStateType.D3D11 && m_D3D11 != null; + } + } + + private bool IsLogGL + { + get + { + return LogLoaded && m_APIProps.pipelineType == APIPipelineStateType.OpenGL && m_GL != null; + } + } + + // add a bunch of generic properties that people can check to save having to see which pipeline state + // is valid and look at the appropriate part of it + public bool IsTessellationEnabled + { + get + { + if (LogLoaded) + { + if (IsLogD3D11) + return m_D3D11 != null && m_D3D11.m_HS.Shader != ResourceId.Null; + + if (IsLogGL) + return m_GL != null && m_GL.m_TES.Shader != ResourceId.Null; + } + + return false; + } + } + + public PrimitiveTopology DrawTopology + { + get + { + if (LogLoaded) + { + if (IsLogD3D11) + return m_D3D11.m_IA.Topology; + + if (IsLogGL) + return m_GL.m_VtxIn.Topology; + } + + return PrimitiveTopology.Unknown; + } + } + + // there's a lot of redundancy in these functions + + public ShaderReflection GetShaderReflection(ShaderStageType stage) + { + if (LogLoaded) + { + if (IsLogD3D11) + { + switch (stage) + { + case ShaderStageType.Vertex: return m_D3D11.m_VS.ShaderDetails; + case ShaderStageType.Domain: return m_D3D11.m_DS.ShaderDetails; + case ShaderStageType.Hull: return m_D3D11.m_HS.ShaderDetails; + case ShaderStageType.Geometry: return m_D3D11.m_GS.ShaderDetails; + case ShaderStageType.Pixel: return m_D3D11.m_PS.ShaderDetails; + case ShaderStageType.Compute: return m_D3D11.m_CS.ShaderDetails; + } + } + else if (IsLogGL) + { + switch (stage) + { + case ShaderStageType.Vertex: return m_GL.m_VS.ShaderDetails; + case ShaderStageType.Tess_Control: return m_GL.m_TCS.ShaderDetails; + case ShaderStageType.Tess_Eval: return m_GL.m_TES.ShaderDetails; + case ShaderStageType.Geometry: return m_GL.m_GS.ShaderDetails; + case ShaderStageType.Fragment: return m_GL.m_FS.ShaderDetails; + case ShaderStageType.Compute: return m_GL.m_CS.ShaderDetails; + } + } + } + + return null; + } + + public ResourceId GetShader(ShaderStageType stage) + { + if (LogLoaded) + { + if (IsLogD3D11) + { + switch (stage) + { + case ShaderStageType.Vertex: return m_D3D11.m_VS.Shader; + case ShaderStageType.Domain: return m_D3D11.m_DS.Shader; + case ShaderStageType.Hull: return m_D3D11.m_HS.Shader; + case ShaderStageType.Geometry: return m_D3D11.m_GS.Shader; + case ShaderStageType.Pixel: return m_D3D11.m_PS.Shader; + case ShaderStageType.Compute: return m_D3D11.m_CS.Shader; + } + } + else if (IsLogGL) + { + switch (stage) + { + case ShaderStageType.Vertex: return m_GL.m_VS.Shader; + case ShaderStageType.Tess_Control: return m_GL.m_TCS.Shader; + case ShaderStageType.Tess_Eval: return m_GL.m_TES.Shader; + case ShaderStageType.Geometry: return m_GL.m_GS.Shader; + case ShaderStageType.Fragment: return m_GL.m_FS.Shader; + case ShaderStageType.Compute: return m_GL.m_CS.Shader; + } + } + } + + return ResourceId.Null; + } + + public void GetIBuffer(out ResourceId buf, out uint ByteOffset, out ResourceFormat IndexFormat) + { + if (LogLoaded) + { + if (IsLogD3D11) + { + buf = m_D3D11.m_IA.ibuffer.Buffer; + ByteOffset = m_D3D11.m_IA.ibuffer.Offset; + IndexFormat = m_D3D11.m_IA.ibuffer.Format; + + return; + } + else if (IsLogGL) + { + buf = m_GL.m_VtxIn.ibuffer.Buffer; + ByteOffset = m_GL.m_VtxIn.ibuffer.Offset; + IndexFormat = m_GL.m_VtxIn.ibuffer.Format; + + return; + } + } + + buf = ResourceId.Null; + ByteOffset = 0; + IndexFormat = new ResourceFormat(FormatComponentType.UInt, 1, 2); + } + + public struct VBuffer + { + public ResourceId Buffer; + public uint ByteOffset; + public uint ByteStride; + }; + + public VBuffer[] GetVBuffers() + { + if (LogLoaded) + { + if (IsLogD3D11) + { + VBuffer[] ret = new VBuffer[m_D3D11.m_IA.vbuffers.Length]; + for (int i = 0; i < m_D3D11.m_IA.vbuffers.Length; i++) + { + ret[i].Buffer = m_D3D11.m_IA.vbuffers[i].Buffer; + ret[i].ByteOffset = m_D3D11.m_IA.vbuffers[i].Offset; + ret[i].ByteStride = m_D3D11.m_IA.vbuffers[i].Stride; + } + + return ret; + } + else if (IsLogGL) + { + VBuffer[] ret = new VBuffer[m_GL.m_VtxIn.vbuffers.Length]; + for (int i = 0; i < m_GL.m_VtxIn.vbuffers.Length; i++) + { + ret[i].Buffer = m_GL.m_VtxIn.vbuffers[i].Buffer; + ret[i].ByteOffset = m_GL.m_VtxIn.vbuffers[i].Offset; + ret[i].ByteStride = m_GL.m_VtxIn.vbuffers[i].Stride; + } + + return ret; + } + } + + return null; + } + + public struct VertexInputAttribute + { + public string Name; + public int VertexBuffer; + public uint RelativeByteOffset; + public bool PerInstance; + public int InstanceRate; + public ResourceFormat Format; + }; + + public VertexInputAttribute[] GetVertexInputs() + { + if (LogLoaded) + { + if (IsLogD3D11) + { + uint[] byteOffs = new uint[128]; + for (int i = 0; i < 128; i++) + byteOffs[i] = 0; + + var layouts = m_D3D11.m_IA.layouts; + + VertexInputAttribute[] ret = new VertexInputAttribute[layouts.Length]; + for (int i = 0; i < layouts.Length; i++) + { + bool needsSemanticIdx = false; + for (int j = 0; j < layouts.Length; j++) + { + if (i != j && layouts[i].SemanticName == layouts[j].SemanticName) + { + needsSemanticIdx = true; + break; + } + } + + uint offs = layouts[i].ByteOffset; + if (offs == uint.MaxValue) // APPEND_ALIGNED + offs = byteOffs[layouts[i].InputSlot]; + else + byteOffs[layouts[i].InputSlot] = offs = layouts[i].ByteOffset; + + byteOffs[layouts[i].InputSlot] += layouts[i].Format.compByteWidth * layouts[i].Format.compCount; + + ret[i].Name = layouts[i].SemanticName + (needsSemanticIdx ? layouts[i].SemanticIndex.ToString() : ""); + ret[i].VertexBuffer = (int)layouts[i].InputSlot; + ret[i].RelativeByteOffset = offs; + ret[i].PerInstance = layouts[i].PerInstance; + ret[i].InstanceRate = (int)layouts[i].InstanceDataStepRate; + ret[i].Format = layouts[i].Format; + } + + return ret; + } + else if (IsLogGL) + { + var attrs = m_GL.m_VtxIn.attributes; + + int num = 0; + for (int i = 0; i < attrs.Length; i++) + { + if (attrs[i].Enabled) + num++; + } + + int a = 0; + VertexInputAttribute[] ret = new VertexInputAttribute[num]; + for (int i = 0; i < attrs.Length; i++) + { + if (!attrs[i].Enabled) continue; + + ret[a].Name = String.Format("attr{0}", i); + ret[a].VertexBuffer = (int)attrs[i].BufferSlot; + ret[a].RelativeByteOffset = attrs[i].RelativeOffset; + ret[a].PerInstance = m_GL.m_VtxIn.vbuffers[attrs[i].BufferSlot].PerInstance; + ret[a].InstanceRate = (int)m_GL.m_VtxIn.vbuffers[attrs[i].BufferSlot].Divisor; + ret[a].Format = attrs[i].Format; + + a++; + } + + return ret; + } + } + + return null; + } + + public void GetConstantBuffer(ShaderStageType stage, uint BindPoint, out ResourceId buf, out uint ByteOffset) + { + if (LogLoaded) + { + if (IsLogD3D11) + { + D3D11PipelineState.ShaderStage s = null; + + switch (stage) + { + case ShaderStageType.Vertex: s = m_D3D11.m_VS; break; + case ShaderStageType.Domain: s = m_D3D11.m_DS; break; + case ShaderStageType.Hull: s = m_D3D11.m_HS; break; + case ShaderStageType.Geometry: s = m_D3D11.m_GS; break; + case ShaderStageType.Pixel: s = m_D3D11.m_PS; break; + case ShaderStageType.Compute: s = m_D3D11.m_CS; break; + } + + buf = s.ConstantBuffers[BindPoint].Buffer; + ByteOffset = s.ConstantBuffers[BindPoint].VecOffset * 4 * sizeof(float); + + return; + } + else if (IsLogGL) + { + buf = ResourceId.Null; + ByteOffset = 0; + + return; + } + } + + buf = ResourceId.Null; + ByteOffset = 0; + } + + public ResourceId[] GetResources(ShaderStageType stage) + { + if (LogLoaded) + { + if (IsLogD3D11) + { + D3D11PipelineState.ShaderStage s = null; + + switch (stage) + { + case ShaderStageType.Vertex: s = m_D3D11.m_VS; break; + case ShaderStageType.Domain: s = m_D3D11.m_DS; break; + case ShaderStageType.Hull: s = m_D3D11.m_HS; break; + case ShaderStageType.Geometry: s = m_D3D11.m_GS; break; + case ShaderStageType.Pixel: s = m_D3D11.m_PS; break; + case ShaderStageType.Compute: s = m_D3D11.m_CS; break; + } + + ResourceId[] ret = new ResourceId[s.SRVs.Length]; + for (int i = 0; i < s.SRVs.Length; i++) + ret[i] = s.SRVs[i].Resource; + + return ret; + } + else if (IsLogGL) + { + ResourceId[] ret = new ResourceId[m_GL.Textures.Length]; + for (int i = 0; i < m_GL.Textures.Length; i++) + ret[i] = m_GL.Textures[i].Resource; + + return ret; + } + } + + return null; + } + + public ResourceId[] GetOutputTargets() + { + if (LogLoaded) + { + if (IsLogD3D11) + { + ResourceId[] ret = new ResourceId[m_D3D11.m_OM.RenderTargets.Length]; + for (int i = 0; i < m_D3D11.m_OM.RenderTargets.Length; i++) + { + ret[i] = m_D3D11.m_OM.RenderTargets[i].Resource; + if (ret[i] == ResourceId.Null && i > m_D3D11.m_OM.UAVStartSlot) + ret[i] = m_D3D11.m_OM.UAVs[i - m_D3D11.m_OM.UAVStartSlot].Resource; + } + + return ret; + } + else if (IsLogGL) + { + return m_GL.m_FB.Color; + } + } + + return null; + } + + public ResourceId OutputDepth + { + get + { + if (LogLoaded) + { + if (IsLogD3D11) + return m_D3D11.m_OM.DepthTarget.Resource; + + if (IsLogGL) + return m_GL.m_FB.Depth; + } + + return ResourceId.Null; + } + } + + public ResourceId OutputStencil + { + get + { + if (LogLoaded) + { + if (IsLogD3D11) + return m_D3D11.m_OM.DepthTarget.Resource; + + if (IsLogGL) + return m_GL.m_FB.Stencil; + } + + return ResourceId.Null; + } + } + + // Still to add: + // [ShaderViewer] * {FetchTexture,FetchBuffer} GetFetchBufferOrFetchTexture(ShaderResource) + } +} diff --git a/renderdocui/Code/Core.cs b/renderdocui/Code/Core.cs new file mode 100644 index 0000000000..b1aa92f66d --- /dev/null +++ b/renderdocui/Code/Core.cs @@ -0,0 +1,806 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Diagnostics; +using System.Linq; +using System.IO; +using System.Text; +using System.Windows.Forms; +using System.Threading; +using renderdocui.Windows; +using renderdocui.Windows.Dialogs; +using renderdocui.Windows.PipelineState; +using renderdoc; + +namespace renderdocui.Code +{ + // Single core class. Between this and the RenderManager these classes govern the interaction + // between the UI and the actual implementation. + // + // This class primarily controls things that need to be propogated globally, it keeps a list of + // ILogViewerForms which are windows that would like to be notified of changes to the current event, + // when a log is opened or closed, etc. It also contains data that potentially every window will + // want access to - like a list of all buffers in the log and their properties, etc. + public class Core + { + #region Privates + + private RenderManager m_Renderer = new RenderManager(); + + private PersistantConfig m_Config = null; + + private bool m_LogLoaded = false; + + private string m_LogFile = ""; + + private UInt32 m_FrameID = 0; + private UInt32 m_EventID = 0; + private UInt32 m_DeferredEvent = 0; + + private APIProperties m_APIProperties = null; + + private FetchFrameInfo[] m_FrameInfo = null; + private FetchDrawcall[][] m_DrawCalls = null; + private FetchBuffer[] m_Buffers = null; + private FetchTexture[] m_Textures = null; + + private D3D11PipelineState m_D3D11PipelineState = null; + private GLPipelineState m_GLPipelineState = null; + private CommonPipelineState m_PipelineState = new CommonPipelineState(); + + private List m_LogViewers = new List(); + private List m_ProgressListeners = new List(); + + private MainWindow m_MainWindow = null; + private EventBrowser m_EventBrowser = null; + private APIInspector m_APIInspector = null; + private DebugMessages m_DebugMessages = null; + private TimelineBar m_TimelineBar = null; + private TextureViewer m_TextureViewer = null; + private PipelineStateViewer m_PipelineStateViewer = null; + + #endregion + + #region Properties + + public static string ConfigDirectory + { + get + { + string appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + return Path.Combine(appdata, "renderdoc"); + } + } + + public static string ConfigFilename + { + get + { + return Path.Combine(ConfigDirectory, "UI.config"); + } + } + + public PersistantConfig Config { get { return m_Config; } } + public bool LogLoaded { get { return m_LogLoaded; } } + public bool LogLoading { get { return m_LogLoadingInProgress; } } + public string LogFileName { get { return m_LogFile; } set { if (LogLoaded) m_LogFile = value; } } + + public FetchFrameInfo[] FrameInfo { get { while (m_FrameInfo == null); return m_FrameInfo; } } + + public APIProperties APIProps { get { return m_APIProperties; } } + + // typically 0 right now as we haven't supported multiple frames in logs for a loooong time. + public UInt32 CurFrame { get { return m_FrameID; } } + public UInt32 CurEvent { get { return m_DeferredEvent > 0 ? m_DeferredEvent : m_EventID; } } + + public FetchDrawcall[] CurDrawcalls { get { return GetDrawcalls(CurFrame); } } + + public FetchDrawcall CurDrawcall { get { return GetDrawcall(CurFrame, CurEvent); } } + + public FetchTexture[] CurTextures { get { return m_Textures; } } + public FetchBuffer[] CurBuffers { get { return m_Buffers; } } + + // the RenderManager can be used when you want to perform an operation, it will let you Invoke or + // BeginInvoke onto the thread that's used to access the renderdoc project. + public RenderManager Renderer { get { return m_Renderer; } } + + public Form AppWindow { get { return m_MainWindow; } } + + #endregion + + #region Pipeline State + + // direct access (note that only one of these will be valid for a log, check APIProps.pipelineType) + public D3D11PipelineState CurD3D11PipelineState { get { return m_D3D11PipelineState; } } + public GLPipelineState CurGLPipelineState { get { return m_GLPipelineState; } } + public CommonPipelineState CurPipelineState { get { return m_PipelineState; } } + + #endregion + + #region Init and Shutdown + + public Core(string paramFilename, bool temp, PersistantConfig config) + { + if (!Directory.Exists(ConfigDirectory)) + Directory.CreateDirectory(ConfigDirectory); + + m_Config = config; + m_MainWindow = new MainWindow(this, paramFilename, temp); + } + + public void Shutdown() + { + if (m_Renderer != null) + m_Renderer.CloseThreadSync(); + } + + #endregion + + #region Log Loading & Capture + + private bool m_LogLoadingInProgress = false; + + private bool LogLoadCallback() + { + return !m_LogLoadingInProgress; + } + + // used to determine if two drawcalls can be considered in the same 'pass', + // ie. writing to similar targets, same type of call, etc. + // + // When a log has no markers, this is used to group up drawcalls into fake markers + private bool PassEquivalent(FetchDrawcall a, FetchDrawcall b) + { + // executing command lists can have children + if(a.children.Length > 0 || b.children.Length > 0) + return false; + + // don't group draws and compute executes + if ((a.flags & DrawcallFlags.Dispatch) != (b.flags & DrawcallFlags.Dispatch)) + return false; + + // don't group things run on different multithreaded contexts + if(a.context != b.context) + return false; + + // don't group things with different depth outputs + if (a.depthOut != b.depthOut) + return false; + + int numAOuts = 0, numBOuts = 0; + for (int i = 0; i < 8; i++) + { + if (a.outputs[i] != ResourceId.Null) numAOuts++; + if (b.outputs[i] != ResourceId.Null) numBOuts++; + } + + int numSame = 0; + + if (a.depthOut != ResourceId.Null) + { + numAOuts++; + numBOuts++; + numSame++; + } + + for (int i = 0; i < 8; i++) + { + if (a.outputs[i] != ResourceId.Null) + { + for (int j = 0; j < 8; j++) + { + if (a.outputs[i] == b.outputs[j]) + { + numSame++; + break; + } + } + } + else if (b.outputs[i] != ResourceId.Null) + { + for (int j = 0; j < 8; j++) + { + if (a.outputs[j] == b.outputs[i]) + { + numSame++; + break; + } + } + } + } + + // use a kind of heuristic to group together passes where the outputs are similar enough. + // could be useful for example if you're rendering to a gbuffer and sometimes you render + // without one target, but the draws are still batched up. + if (numSame > Math.Max(numAOuts, numBOuts) / 2 && Math.Max(numAOuts, numBOuts) > 1) + return true; + + if (numSame == Math.Max(numAOuts, numBOuts)) + return true; + + return false; + } + + private bool ContainsMarker(FetchDrawcall[] draws) + { + bool ret = false; + + foreach (var d in draws) + { + ret |= (d.flags & (DrawcallFlags.PushMarker | DrawcallFlags.SetMarker)) > 0 && (d.flags & DrawcallFlags.CmdList) == 0; + ret |= ContainsMarker(d.children); + } + + return ret; + } + + // if a log doesn't contain any markers specified at all by the user, then we can + // fake some up by determining batches of draws that are similar and giving them a + // pass number + private FetchDrawcall[] FakeProfileMarkers(int frameID, FetchDrawcall[] draws) + { + if (ContainsMarker(draws)) + return draws; + + var ret = new List(); + + int depthpassID = 1; + int computepassID = 1; + int passID = 1; + + int start = 0; + + int counter = 1; + + for (int i = 1; i < draws.Length; i++) + { + if (PassEquivalent(draws[i], draws[start]) && i+1 < draws.Length) + continue; + + int end = i - 1; + + if (i == draws.Length - 1) + end = i; + + if (end - start < 2 || + draws[i].children.Length > 0 || draws[start].children.Length > 0 || + draws[i].context != m_FrameInfo[frameID].immContextId || + draws[start].context != m_FrameInfo[frameID].immContextId) + { + for (int j = start; j <= end; j++) + { + ret.Add(draws[j]); + counter++; + } + + start = i; + continue; + } + + int minOutCount = 100; + int maxOutCount = 0; + + for (int j = start; j <= end; j++) + { + int outCount = 0; + foreach (var o in draws[j].outputs) + if (o != ResourceId.Null) + outCount++; + minOutCount = Math.Min(minOutCount, outCount); + maxOutCount = Math.Max(maxOutCount, outCount); + } + + FetchDrawcall mark = new FetchDrawcall(); + + mark.eventID = draws[end].eventID; + mark.drawcallID = draws[end].drawcallID; + + mark.context = draws[end].context; + mark.flags = DrawcallFlags.PushMarker; + mark.outputs = draws[end].outputs; + mark.depthOut = draws[end].depthOut; + + mark.name = "Guessed Pass"; + + if((draws[end].flags & DrawcallFlags.Dispatch) != 0) + mark.name = String.Format("Compute Pass #{0}", computepassID++); + else if (maxOutCount == 0) + mark.name = String.Format("Depth-only Pass #{0}", depthpassID++); + else if(minOutCount == maxOutCount) + mark.name = String.Format("Colour Pass #{0} ({1} Targets{2})", passID++, minOutCount, draws[end].depthOut == ResourceId.Null ? "" : " + Depth"); + else + mark.name = String.Format("Colour Pass #{0} ({1}-{2} Targets{3})", passID++, minOutCount, maxOutCount, draws[end].depthOut == ResourceId.Null ? "" : " + Depth"); + + mark.children = new FetchDrawcall[end - start + 1]; + + for (int j = start; j <= end; j++) + { + mark.children[j - start] = draws[j]; + draws[j].parent = mark; + } + + ret.Add(mark); + + start = i; + counter++; + } + + return ret.ToArray(); + } + + // loading a local log, no remote replay + public void LoadLogfile(string logFile, bool temporary) + { + LoadLogfile(-1, "", logFile, temporary); + } + + // when loading a log while replaying remotely, provide the proxy renderer that will be used + // as well as the hostname to replay on. + public void LoadLogfile(int proxyRenderer, string replayHost, string logFile, bool temporary) + { + m_LogFile = logFile; + + m_LogLoadingInProgress = true; + + if(!temporary) + m_Config.AddRecentFile(m_Config.RecentLogFiles, logFile, 10); + + if (File.Exists(Core.ConfigFilename)) + m_Config.Serialize(Core.ConfigFilename); + + float postloadProgress = 0.0f; + + bool progressThread = true; + + // start a modal dialog to prevent the user interacting with the form while the log is loading. + // We'll close it down when log loading finishes (whether it succeeds or fails) + ModalPopup modal = new ModalPopup(LogLoadCallback, true); + + Thread modalThread = new Thread(new ThreadStart(() => + { + modal.SetModalText(string.Format("Loading Log {0}.", m_LogFile)); + + AppWindow.BeginInvoke(new Action(() => + { + modal.ShowDialog(AppWindow); + })); + })); + modalThread.Start(); + + // this thread continually ticks and notifies any threads of the progress, through a float + // that is updated by the main loading code + Thread thread = new Thread(new ThreadStart(() => + { + modal.LogfileProgressBegin(); + + foreach (var p in m_ProgressListeners) + p.LogfileProgressBegin(); + + while (progressThread) + { + Thread.Sleep(2); + + float progress = 0.5f * m_Renderer.LoadProgress + 0.49f * postloadProgress + 0.01f; + + modal.LogfileProgress(progress); + + foreach (var p in m_ProgressListeners) + p.LogfileProgress(progress); + } + })); + thread.Start(); + + // this function call will block until the log is either loaded, or there's some failure + m_Renderer.Init(proxyRenderer, replayHost, logFile); + + // if the renderer isn't running, we hit a failure case so display an error message + if (!m_Renderer.Running) + { + string errmsg = "Unknown error message"; + if (m_Renderer.InitException.Data.Contains("status")) + errmsg = ((ReplayCreateStatus)m_Renderer.InitException.Data["status"]).Str(); + + if(proxyRenderer >= 0) + MessageBox.Show(String.Format("{0}\nFailed to transfer and replay on remote host {1}: {2}.\n\n" + + "Check diagnostic log in Help menu for more details.", logFile, replayHost, errmsg), + "Error opening log", MessageBoxButtons.OK, MessageBoxIcon.Error); + else + MessageBox.Show(String.Format("{0}\nFailed to open logfile for replay: {1}.\n\n" + + "Check diagnostic log in Help menu for more details.", logFile, errmsg), + "Error opening log", MessageBoxButtons.OK, MessageBoxIcon.Error); + + progressThread = false; + thread.Join(); + + m_LogLoadingInProgress = false; + + modal.LogfileProgress(-1.0f); + + foreach (var p in m_ProgressListeners) + p.LogfileProgress(-1.0f); + + return; + } + + m_FrameID = 0; + m_EventID = 0; + + m_FrameInfo = null; + m_APIProperties = null; + + // fetch initial data like drawcalls, textures and buffers + m_Renderer.Invoke((ReplayRenderer r) => + { + m_FrameInfo = r.GetFrameInfo(); + + m_APIProperties = r.GetAPIProperties(); + + postloadProgress = 0.2f; + + m_DrawCalls = new FetchDrawcall[m_FrameInfo.Length][]; + + postloadProgress = 0.4f; + + for (int i = 0; i < m_FrameInfo.Length; i++) + m_DrawCalls[i] = FakeProfileMarkers(i, r.GetDrawcalls((UInt32)i, false)); + + m_TimedDrawcalls = false; + + postloadProgress = 0.7f; + + m_Buffers = r.GetBuffers(); + + postloadProgress = 0.8f; + var texs = new List(r.GetTextures()); + m_Textures = texs.OrderBy(o => o.name).ToArray(); + + postloadProgress = 0.9f; + + m_D3D11PipelineState = r.GetD3D11PipelineState(); + m_GLPipelineState = r.GetGLPipelineState(); + m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_GLPipelineState); + + postloadProgress = 1.0f; + }); + + Thread.Sleep(20); + + m_LogLoaded = true; + progressThread = false; + + // notify all the registers log viewers that a log has been loaded + foreach (var logviewer in m_LogViewers) + { + Control c = (Control)logviewer; + if (c.InvokeRequired) + { + if (!c.IsDisposed) + { + c.Invoke(new Action(() => { + try + { + logviewer.OnLogfileLoaded(); + } + catch (Exception ex) + { + throw new AccessViolationException("Rethrown from Invoke:\n" + ex.ToString()); + } + })); + } + } + else if (!c.IsDisposed) + logviewer.OnLogfileLoaded(); + } + + m_LogLoadingInProgress = false; + + modal.LogfileProgress(1.0f); + + foreach (var p in m_ProgressListeners) + p.LogfileProgress(1.0f); + } + + public void CloseLogfile() + { + if (!m_LogLoaded) return; + + m_LogFile = ""; + + m_Renderer.CloseThreadSync(); + m_Renderer = new RenderManager(); + + m_APIProperties = null; + m_FrameInfo = null; + m_DrawCalls = null; + m_Buffers = null; + m_Textures = null; + + m_D3D11PipelineState = null; + m_GLPipelineState = null; + m_PipelineState.SetStates(null, null, null); + + m_LogLoaded = false; + + foreach (var logviewer in m_LogViewers) + { + Control c = (Control)logviewer; + if (c.InvokeRequired) + c.Invoke(new Action(() => logviewer.OnLogfileClosed())); + else + logviewer.OnLogfileClosed(); + } + } + + public String TempLogFilename(String appname) + { + string folder = Config.CaptureSavePath; + try + { + if (folder == "" || !Directory.Exists(folder)) + folder = Path.GetTempPath(); + } + catch (ArgumentException) + { + // invalid path or similar + folder = Path.GetTempPath(); + } + return Path.Combine(folder, appname + "_" + DateTime.Now.ToString(@"yyyy.MM.dd_HH.mm.ss") + ".rdc"); + } + + #endregion + + #region Log drawcalls + + private bool m_TimedDrawcalls = false; + public void TimeDrawcalls(ReplayRenderer r) + { + if (m_TimedDrawcalls) return; + m_TimedDrawcalls = true; + + for (int i = 0; i < m_FrameInfo.Length; i++) + m_DrawCalls[i] = FakeProfileMarkers(i, r.GetDrawcalls((UInt32)i, true)); + } + + public FetchDrawcall[] GetDrawcalls(UInt32 frameIdx) + { + if (m_DrawCalls == null) return null; + return m_DrawCalls[frameIdx]; + } + + private FetchDrawcall GetDrawcall(FetchDrawcall[] draws, UInt32 eventID) + { + foreach (var d in draws) + { + if (d.children != null && d.children.Length > 0) + { + var draw = GetDrawcall(d.children, eventID); + if (draw != null) return draw; + } + + if (d.eventID == eventID) + return d; + } + + return null; + } + + public FetchDrawcall GetDrawcall(UInt32 frameID, UInt32 eventID) + { + if (frameID < 0 || m_DrawCalls == null || frameID >= m_DrawCalls.Length) + return null; + + return GetDrawcall(m_DrawCalls[frameID], eventID); + } + + #endregion + + #region Viewers + + // Some viewers we only allow one to exist at once, so we keep the instance here. + + public EventBrowser GetEventBrowser() + { + if (m_EventBrowser == null || m_EventBrowser.IsDisposed) + { + m_EventBrowser = new EventBrowser(this); + AddLogViewer(m_EventBrowser); + } + + return m_EventBrowser; + } + + public TextureViewer GetTextureViewer() + { + if (m_TextureViewer == null || m_TextureViewer.IsDisposed) + { + m_TextureViewer = new TextureViewer(this); + AddLogViewer(m_TextureViewer); + } + + return m_TextureViewer; + } + + public PipelineStateViewer GetPipelineStateViewer() + { + if (m_PipelineStateViewer == null || m_PipelineStateViewer.IsDisposed) + { + m_PipelineStateViewer = new PipelineStateViewer(this); + AddLogViewer(m_PipelineStateViewer); + } + + return m_PipelineStateViewer; + } + + public APIInspector GetAPIInspector() + { + if (m_APIInspector == null || m_APIInspector.IsDisposed) + { + m_APIInspector = new APIInspector(this); + AddLogViewer(m_APIInspector); + } + + return m_APIInspector; + } + + public DebugMessages GetDebugMessages() + { + if (m_DebugMessages == null || m_DebugMessages.IsDisposed) + { + m_DebugMessages = new DebugMessages(this); + AddLogViewer(m_DebugMessages); + } + + return m_DebugMessages; + } + + public TimelineBar TimelineBar + { + get + { + if (m_TimelineBar == null || m_TimelineBar.IsDisposed) + return null; + + return m_TimelineBar; + } + } + + private CaptureDialog m_CaptureDialog = null; + public CaptureDialog CaptureDialog + { + get + { + return m_CaptureDialog == null || m_CaptureDialog.IsDisposed ? null : m_CaptureDialog; + } + set + { + if (m_CaptureDialog == null || m_CaptureDialog.IsDisposed) + m_CaptureDialog = value; + } + } + + public TimelineBar GetTimelineBar() + { + if (m_TimelineBar == null || m_TimelineBar.IsDisposed) + { + m_TimelineBar = new TimelineBar(this); + AddLogViewer(m_TimelineBar); + } + + return m_TimelineBar; + } + + public void AddLogProgressListener(ILogLoadProgressListener p) + { + m_ProgressListeners.Add(p); + } + + public void AddLogViewer(ILogViewerForm f) + { + m_LogViewers.Add(f); + + if (LogLoaded) + { + f.OnLogfileLoaded(); + f.OnEventSelected(CurFrame, CurEvent); + } + } + + public void RemoveLogViewer(ILogViewerForm f) + { + m_LogViewers.Remove(f); + } + + #endregion + + #region Log Browsing + + // setting a context filter allows replaying of deferred events. You can set the deferred + // events to replay in a context, after replaying up to a given event on the main thread + public void SetContextFilter(ILogViewerForm exclude, UInt32 frameID, UInt32 eventID, + ResourceId ctx, UInt32 firstDeferred, UInt32 lastDeferred) + { + m_FrameID = frameID; + m_EventID = eventID; + + m_DeferredEvent = lastDeferred; + + m_Renderer.Invoke((ReplayRenderer r) => { r.SetContextFilter(ctx, firstDeferred, lastDeferred); }); + m_Renderer.Invoke((ReplayRenderer r) => { + r.SetFrameEvent(m_FrameID, m_EventID); + m_D3D11PipelineState = r.GetD3D11PipelineState(); + m_GLPipelineState = r.GetGLPipelineState(); + m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_GLPipelineState); + }); + + foreach (var logviewer in m_LogViewers) + { + if (logviewer == exclude) + continue; + + Control c = (Control)logviewer; + if (c.InvokeRequired) + c.BeginInvoke(new Action(() => logviewer.OnEventSelected(frameID, eventID))); + else + logviewer.OnEventSelected(frameID, eventID); + } + } + + public void SetEventID(ILogViewerForm exclude, UInt32 frameID, UInt32 eventID) + { + m_FrameID = frameID; + m_EventID = eventID; + + m_DeferredEvent = 0; + + m_Renderer.Invoke((ReplayRenderer r) => { r.SetContextFilter(ResourceId.Null, 0, 0); }); + m_Renderer.Invoke((ReplayRenderer r) => + { + r.SetFrameEvent(m_FrameID, m_EventID); + m_D3D11PipelineState = r.GetD3D11PipelineState(); + m_GLPipelineState = r.GetGLPipelineState(); + m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_GLPipelineState); + }); + + foreach (var logviewer in m_LogViewers) + { + if(logviewer == exclude) + continue; + + Control c = (Control)logviewer; + if (c.InvokeRequired) + c.BeginInvoke(new Action(() => logviewer.OnEventSelected(frameID, eventID))); + else + logviewer.OnEventSelected(frameID, eventID); + } + } + + #endregion + } +} diff --git a/renderdocui/Code/Helpers.cs b/renderdocui/Code/Helpers.cs new file mode 100644 index 0000000000..5ef5abff7f --- /dev/null +++ b/renderdocui/Code/Helpers.cs @@ -0,0 +1,182 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; +using Microsoft.Win32; +using System.Security.Principal; +using System.Diagnostics; +using System.Xml.Serialization; + +namespace renderdocui.Code +{ + static class Helpers + { + // simple helpers to wrap a given control in a DockContent, so it can be docked into a panel. + static public DockContent WrapDockContent(DockPanel panel, Control c) + { + return WrapDockContent(panel, c, c.Text); + } + + static public DockContent WrapDockContent(DockPanel panel, Control c, string Title) + { + DockContent w = new DockContent(); + c.Dock = DockStyle.Fill; + w.Controls.Add(c); + w.DockAreas &= ~DockAreas.Float; + w.Text = Title; + w.DockPanel = panel; + + w.DockHandler.GetPersistStringCallback = new GetPersistStringCallback(() => { return c.Name; }); + + Control win = panel as Control; + + while (win != null && !(win is Form)) + win = win.Parent; + + if (win != null && win is Form) + w.Icon = (win as Form).Icon; + + return w; + } + + public static T Clamp(this T val, T min, T max) where T : IComparable + { + if (val.CompareTo(min) < 0) return min; + else if (val.CompareTo(max) > 0) return max; + else return val; + } + + public static bool IsElevated + { + get + { + return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); + } + } + + public static void RefreshAssociations() + { + Win32PInvoke.SHChangeNotify(Win32PInvoke.HChangeNotifyEventID.SHCNE_ASSOCCHANGED, + Win32PInvoke.HChangeNotifyFlags.SHCNF_IDLIST | + Win32PInvoke.HChangeNotifyFlags.SHCNF_FLUSHNOWAIT | + Win32PInvoke.HChangeNotifyFlags.SHCNF_NOTIFYRECURSIVE, + IntPtr.Zero, IntPtr.Zero); + } + + public static void InstallRDCAssociation() + { + if (!IsElevated) + { + var process = new Process(); + process.StartInfo = new ProcessStartInfo(Application.ExecutablePath, "--registerRDCext"); + process.StartInfo.Verb = "runas"; + try + { + process.Start(); + } + catch (Exception) + { + // fire and forget - most likely caused by user saying no to UAC prompt + } + return; + } + + var path = Path.GetFullPath(Application.ExecutablePath); + + RegistryKey key = Registry.ClassesRoot.CreateSubKey("RenderDoc.RDCCapture.1"); + key.SetValue("", "RenderDoc Capture Log (.rdc)"); + key.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command").SetValue("", "\"" + path + "\" \"%1\""); + key.CreateSubKey("DefaultIcon").SetValue("", path); + key.CreateSubKey("CLSID").SetValue("", "{5D6BF029-A6BA-417A-8523-120492B1DCE3}"); + key.CreateSubKey("ShellEx").CreateSubKey("{e357fccd-a995-4576-b01f-234630154e96}").SetValue("", "{5D6BF029-A6BA-417A-8523-120492B1DCE3}"); + key.Close(); + + key = Registry.ClassesRoot.CreateSubKey(".rdc"); + key.SetValue("", "RenderDoc.RDCCapture.1"); + key.Close(); + + var dllpath = Path.Combine(Path.GetDirectoryName(path), "renderdoc.dll"); + + key = Registry.ClassesRoot.OpenSubKey("CLSID", true).CreateSubKey("{5D6BF029-A6BA-417A-8523-120492B1DCE3}"); + key.SetValue("", "RenderDoc Thumbnail Handler"); + key.CreateSubKey("InprocServer32").SetValue("", dllpath); + key.Close(); + + RefreshAssociations(); + } + + public static void InstallCAPAssociation() + { + if (!IsElevated) + { + var process = new Process(); + process.StartInfo = new ProcessStartInfo(Application.ExecutablePath, "--registerCAPext"); + process.StartInfo.Verb = "runas"; + try + { + process.Start(); + } + catch (Exception) + { + // fire and forget - most likely caused by user saying no to UAC prompt + } + return; + } + + var path = Path.GetFullPath(Application.ExecutablePath); + + RegistryKey key = Registry.ClassesRoot.CreateSubKey("RenderDoc.RDCSettings.1"); + key.SetValue("", "RenderDoc Capture Settings (.cap)"); + key.CreateSubKey("DefaultIcon").SetValue("", path); + key.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command").SetValue("", "\"" + path + "\" \"%1\""); + key.Close(); + + key = Registry.ClassesRoot.CreateSubKey(".cap"); + key.SetValue("", "RenderDoc.RDCSettings.1"); + key.Close(); + + RefreshAssociations(); + } + } + + // KeyValuePair isn't serializable, so we make our own that is + [Serializable] + public struct SerializableKeyValuePair + { + public SerializableKeyValuePair(K k, V v) : this() { Key = k; Value = v; } + + public K Key + { get; set; } + + public V Value + { get; set; } + } +} diff --git a/renderdocui/Code/LogViewerForm.cs b/renderdocui/Code/LogViewerForm.cs new file mode 100644 index 0000000000..ad6016a828 --- /dev/null +++ b/renderdocui/Code/LogViewerForm.cs @@ -0,0 +1,45 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace renderdocui.Code +{ + public interface ILogViewerForm + { + void OnLogfileLoaded(); + void OnLogfileClosed(); + void OnEventSelected(UInt32 frameID, UInt32 eventID); + } + + public interface ILogLoadProgressListener + { + void LogfileProgressBegin(); + void LogfileProgress(float progress); + } +} diff --git a/renderdocui/Code/PersistantConfig.cs b/renderdocui/Code/PersistantConfig.cs new file mode 100644 index 0000000000..cca8be6cf1 --- /dev/null +++ b/renderdocui/Code/PersistantConfig.cs @@ -0,0 +1,156 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using renderdoc; + +namespace renderdocui.Code +{ + [Serializable] + public class PersistantConfig + { + public string LastLogPath = ""; + public List RecentLogFiles = new List(); + public string LastCapturePath = ""; + public List RecentCaptureSettings = new List(); + public int CallstackLevelSkip = 0; + + public string CaptureSavePath = ""; + + public bool TextureViewer_ResetRange = false; + public bool TextureViewer_DisableThumbnails = false; + public bool ShaderViewer_FriendlyNaming = true; + + public List RecentHosts = new List(); + + public int LocalProxy = 0; + + [XmlIgnore] // not directly serializable + public Dictionary ReplayHosts = new Dictionary(); + public List> ReplayHostKeyValues = new List>(); + + public List> PreviouslyUsedHosts = new List>(); + + public enum TimeUnit + { + Seconds = 0, + Milliseconds, + Microseconds, + Nanoseconds, + }; + + public static String UnitPrefix(TimeUnit t) + { + if (t == TimeUnit.Seconds) + return "s"; + else if (t == TimeUnit.Milliseconds) + return "ms"; + else if (t == TimeUnit.Microseconds) + return "µs"; + else if (t == TimeUnit.Nanoseconds) + return "ns"; + + return "s"; + } + + public TimeUnit EventBrowser_TimeUnit = TimeUnit.Microseconds; + public bool EventBrowser_HideEmpty = false; + + public int Formatter_MinFigures = 2; + public int Formatter_MaxFigures = 5; + public int Formatter_NegExp = 5; + public int Formatter_PosExp = 7; + + public bool CheckUpdate_AllowChecks = true; + public bool CheckUpdate_UpdateAvailable = false; + public DateTime CheckUpdate_LastUpdate = new DateTime(2012, 06, 27); + + public void SetupFormatter() + { + Formatter.MinFigures = Formatter_MinFigures; + Formatter.MaxFigures = Formatter_MaxFigures; + Formatter.ExponentialNegCutoff = Formatter_NegExp; + Formatter.ExponentialPosCutoff = Formatter_PosExp; + } + + public void AddRecentFile(List recentList, string file, int maxItems) + { + if (!recentList.Contains(Path.GetFullPath(file))) + { + recentList.Add(Path.GetFullPath(file)); + if (recentList.Count >= maxItems) + recentList.RemoveAt(0); + } + else + { + recentList.Remove(Path.GetFullPath(file)); + recentList.Add(Path.GetFullPath(file)); + } + } + + public PersistantConfig() + { + CallstackLevelSkip = 0; + RecentLogFiles.Clear(); + RecentCaptureSettings.Clear(); + } + + public void Serialize(string file) + { + ReplayHostKeyValues.Clear(); + foreach(var kv in ReplayHosts) + ReplayHostKeyValues.Add(new SerializableKeyValuePair(kv.Key, kv.Value)); + + XmlSerializer xs = new XmlSerializer(this.GetType()); + StreamWriter writer = File.CreateText(file); + xs.Serialize(writer, this); + writer.Flush(); + writer.Close(); + } + + public static PersistantConfig Deserialize(string file) + { + XmlSerializer xs = new XmlSerializer(typeof(PersistantConfig)); + StreamReader reader = File.OpenText(file); + PersistantConfig c = (PersistantConfig)xs.Deserialize(reader); + reader.Close(); + + foreach (var kv in c.ReplayHostKeyValues) + { + if(kv.Key != null && kv.Key != "" && + kv.Value != null) + c.ReplayHosts.Add(kv.Key, kv.Value); + } + + return c; + } + } +} diff --git a/renderdocui/Code/RenderManager.cs b/renderdocui/Code/RenderManager.cs new file mode 100644 index 0000000000..a120ba7811 --- /dev/null +++ b/renderdocui/Code/RenderManager.cs @@ -0,0 +1,238 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Reflection; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using renderdoc; + +namespace renderdocui.Code +{ + public delegate void InvokeMethod(ReplayRenderer r); + + // this class owns the thread that interacts with the main library, to ensure that we don't + // have to worry elsewhere about threading access. Elsewhere in the UI you can do Invoke or + // BeginInvoke and get a ReplayRenderer reference back to access through + public class RenderManager + { + private class InvokeHandle + { + public InvokeHandle(InvokeMethod m) + { + method = m; + processed = false; + } + + public InvokeMethod method; + volatile public bool processed; + }; + + //////////////////////////////////////////// + // variables + + private AutoResetEvent m_WakeupEvent = new AutoResetEvent(false); + private Thread m_Thread; + private int m_ProxyRenderer = -1; + private string m_ReplayHost; + private string m_Logfile; + private bool m_Running; + + private List m_renderQueue; + + //////////////////////////////////////////// + // Interface + + public RenderManager() + { + Running = false; + + m_renderQueue = new List(); + } + + public void Init(int proxyRenderer, string replayHost, string logfile) + { + if(Running) + return; + + m_ProxyRenderer = proxyRenderer; + m_ReplayHost = replayHost; + m_Logfile = logfile; + + LoadProgress = 0.0f; + + InitException = null; + + m_Thread = new Thread(new ThreadStart(this.RunThread)); + m_Thread.Priority = ThreadPriority.Highest; + m_Thread.Start(); + + while (m_Thread.IsAlive && !Running) ; + } + + public bool Running + { + get { return m_Running; } + set { m_Running = value; m_WakeupEvent.Set(); } + } + + public ApplicationException InitException = null; + + public void CloseThreadSync() + { + Running = false; + + while (m_Thread != null && m_Thread.IsAlive) ; + } + + public float LoadProgress; + + public void BeginInvoke(InvokeMethod m) + { + InvokeHandle cmd = new InvokeHandle(m); + + PushInvoke(cmd); + } + + public void Invoke(InvokeMethod m) + { + InvokeHandle cmd = new InvokeHandle(m); + + PushInvoke(cmd); + + while (!cmd.processed) ; + } + + private void PushInvoke(InvokeHandle cmd) + { + if (m_Thread == null || !Running) + { + cmd.processed = true; + return; + } + + m_WakeupEvent.Set(); + + lock (m_renderQueue) + { + m_renderQueue.Add(cmd); + } + } + + //////////////////////////////////////////// + // Internals + + private void CreateReplayRenderer(ref ReplayRenderer renderer, ref RemoteRenderer remote) + { + if (m_ProxyRenderer < 0) + { + renderer = StaticExports.CreateReplayRenderer(m_Logfile, ref LoadProgress); + return; + } + + remote = StaticExports.CreateRemoteReplayConnection(m_ReplayHost); + + if(remote == null) + { + var e = new System.ApplicationException("Failed to connect to remote replay host"); + e.Data.Add("status", ReplayCreateStatus.UnknownError); + throw e; + } + + renderer = remote.CreateProxyRenderer(m_ProxyRenderer, m_Logfile, ref LoadProgress); + + if(renderer == null) + { + remote.Shutdown(); + + var e = new System.ApplicationException("Failed to connect to remote replay host"); + e.Data.Add("status", ReplayCreateStatus.UnknownError); + throw e; + } + } + + private void RunThread() + { + try + { + ReplayRenderer renderer = null; + RemoteRenderer remote = null; + CreateReplayRenderer(ref renderer, ref remote); + if(renderer != null) + { + System.Diagnostics.Debug.WriteLine("Renderer created"); + + DateTime prevTime = DateTime.Now; + + Running = true; + + while (Running) + { + DateTime curTime = DateTime.Now; + long msPassed = (curTime.Ticks - prevTime.Ticks) / TimeSpan.TicksPerMillisecond; + + List queue = new List(); + lock (m_renderQueue) + { + foreach (var cmd in m_renderQueue) + queue.Add(cmd); + + m_renderQueue.Clear(); + } + + foreach (var cmd in queue) + { + if (cmd.method != null) + cmd.method(renderer); + + cmd.processed = true; + } + + m_WakeupEvent.WaitOne(10); + } + + lock (m_renderQueue) + { + foreach (var cmd in m_renderQueue) + cmd.processed = true; + + m_renderQueue.Clear(); + } + + renderer.Shutdown(); + if (remote != null) remote.Shutdown(); + } + } + catch (ApplicationException ex) + { + InitException = ex; + } + } + } +} diff --git a/renderdocui/Code/Win32PInvoke.cs b/renderdocui/Code/Win32PInvoke.cs new file mode 100644 index 0000000000..7094b20e71 --- /dev/null +++ b/renderdocui/Code/Win32PInvoke.cs @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace renderdocui.Code +{ + class Win32PInvoke + { + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLibrary(string lpFileName); + + // for redirecting mousewheel + [DllImport("user32.dll")] + public static extern IntPtr WindowFromPoint(System.Drawing.Point pt); + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr wnd, int msg, IntPtr wp, IntPtr lp); + + // windows message from winuser.h + public enum Win32Message + { + WM_MOUSEWHEEL = 0x020A, + TCM_ADJUSTRECT = 0x1328, + }; + + [Flags] + public enum HChangeNotifyEventID + { + SHCNE_ALLEVENTS = 0x7FFFFFFF, + SHCNE_ASSOCCHANGED = 0x08000000, + SHCNE_ATTRIBUTES = 0x00000800, + SHCNE_CREATE = 0x00000002, + SHCNE_DELETE = 0x00000004, + SHCNE_DRIVEADD = 0x00000100, + SHCNE_DRIVEADDGUI = 0x00010000, + SHCNE_DRIVEREMOVED = 0x00000080, + SHCNE_EXTENDED_EVENT = 0x04000000, + SHCNE_FREESPACE = 0x00040000, + SHCNE_MEDIAINSERTED = 0x00000020, + SHCNE_MEDIAREMOVED = 0x00000040, + SHCNE_MKDIR = 0x00000008, + SHCNE_NETSHARE = 0x00000200, + SHCNE_NETUNSHARE = 0x00000400, + SHCNE_RENAMEFOLDER = 0x00020000, + SHCNE_RENAMEITEM = 0x00000001, + SHCNE_RMDIR = 0x00000010, + SHCNE_SERVERDISCONNECT = 0x00004000, + SHCNE_UPDATEDIR = 0x00001000, + SHCNE_UPDATEIMAGE = 0x00008000, + } + + [Flags] + public enum HChangeNotifyFlags + { + SHCNF_DWORD = 0x0003, + SHCNF_IDLIST = 0x0000, + SHCNF_PATHA = 0x0001, + SHCNF_PATHW = 0x0005, + SHCNF_PRINTERA = 0x0002, + SHCNF_PRINTERW = 0x0006, + SHCNF_FLUSH = 0x1000, + SHCNF_FLUSHNOWAIT = 0x2000, + SHCNF_NOTIFYRECURSIVE = 0x10000, + } + + [DllImport("shell32.dll")] + public static extern void SHChangeNotify(HChangeNotifyEventID wEventId, HChangeNotifyFlags uFlags, IntPtr dwItem1, IntPtr dwItem2); + } +} diff --git a/renderdocui/Controls/ConstantBufferPreviewer.Designer.cs b/renderdocui/Controls/ConstantBufferPreviewer.Designer.cs new file mode 100644 index 0000000000..be32dce3d8 --- /dev/null +++ b/renderdocui/Controls/ConstantBufferPreviewer.Designer.cs @@ -0,0 +1,111 @@ +namespace renderdocui.Controls +{ + partial class ConstantBufferPreviewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + TreelistView.TreeListColumn treeListColumn1 = ((TreelistView.TreeListColumn)(new TreelistView.TreeListColumn("VarName", "Name"))); + TreelistView.TreeListColumn treeListColumn2 = ((TreelistView.TreeListColumn)(new TreelistView.TreeListColumn("VarValue", "Value"))); + TreelistView.TreeListColumn treeListColumn3 = ((TreelistView.TreeListColumn)(new TreelistView.TreeListColumn("VarType", "Type"))); + this.slotLabel = new System.Windows.Forms.Label(); + this.nameLabel = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.variables = new TreelistView.TreeListView(); + this.tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.variables)).BeginInit(); + this.SuspendLayout(); + // + // slotLabel + // + this.slotLabel.AutoSize = true; + this.slotLabel.Location = new System.Drawing.Point(3, 0); + this.slotLabel.Name = "slotLabel"; + this.slotLabel.Padding = new System.Windows.Forms.Padding(5); + this.slotLabel.Size = new System.Drawing.Size(10, 23); + this.slotLabel.TabIndex = 0; + // + // nameLabel + // + this.nameLabel.AutoSize = true; + this.nameLabel.Location = new System.Drawing.Point(19, 0); + this.nameLabel.Name = "nameLabel"; + this.nameLabel.Padding = new System.Windows.Forms.Padding(5); + this.nameLabel.Size = new System.Drawing.Size(10, 23); + this.nameLabel.TabIndex = 1; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.slotLabel, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.nameLabel, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.variables, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(499, 357); + this.tableLayoutPanel1.TabIndex = 0; + // + // variables + // + treeListColumn1.AutoSizeMinSize = 0; + treeListColumn1.Width = 175; + treeListColumn2.AutoSize = true; + treeListColumn2.AutoSizeMinSize = 0; + treeListColumn2.Width = 50; + treeListColumn3.AutoSizeMinSize = 0; + treeListColumn3.Width = 50; + this.variables.Columns.AddRange(new TreelistView.TreeListColumn[] { + treeListColumn1, + treeListColumn2, + treeListColumn3}); + this.variables.ColumnsOptions.LeftMargin = 0; + this.tableLayoutPanel1.SetColumnSpan(this.variables, 2); + this.variables.Cursor = System.Windows.Forms.Cursors.Arrow; + this.variables.Dock = System.Windows.Forms.DockStyle.Fill; + this.variables.Location = new System.Drawing.Point(3, 26); + this.variables.Name = "variables"; + this.variables.RowOptions.ShowHeader = false; + this.variables.Size = new System.Drawing.Size(493, 328); + this.variables.TabIndex = 2; + this.variables.Text = "treeListView1"; + this.variables.KeyDown += new System.Windows.Forms.KeyEventHandler(this.variables_KeyDown); + // + // ConstantBufferPreviewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ConstantBufferPreviewer"; + this.Size = new System.Drawing.Size(499, 357); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.variables)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private TreelistView.TreeListView variables; + private System.Windows.Forms.Label slotLabel; + private System.Windows.Forms.Label nameLabel; + + } +} diff --git a/renderdocui/Controls/ConstantBufferPreviewer.cs b/renderdocui/Controls/ConstantBufferPreviewer.cs new file mode 100644 index 0000000000..a756118664 --- /dev/null +++ b/renderdocui/Controls/ConstantBufferPreviewer.cs @@ -0,0 +1,268 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using renderdocui.Code; +using renderdoc; +using WeifenLuo.WinFormsUI.Docking; + +namespace renderdocui.Controls +{ + public partial class ConstantBufferPreviewer : UserControl, ILogViewerForm + { + private Core m_Core; + + public ConstantBufferPreviewer(Core c, ShaderStageType stage, UInt32 slot) + { + InitializeComponent(); + + m_Core = c; + Stage = stage; + Slot = slot; + shader = m_Core.CurPipelineState.GetShader(stage); + UpdateLabels(); + + uint offs = 0; + m_Core.CurPipelineState.GetConstantBuffer(Stage, Slot, out cbuffer, out offs); + + m_Core.Renderer.BeginInvoke((ReplayRenderer r) => + { + SetVariables(r.GetCBufferVariableContents(shader, Slot, cbuffer, offs)); + }); + + m_Core.AddLogViewer(this); + } + + private static List m_Docks = new List(); + + public static DockContent Has(ShaderStageType stage, UInt32 slot) + { + foreach (var d in m_Docks) + { + ConstantBufferPreviewer cb = d.Controls[0] as ConstantBufferPreviewer; + + if(cb.Stage == stage && cb.Slot == slot) + return cb.Parent as DockContent; + } + + return null; + } + + public static void ShowDock(DockContent dock, DockPane pane, DockAlignment align, double proportion) + { + dock.FormClosed += new FormClosedEventHandler(dock_FormClosed); + + if (m_Docks.Count > 0) + dock.Show(m_Docks[0].Pane, m_Docks[0]); + else + dock.Show(pane, align, proportion); + + m_Docks.Add(dock); + } + + static void dock_FormClosed(object sender, FormClosedEventArgs e) + { + DockContent p = sender as DockContent; + m_Docks.Remove(p); + } + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + + m_Core.RemoveLogViewer(this); + } + base.Dispose(disposing); + } + + public void OnLogfileClosed() + { + variables.BeginUpdate(); + variables.Nodes.Clear(); + + variables.EndUpdate(); + variables.Invalidate(); + } + + public void OnLogfileLoaded() + { + variables.BeginUpdate(); + variables.Nodes.Clear(); + + variables.EndUpdate(); + variables.Invalidate(); + } + + private void AddVariables(TreelistView.NodeCollection root, ShaderVariable[] vars) + { + foreach (var v in vars) + { + TreelistView.Node n = root.Add(new TreelistView.Node(new object[] { v.name, v, v.TypeString() })); + + if (v.rows > 1) + { + for (int i = 0; i < v.rows; i++) + { + n.Nodes.Add(new TreelistView.Node(new object[] { String.Format("{0}.row{1}", v.name, i), v.Row(i), v.RowTypeString() })); + } + } + + if (v.members.Length > 0) + { + AddVariables(n.Nodes, v.members); + } + } + } + + private void SetVariables(ShaderVariable[] vars) + { + if (variables.InvokeRequired) + { + this.BeginInvoke(new Action(() => { SetVariables(vars); })); + return; + } + + variables.BeginUpdate(); + variables.Nodes.Clear(); + + if(vars != null && vars.Length > 0) + AddVariables(variables.Nodes, vars); + + variables.EndUpdate(); + variables.Invalidate(); + } + + public void OnEventSelected(UInt32 frameID, UInt32 eventID) + { + uint offs = 0; + m_Core.CurPipelineState.GetConstantBuffer(Stage, Slot, out cbuffer, out offs); + + shader = m_Core.CurPipelineState.GetShader(Stage); + var reflection = m_Core.CurPipelineState.GetShaderReflection(Stage); + + UpdateLabels(); + + if (reflection == null || reflection.ConstantBlocks.Length <= Slot) + { + SetVariables(null); + return; + } + + m_Core.Renderer.BeginInvoke((ReplayRenderer r) => + { + SetVariables(r.GetCBufferVariableContents(shader, Slot, cbuffer, offs)); + }); + } + + private string BufferName = ""; + + private ResourceId cbuffer; + private ResourceId shader; + private ShaderStageType Stage; + private UInt32 Slot = 0; + + public override string Text + { + get + { + return String.Format("{0} CB {1}", Stage.ToString(), Slot); + } + } + + private void UpdateLabels() + { + BufferName = ""; + + bool needName = true; + + foreach (var b in m_Core.CurBuffers) + { + if (b.ID == cbuffer) + { + BufferName = b.name; + if(b.customName) + needName = false; + } + } + + var reflection = m_Core.CurPipelineState.GetShaderReflection(Stage); + + if (reflection != null) + { + if (needName && + Slot < reflection.ConstantBlocks.Length && + reflection.ConstantBlocks[Slot].name != "") + BufferName = "<" + reflection.ConstantBlocks[Slot].name + ">"; + } + + nameLabel.Text = BufferName; + + slotLabel.Text = Stage.ToString(); + slotLabel.Text += " Shader Slot " + Slot; + } + + private void variables_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.C && e.Control) + { + int[] width = new int[] { 0, 0, 0 }; + + foreach (var n in variables.NodesSelection) + { + width[0] = Math.Max(width[0], n[0].ToString().Length); + width[1] = Math.Max(width[1], n[1].ToString().Length); + width[2] = Math.Max(width[2], n[2].ToString().Length); + } + + width[0] = Math.Min(50, width[0]); + width[1] = Math.Min(50, width[1]); + width[2] = Math.Min(50, width[2]); + + string fmt = "{0,-" + width[0] + "} {1,-" + width[1] + "} {2,-" + width[2] + "}" + Environment.NewLine; + + string text = ""; + foreach (var n in variables.NodesSelection) + { + text += string.Format(fmt, n[0], n[1], n[2]); + } + + Clipboard.SetText(text); + } + } + } +} diff --git a/renderdocui/Controls/ConstantBufferPreviewer.resx b/renderdocui/Controls/ConstantBufferPreviewer.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/renderdocui/Controls/ConstantBufferPreviewer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/renderdocui/Controls/DoubleClickSplitter.Designer.cs b/renderdocui/Controls/DoubleClickSplitter.Designer.cs new file mode 100644 index 0000000000..e430afdf32 --- /dev/null +++ b/renderdocui/Controls/DoubleClickSplitter.Designer.cs @@ -0,0 +1,37 @@ +namespace renderdocui.Controls +{ + partial class DoubleClickSplitter + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + } + + #endregion + } +} diff --git a/renderdocui/Controls/DoubleClickSplitter.cs b/renderdocui/Controls/DoubleClickSplitter.cs new file mode 100644 index 0000000000..8c83d9af32 --- /dev/null +++ b/renderdocui/Controls/DoubleClickSplitter.cs @@ -0,0 +1,234 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace renderdocui.Controls +{ + public partial class DoubleClickSplitter : SplitContainer + { + public DoubleClickSplitter() + { + InitializeComponent(); + + SplitterMoving += new SplitterCancelEventHandler(OnSplitterMoving); + } + + private int m_PanelMinsize = 0; + private int m_SplitterDistance = 0; + + private bool m_Panel1Collapse = true; + + [Description("If the first panel should be the one to collapse"), Category("Behavior")] + [DefaultValue(typeof(bool), "true")] + public bool Panel1Collapse { get { return m_Panel1Collapse; } set { m_Panel1Collapse = value; } } + + private bool m_Collapsed = false; + [Browsable(false)] + public bool Collapsed + { + get + { + return m_Collapsed; + } + set + { + if (m_Collapsed != value) + { + if (value) + { + m_PanelMinsize = Panel1Collapse ? Panel1MinSize : Panel2MinSize; + m_SplitterDistance = SplitterDistance; + + if (Panel1Collapse) + { + Panel1MinSize = 0; + SplitterDistance = 0; + } + else + { + Panel2MinSize = 0; + SplitterDistance = 10000; + } + } + else + { + if (Panel1Collapse) + Panel1MinSize = m_PanelMinsize; + else + Panel2MinSize = m_PanelMinsize; + + SplitterDistance = m_SplitterDistance; + } + } + + m_Collapsed = value; + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + try + { + if (m_Collapsed && Panel1Collapse) + SplitterDistance = Panel1MinSize; + else if (m_Collapsed && !Panel1Collapse) + { + if(Orientation == Orientation.Vertical) + SplitterDistance = Height - Panel2MinSize; + else if(Orientation == Orientation.Horizontal) + SplitterDistance = Width - Panel2MinSize; + } + } + catch (System.Exception) + { + // non fatal + } + + // arrow + { + var arrow_centre = new Point(SplitterRectangle.X + SplitterRectangle.Width / 2, SplitterRectangle.Y + SplitterRectangle.Height / 2); + + var oldmode = e.Graphics.SmoothingMode; + e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + + Point[] dots = null; + + using(var brush = new SolidBrush(ForeColor)) + { + int dot_diameter = 0; + + if (Orientation == Orientation.Horizontal) + { + dot_diameter = SplitterRectangle.Height - Math.Max(0, SplitterRectangle.Height / 4); + + var arrow_size = new Size(SplitterRectangle.Height * 2, dot_diameter); + var arrow_pos = new Point(arrow_centre.X - arrow_size.Width / 2, arrow_centre.Y - arrow_size.Height / 2); + + if ((Panel1Collapse && !Collapsed) || (!Panel1Collapse && Collapsed)) + { + e.Graphics.FillPolygon(brush, new Point[] { + new Point(arrow_pos.X, arrow_pos.Y + arrow_size.Height), + new Point(arrow_pos.X +arrow_size.Width, arrow_pos.Y + arrow_size.Height), + new Point(arrow_pos.X + arrow_size.Width/2, arrow_pos.Y), + }); + } + else + { + e.Graphics.FillPolygon(brush, new Point[] { + new Point(arrow_pos.X, arrow_pos.Y), + new Point(arrow_pos.X +arrow_size.Width, arrow_pos.Y), + new Point(arrow_pos.X + arrow_size.Width/2, arrow_pos.Y + arrow_size.Height), + }); + } + + dots = new Point[] { + new Point(arrow_centre.X - SplitterRectangle.Width/4 - (int)(dot_diameter*1.5), arrow_centre.Y), + new Point(arrow_centre.X - SplitterRectangle.Width/4, arrow_centre.Y), + new Point(arrow_centre.X - SplitterRectangle.Width/4 + (int)(dot_diameter*1.5), arrow_centre.Y), + + new Point(arrow_centre.X + SplitterRectangle.Width/4 - (int)(dot_diameter*1.5), arrow_centre.Y), + new Point(arrow_centre.X + SplitterRectangle.Width/4, arrow_centre.Y), + new Point(arrow_centre.X + SplitterRectangle.Width/4 + (int)(dot_diameter*1.5), arrow_centre.Y), + }; + } + else + { + dot_diameter = SplitterRectangle.Width - Math.Max(0, SplitterRectangle.Width / 4); + + var arrow_size = new Size(dot_diameter, SplitterRectangle.Width * 2); + var arrow_pos = new Point(arrow_centre.X - arrow_size.Width / 2, arrow_centre.Y - arrow_size.Height / 2); + + if ((Panel1Collapse && !Collapsed) || (!Panel1Collapse && Collapsed)) + { + e.Graphics.FillPolygon(brush, new Point[] { + new Point(arrow_pos.X + arrow_size.Width, arrow_pos.Y), + new Point(arrow_pos.X +arrow_size.Width, arrow_pos.Y + arrow_size.Height), + new Point(arrow_pos.X, arrow_pos.Y + arrow_size.Height/2), + }); + } + else + { + e.Graphics.FillPolygon(brush, new Point[] { + new Point(arrow_pos.X, arrow_pos.Y), + new Point(arrow_pos.X, arrow_pos.Y +arrow_size.Height), + new Point(arrow_pos.X + arrow_size.Width, arrow_pos.Y + arrow_size.Height/2), + }); + } + + dots = new Point[] { + new Point(arrow_centre.X, arrow_centre.Y - SplitterRectangle.Height/4 - (int)(dot_diameter*1.5)), + new Point(arrow_centre.X, arrow_centre.Y - SplitterRectangle.Height/4), + new Point(arrow_centre.X, arrow_centre.Y - SplitterRectangle.Height/4 + (int)(dot_diameter*1.5)), + + new Point(arrow_centre.X, arrow_centre.Y + SplitterRectangle.Height/4 - (int)(dot_diameter*1.5)), + new Point(arrow_centre.X, arrow_centre.Y + SplitterRectangle.Height/4), + new Point(arrow_centre.X, arrow_centre.Y + SplitterRectangle.Height/4 + (int)(dot_diameter*1.5)), + }; + } + + if (dots != null) + { + foreach (var d in dots) + { + var rect = new Rectangle(new Point(d.X - dot_diameter / 2, d.Y - dot_diameter / 2), new Size(dot_diameter, dot_diameter)); + + e.Graphics.FillPie(brush, rect, 0, 360.0f); + } + } + } + + e.Graphics.SmoothingMode = oldmode; + } + } + + protected override void OnDoubleClick(EventArgs e) + { + if (SplitterRectangle.Contains(PointToClient(Control.MousePosition))) + { + Collapsed = !Collapsed; + + return; + } + + base.OnDoubleClick(e); + } + + void OnSplitterMoving(object sender, SplitterCancelEventArgs e) + { + if (Collapsed) + e.Cancel = true; + } + } +} diff --git a/renderdocui/Controls/NoscrollPanel.cs b/renderdocui/Controls/NoscrollPanel.cs new file mode 100644 index 0000000000..4951d41e39 --- /dev/null +++ b/renderdocui/Controls/NoscrollPanel.cs @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace renderdocui.Controls +{ + public class NoScrollPanel : Panel + { + public MouseEventHandler MouseWheelHandler = null; + public KeyEventHandler KeyHandler = null; + + public NoScrollPanel() { } + + protected override void OnMouseWheel(MouseEventArgs e) + { + if (MouseWheelHandler != null) + MouseWheelHandler(this, e); + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (Focused && KeyHandler != null) + { + var args = new KeyEventArgs(keyData); + KeyHandler(this, args); + if(args.Handled) + return true; + } + return base.ProcessCmdKey(ref msg, keyData); + } + + public bool Painting = false; + + protected override void OnPaintBackground(PaintEventArgs pevent) + { + if (Controls.Count == 0 && !Painting) + { + pevent.Graphics.Clear(BackColor); + } + else if (Controls.Count == 1) + { + var pos = Controls[0].Location; + var size = Controls[0].Size; + + using (var brush = new SolidBrush(BackColor)) + { + var rightRect = new Rectangle(pos.X + size.Width, 0, ClientRectangle.Width - (pos.X + size.Width), ClientRectangle.Height); + var leftRect = new Rectangle(0, 0, pos.X, ClientRectangle.Height); + var topRect = new Rectangle(pos.X, 0, size.Width, pos.Y); + var bottomRect = new Rectangle(pos.X, pos.Y + size.Height, size.Width, ClientRectangle.Height - (pos.Y + size.Height)); + + pevent.Graphics.FillRectangle(brush, topRect); + pevent.Graphics.FillRectangle(brush, bottomRect); + pevent.Graphics.FillRectangle(brush, leftRect); + pevent.Graphics.FillRectangle(brush, rightRect); + } + } + } + + protected override Point ScrollToControl(Control activeControl) + { + // Returning the current location prevents the panel from + // scrolling to the active control when the panel loses and regains focus + return this.DisplayRectangle.Location; + } + } +} diff --git a/renderdocui/Controls/PipelineFlowchart.Designer.cs b/renderdocui/Controls/PipelineFlowchart.Designer.cs new file mode 100644 index 0000000000..5873ef4e33 --- /dev/null +++ b/renderdocui/Controls/PipelineFlowchart.Designer.cs @@ -0,0 +1,47 @@ +namespace renderdocui.Controls +{ + partial class PipelineFlowchart + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // PipelineFlowchart + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.Name = "PipelineFlowchart"; + this.Size = new System.Drawing.Size(988, 229); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.PipelineFlowchart_Paint); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/renderdocui/Controls/PipelineFlowchart.cs b/renderdocui/Controls/PipelineFlowchart.cs new file mode 100644 index 0000000000..6267e78ba1 --- /dev/null +++ b/renderdocui/Controls/PipelineFlowchart.cs @@ -0,0 +1,372 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace renderdocui.Controls +{ + public partial class PipelineFlowchart : UserControl + { + public PipelineFlowchart() + { + InitializeComponent(); + + this.DoubleBuffered = true; + SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true); + } + + public void SetStages(KeyValuePair[] stages) + { + m_StageNames = stages; + m_StagesEnabled = new bool[stages.Length]; + m_StageFlows = new bool[stages.Length]; + for(int i=0; i < stages.Length; i++) + m_StageFlows[i] = true; + + Invalidate(); + } + + #region Events + + private static readonly object SelectedStageChangedEvent = new object(); + + [Description("Event raised when the selected pipeline stage is changed."), Category("Behavior")] + public event EventHandler SelectedStageChanged + { + add { Events.AddHandler(SelectedStageChangedEvent, value); } + remove { Events.RemoveHandler(SelectedStageChangedEvent, value); } + } + protected virtual void OnSelectedStageChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[SelectedStageChangedEvent]; + if (handler != null) + handler(this, e); + } + + #endregion + + #region Data Properties + + private bool[] m_StagesEnabled = null; + private bool[] m_StageFlows = null; + private KeyValuePair[] m_StageNames = null; + + public void SetStagesEnabled(bool[] enabled) + { + if (m_StagesEnabled != null && enabled.Length == m_StagesEnabled.Length) + m_StagesEnabled = enabled; + + Invalidate(); + } + + public void IsolateStage(int index) + { + if (m_StageNames != null && index >= 0 && index < m_StageNames.Length) + m_StageFlows[index] = false; + } + + private bool IsStageEnabled(int index) + { + return m_StagesEnabled != null && m_StagesEnabled[index]; + } + + private int m_HoverStage = -1; + private int m_SelectedStage = 0; + + [Browsable(false)] + public int SelectedStage + { + get + { + return m_SelectedStage; + } + set + { + if (value >= 0 && m_StageNames != null && value < m_StageNames.Length) + { + m_SelectedStage = value; + Invalidate(); + + OnSelectedStageChanged(new EventArgs()); + } + } + } + + #endregion + + #region Constants and positions/dimensions + + const int BoxBorderWidth = 3; + const int MinBoxDimension = 25; + const int MaxBoxCornerRadius = 20; + const float BoxCornerRadiusFraction = 1.0f / 6.0f; + const float ArrowHeadSize = 6.0f; + const int MinBoxMargin = 4; + const int BoxLabelMargin = 8; + const float BoxMarginFraction = 0.02f; + + private Rectangle TotalAreaRect + { + get + { + Rectangle rect = ClientRectangle; + + rect.Inflate(-1, -1); + + rect.X += Padding.Left; + rect.Width -= Padding.Left + Padding.Right; + + rect.Y += Padding.Top; + rect.Height -= Padding.Top + Padding.Bottom; + + rect.Inflate(-BoxBorderWidth, -BoxBorderWidth); + + return rect; + } + } + + private float BoxMargin + { + get + { + float margin = Math.Max(TotalAreaRect.Width, TotalAreaRect.Height) * BoxMarginFraction; + + margin = Math.Max(MinBoxMargin, margin); + + return margin; + } + } + + private int NumGaps { get { return m_StageNames == null ? 1 : m_StageNames.Length - 1; } } + private int NumItems { get { return m_StageNames == null ? 2 : m_StageNames.Length; } } + + private SizeF BoxSize + { + get + { + float boxeswidth = TotalAreaRect.Width - NumGaps * BoxMargin; + + float boxdim = Math.Min(TotalAreaRect.Height, boxeswidth / NumItems); + + boxdim = Math.Max(MinBoxDimension, boxdim); + + float oblongwidth = Math.Max(0, (boxeswidth - boxdim * NumItems) / NumItems); + + return new SizeF(boxdim + oblongwidth, boxdim); + } + } + + private RectangleF GetBoxRect(int i) + { + return new RectangleF(TotalAreaRect.X + i * (BoxSize.Width + BoxMargin), + TotalAreaRect.Y + TotalAreaRect.Height / 2 - BoxSize.Height / 2, + BoxSize.Width, BoxSize.Height); + } + + #endregion + + #region Painting + + GraphicsPath RoundedRect(RectangleF rect, int radius) + { + GraphicsPath ret = new GraphicsPath(); + + ret.StartFigure(); + + ret.AddArc(rect.X, rect.Y, 2 * radius, 2 * radius, 180, 90); + ret.AddLine(rect.X + radius, rect.Y, rect.X + rect.Width - radius, rect.Y); + ret.AddArc(rect.X + rect.Width - radius * 2, rect.Y, 2 * radius, 2 * radius, 270, 90); + ret.AddLine(rect.X + rect.Width, rect.Y + radius, rect.X + rect.Width, rect.Y + rect.Height - radius); + ret.AddArc(rect.X + rect.Width - 2*radius, rect.Y + rect.Height - 2 * radius, 2 * radius, 2 * radius, 0, 90); + ret.AddLine(rect.X + rect.Width - radius, rect.Y + rect.Height, rect.X + radius, rect.Y + rect.Height); + ret.AddArc(rect.X, rect.Y + rect.Height - 2*radius, 2 * radius, 2 * radius, 90, 90); + + ret.CloseFigure(); + + return ret; + } + + void DrawArrow(Graphics dc, Brush b, Pen p, float headsize, float y, float left, float right) + { + dc.DrawLine(p, new PointF(left, y), new PointF(right, y)); + + using (GraphicsPath head = new GraphicsPath()) + { + head.StartFigure(); + + head.AddLine(new PointF(right, y), new PointF(right - headsize, y - headsize)); + head.AddLine(new PointF(right - headsize, y - headsize), new PointF(right - headsize, y + headsize)); + + head.CloseFigure(); + + dc.FillPath(b, head); + } + } + + private void PipelineFlowchart_Paint(object sender, PaintEventArgs e) + { + if (m_StageNames == null) + return; + + var dc = e.Graphics; + + dc.CompositingQuality = CompositingQuality.HighQuality; + dc.SmoothingMode = SmoothingMode.AntiAlias; + + int radius = (int)Math.Min(MaxBoxCornerRadius, BoxSize.Height * BoxCornerRadiusFraction); + + float arrowY = TotalAreaRect.Y + TotalAreaRect.Height / 2; + + using (var pen = new Pen(Brushes.Black, BoxBorderWidth)) + using (var selectedpen = new Pen(Brushes.Red, BoxBorderWidth)) + { + for (int i = 0; i < NumGaps; i++) + { + if (!m_StageFlows[i] || !m_StageFlows[i + 1]) + continue; + + float right = TotalAreaRect.X + (i + 1) * (BoxSize.Width + BoxMargin); + float left = right - BoxMargin; + + DrawArrow(dc, Brushes.Black, pen, ArrowHeadSize, arrowY, left, right); + } + + for (int i = 0; i < NumItems; i++) + { + RectangleF boxrect = GetBoxRect(i); + + var backBrush = Brushes.Gainsboro; + var textBrush = Brushes.Black; + var outlinePen = pen; + + if (!IsStageEnabled(i)) + { + backBrush = Brushes.DarkGray; + //textBrush = Brushes.Gainsboro; + } + + if (i == m_HoverStage) + { + backBrush = Brushes.LightYellow; + } + + if (i == SelectedStage) + { + //backBrush = Brushes.Coral; + outlinePen = selectedpen; + } + + using (var boxpath = RoundedRect(boxrect, radius)) + { + dc.FillPath(backBrush, boxpath); + dc.DrawPath(outlinePen, boxpath); + } + + StringFormat format = new StringFormat(); + format.LineAlignment = StringAlignment.Center; + format.Alignment = StringAlignment.Center; + + var s = m_StageNames[i].Value; + + var size = dc.MeasureString(s, Font); + + // Decide whether we can draw the whole stage name or just the abbreviation. + // This can look a little awkward sometimes if it's sometimes abbreviated sometimes + // not. Maybe it should always abbreviate or not at all? + if (size.Width + BoxLabelMargin > (float)boxrect.Width) + { + s = s.Replace(" ", "\n"); + size = dc.MeasureString(s, Font); + + if (size.Width + BoxLabelMargin > (float)boxrect.Width || + size.Height + BoxLabelMargin > (float)boxrect.Height) + { + s = m_StageNames[i].Key; + size = dc.MeasureString(s, Font); + } + } + + dc.DrawString(s, Font, textBrush, new PointF(boxrect.X + boxrect.Width / 2, arrowY), format); + } + } + } + + #endregion + + #region Mouse Handling + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + int old = m_HoverStage; + m_HoverStage = -1; + + for(int i=0; i < NumItems; i++) + { + if (GetBoxRect(i).Contains(e.Location)) + { + m_HoverStage = i; + break; + } + } + + if(m_HoverStage != old) + Invalidate(); + } + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + m_HoverStage = -1; + Invalidate(); + } + + protected override void OnMouseClick(MouseEventArgs e) + { + base.OnMouseClick(e); + + for (int i = 0; i < NumItems; i++) + { + if (GetBoxRect(i).Contains(e.Location)) + { + SelectedStage = i; + break; + } + } + } + + #endregion + } +} diff --git a/renderdocui/Controls/PipelineFlowchart.resx b/renderdocui/Controls/PipelineFlowchart.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/renderdocui/Controls/PipelineFlowchart.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/renderdocui/Controls/RangeHistogram.Designer.cs b/renderdocui/Controls/RangeHistogram.Designer.cs new file mode 100644 index 0000000000..40ffe9dfc2 --- /dev/null +++ b/renderdocui/Controls/RangeHistogram.Designer.cs @@ -0,0 +1,72 @@ +namespace renderdocui.Controls +{ + partial class RangeHistogram + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.whiteToolTip = new System.Windows.Forms.ToolTip(this.components); + this.blackToolTip = new System.Windows.Forms.ToolTip(this.components); + this.SuspendLayout(); + // + // whiteToolTip + // + this.whiteToolTip.AutomaticDelay = 0; + this.whiteToolTip.UseAnimation = false; + this.whiteToolTip.UseFading = false; + // + // blackToolTip + // + this.blackToolTip.AutomaticDelay = 0; + this.blackToolTip.UseAnimation = false; + this.blackToolTip.UseFading = false; + // + // RangeHistogram + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.GradientActiveCaption; + this.DoubleBuffered = true; + this.Name = "RangeHistogram"; + this.Size = new System.Drawing.Size(150, 40); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.RangeHistogram_Paint); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RangeHistogram_MouseDown); + this.MouseEnter += new System.EventHandler(this.RangeHistogram_MouseEnter); + this.MouseLeave += new System.EventHandler(this.RangeHistogram_MouseLeave); + this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.RangeHistogram_MouseMove); + this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.RangeHistogram_MouseUp); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ToolTip whiteToolTip; + private System.Windows.Forms.ToolTip blackToolTip; + + } +} diff --git a/renderdocui/Controls/RangeHistogram.cs b/renderdocui/Controls/RangeHistogram.cs new file mode 100644 index 0000000000..6a993a963b --- /dev/null +++ b/renderdocui/Controls/RangeHistogram.cs @@ -0,0 +1,515 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace renderdocui.Controls +{ + [Designer(typeof(System.Windows.Forms.Design.ControlDesigner))] + public partial class RangeHistogram : UserControl + { + public RangeHistogram() + { + InitializeComponent(); + } + + #region Events + + private static readonly object RangeUpdatedEvent = new object(); + public event EventHandler RangeUpdated + { + add { Events.AddHandler(RangeUpdatedEvent, value); } + remove { Events.RemoveHandler(RangeUpdatedEvent, value); } + } + protected virtual void OnRangeUpdated(RangeHistogramEventArgs e) + { + EventHandler handler = (EventHandler)Events[RangeUpdatedEvent]; + if (handler != null) + handler(this, e); + } + + #endregion + + #region Privates + + private float m_RangeMax = 1.0f; + private float m_RangeMin = 0.0f; + + private float m_WhitePoint = 1.0f; + private float m_BlackPoint = 0.0f; + + private float m_MinRangeSize = 0.001f; + + private int m_Margin = 4; + private int m_Border = 1; + private int m_MarkerSize = 6; + + #endregion + + #region Code Properties + + private uint[] m_HistogramData = null; + private float m_HistogramMin = 0.0f; + private float m_HistogramMax = 1.0f; + + // sets the range of data where the histogram data was calculated. + public void SetHistogramRange(float min, float max) + { + m_HistogramMin = min; + m_HistogramMax = max; + } + + // sets the minimum and maximum as well as the black and white points + public void SetRange(float min, float max) + { + m_RangeMin = min; + m_RangeMax = Math.Max((min+float.Epsilon)*(1.0f+m_MinRangeSize), max); + m_BlackPoint = m_RangeMin; + m_WhitePoint = m_RangeMax; + + Invalidate(); + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + } + + [Browsable(false)] + public uint[] HistogramData + { + get + { + return m_HistogramData; + } + set + { + m_HistogramData = value; + Invalidate(); + } + } + + // black point and white point are the currently selected black/white points, within the + // minimum and maximum points. (ie. not 0 or 1) + [Browsable(false)] + public float BlackPoint + { + get + { + return m_BlackPoint; + } + set + { + if (value <= m_RangeMin) + m_BlackPoint = m_RangeMin = value; + else + m_BlackPoint = value; + + Invalidate(); + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + } + } + [Browsable(false)] + public float WhitePoint + { + get + { + return m_WhitePoint; + } + set + { + if (value >= m_RangeMax) + m_WhitePoint = m_RangeMax = value; + else + m_WhitePoint = value; + + Invalidate(); + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + } + } + + // range min/max are the current minimum and maximum values that can be set + // for the black and white points + [Browsable(false)] + public float RangeMin + { + get + { + return m_RangeMin; + } + set + { + m_RangeMin = Math.Min(value, m_RangeMax - MinRangeSize); + + Invalidate(); + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + } + } + [Browsable(false)] + public float RangeMax + { + get + { + return m_RangeMax; + } + set + { + m_RangeMax = Math.Max(value, m_RangeMin + MinRangeSize); + + Invalidate(); + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + } + } + + #endregion + + #region Designer Properties + + [Description("The smallest possible range that can be selected"), Category("Behavior")] + [DefaultValue(typeof(float), "0.001")] + public float MinRangeSize + { + get { return m_MinRangeSize; } + set { m_MinRangeSize = Math.Max(0.000001f, value); } + } + + [Description("The margin around the range display"), Category("Layout")] + [DefaultValue(typeof(int), "4")] + public int RangeMargin + { + get { return m_Margin; } + set { m_Margin = value; } + } + + [Description("The pixel border around the range bar itself"), Category("Appearance")] + [DefaultValue(typeof(int), "1")] + public int Border + { + get { return m_Border; } + set { m_Border = value; } + } + + [Description("The size in pixels of each marker"), Category("Appearance")] + [DefaultValue(typeof(int), "6")] + public int MarkerSize + { + get { return m_MarkerSize; } + set { m_MarkerSize = value; } + } + + #endregion + + #region Internal Properties + + private int m_TotalSpace { get { return m_Margin + m_Border; } } + private int m_RegionWidth { get { return this.Width - m_TotalSpace * 2; } } + + // these are internal only, they give [0, 1] from minimum to maximum of where the black and white points are + private float m_BlackDelta + { + get + { + return GetDelta(BlackPoint); + } + set + { + BlackPoint = Math.Min(WhitePoint - MinRangeSize, value * (RangeMax - RangeMin) + RangeMin); + } + } + private float m_WhiteDelta + { + get + { + return GetDelta(WhitePoint); + } + set + { + WhitePoint = Math.Max(BlackPoint + MinRangeSize, value * (RangeMax - RangeMin) + RangeMin); + } + } + + private float GetDelta(float val) + { + return (val - RangeMin) / (RangeMax - RangeMin); + } + + #endregion + + #region Tooltips + + private void ShowTooltips() + { + blackToolTip.Show(BlackPoint.ToString("F4"), this, + this.ClientRectangle.Left + (int)(this.ClientRectangle.Width * m_BlackDelta), this.ClientRectangle.Bottom); + + whiteToolTip.Show(WhitePoint.ToString("F4"), this, + this.ClientRectangle.Left + (int)(this.ClientRectangle.Width * m_WhiteDelta), this.ClientRectangle.Top - 15); + } + + #endregion + + #region Mouse Handlers + + private Point m_mousePrev = new Point(-1, -1); + + private enum DraggingMode + { + NONE, + WHITE, + BLACK, + } + private DraggingMode m_DragMode; + + // This handler tries to figure out which handle (white or black) you were trying to + // grab when you clicked. + private void RangeHistogram_MouseDown(object sender, MouseEventArgs e) + { + if(e.Button != MouseButtons.Left) + return; + + Rectangle rect = this.ClientRectangle; + + rect.Inflate(-m_TotalSpace, -m_TotalSpace); + + int whiteX = (int)(m_WhiteDelta * rect.Width); + int blackX = (int)(m_BlackDelta * rect.Width); + + var whiteVec = new PointF(whiteX - e.Location.X, ClientRectangle.Height - e.Location.Y); + var blackVec = new PointF(blackX-e.Location.X, e.Location.Y); + + float whitedist = (float)Math.Sqrt(whiteVec.X * whiteVec.X + whiteVec.Y * whiteVec.Y); + float blackdist = (float)Math.Sqrt(blackVec.X * blackVec.X + blackVec.Y * blackVec.Y); + + System.Diagnostics.Trace.WriteLine(string.Format("white {0} black {1}", whitedist, blackdist)); + + if (whitedist < blackdist && whitedist < 18.0f) + m_DragMode = DraggingMode.WHITE; + else if (blackdist < whitedist && blackdist < 18.0f) + m_DragMode = DraggingMode.BLACK; + else if (e.Location.X > whiteX) + m_DragMode = DraggingMode.WHITE; + else if (e.Location.X < blackX) + m_DragMode = DraggingMode.BLACK; + + if (m_DragMode == DraggingMode.WHITE) + { + float newWhite = (float)(e.Location.X - m_TotalSpace) / (float)m_RegionWidth; + + m_WhiteDelta = Math.Max(m_BlackDelta + m_MinRangeSize, Math.Min(1.0f, newWhite)); + } + else if (m_DragMode == DraggingMode.BLACK) + { + float newBlack = (float)(e.Location.X - m_TotalSpace) / (float)m_RegionWidth; + + m_BlackDelta = Math.Min(m_WhiteDelta - m_MinRangeSize, Math.Max(0.0f, newBlack)); + } + + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + + if (m_DragMode != DraggingMode.NONE) + { + this.Invalidate(); + this.Update(); + } + + m_mousePrev.X = e.X; + m_mousePrev.Y = e.Y; + } + + private void RangeHistogram_MouseUp(object sender, MouseEventArgs e) + { + whiteToolTip.Hide(this); + blackToolTip.Hide(this); + + m_DragMode = DraggingMode.NONE; + + m_mousePrev.X = m_mousePrev.Y = -1; + } + + private void RangeHistogram_MouseMove(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left && (e.X != m_mousePrev.X || e.Y != m_mousePrev.Y)) + { + if (m_DragMode == DraggingMode.WHITE) + { + float newWhite = (float)(e.Location.X - m_TotalSpace) / (float)m_RegionWidth; + + m_WhiteDelta = Math.Max(m_BlackDelta + m_MinRangeSize, Math.Min(1.0f, newWhite)); + } + else if (m_DragMode == DraggingMode.BLACK) + { + float newBlack = (float)(e.Location.X - m_TotalSpace) / (float)m_RegionWidth; + + m_BlackDelta = Math.Min(m_WhiteDelta - m_MinRangeSize, Math.Max(0.0f, newBlack)); + } + + OnRangeUpdated(new RangeHistogramEventArgs(BlackPoint, WhitePoint)); + + if (m_DragMode != DraggingMode.NONE) + { + this.Invalidate(); + this.Update(); + } + + m_mousePrev.X = e.X; + m_mousePrev.Y = e.Y; + + ShowTooltips(); + } + } + + private void RangeHistogram_MouseLeave(object sender, EventArgs e) + { + whiteToolTip.Hide(this); + blackToolTip.Hide(this); + } + + private void RangeHistogram_MouseEnter(object sender, EventArgs e) + { + ShowTooltips(); + } + + #endregion + + #region Other Handlers + + private void RangeHistogram_Paint(object sender, PaintEventArgs e) + { + Rectangle rect = this.ClientRectangle; + + e.Graphics.FillRectangle(SystemBrushes.Control, rect); + + rect.Inflate(-m_Margin, -m_Margin); + + e.Graphics.FillRectangle(Brushes.Black, rect); + + rect.Inflate(-m_Border, -m_Border); + + e.Graphics.FillRectangle(Brushes.DarkGray, rect); + + int whiteX = (int)(m_WhiteDelta * rect.Width); + int blackX = (int)(m_BlackDelta * rect.Width); + + Rectangle blackPoint = new Rectangle(rect.Left, rect.Top, blackX, rect.Height); + Rectangle whitePoint = new Rectangle(rect.Left + whiteX, rect.Top, rect.Width - whiteX, rect.Height); + + e.Graphics.FillRectangle(Brushes.White, whitePoint); + e.Graphics.FillRectangle(Brushes.Black, blackPoint); + + if (HistogramData != null) + { + float minx = GetDelta(m_HistogramMin); + float maxx = GetDelta(m_HistogramMax); + + UInt32 maxval = UInt32.MinValue; + for (int i = 0; i < HistogramData.Length; i++) + { + float x = (float)i / (float)HistogramData.Length; + + float xdelta = minx + x * (maxx - minx); + + if (xdelta >= 0.0f && xdelta <= 1.0f) + { + maxval = Math.Max(maxval, HistogramData[i]); + } + } + + for (int i = 0; i < HistogramData.Length; i++) + { + float x = (float)i / (float)HistogramData.Length; + float y = (float)HistogramData[i] / (float)maxval; + + float xdelta = minx + x * (maxx - minx); + + if (xdelta >= 0.0f && xdelta <= 1.0f) + { + float segwidth = Math.Max(rect.Width * (maxx - minx) / (float)HistogramData.Length, 1); + + RectangleF barRect = new RectangleF(new PointF(rect.Left + rect.Width * (minx + x * (maxx - minx)), rect.Bottom - rect.Height * y), + new SizeF(segwidth, rect.Height * y)); + + e.Graphics.FillRectangle(Brushes.Green, barRect); + } + } + } + + Point[] blackTriangle = { new Point(blackPoint.Right, m_MarkerSize*2), + new Point(blackPoint.Right+m_MarkerSize, 0), + new Point(blackPoint.Right-m_MarkerSize, 0) }; + + e.Graphics.FillPolygon(Brushes.DarkGray, blackTriangle); + + Point[] whiteTriangle = { new Point(whitePoint.Left, whitePoint.Bottom-m_MarkerSize*2+m_Margin), + new Point(whitePoint.Left+m_MarkerSize, whitePoint.Bottom+m_Margin), + new Point(whitePoint.Left-m_MarkerSize, whitePoint.Bottom+m_Margin) }; + + e.Graphics.FillPolygon(Brushes.DarkGray, whiteTriangle); + + blackTriangle[0].Y -= 2; + blackTriangle[1].Y += 1; + blackTriangle[2].Y += 1; + + blackTriangle[1].X -= 2; + blackTriangle[2].X += 2; + + whiteTriangle[0].Y += 2; + whiteTriangle[1].Y -= 1; + whiteTriangle[2].Y -= 1; + + whiteTriangle[1].X -= 2; + whiteTriangle[2].X += 2; + + e.Graphics.FillPolygon(Brushes.Black, blackTriangle); + e.Graphics.FillPolygon(Brushes.White, whiteTriangle); + } + + #endregion + } + + public class RangeHistogramEventArgs : EventArgs + { + private float m_black, m_white; + + public RangeHistogramEventArgs(float black, float white) + { + m_black = black; + m_white = white; + } + + public float BlackPoint + { + get { return m_black; } + } + + public float WhitePoint + { + get { return m_white; } + } + } + +} diff --git a/renderdocui/Controls/RangeHistogram.resx b/renderdocui/Controls/RangeHistogram.resx new file mode 100644 index 0000000000..1749b810ad --- /dev/null +++ b/renderdocui/Controls/RangeHistogram.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 132, 17 + + \ No newline at end of file diff --git a/renderdocui/Controls/ResourcePreview.Designer.cs b/renderdocui/Controls/ResourcePreview.Designer.cs new file mode 100644 index 0000000000..f1d3a64c01 --- /dev/null +++ b/renderdocui/Controls/ResourcePreview.Designer.cs @@ -0,0 +1,131 @@ +namespace renderdocui.Controls +{ + partial class ResourcePreview + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.slotLabel = new System.Windows.Forms.Label(); + this.descriptionLabel = new System.Windows.Forms.Label(); + this.thumbnail = new renderdocui.Controls.NoScrollPanel(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.BackColor = System.Drawing.Color.Transparent; + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.slotLabel, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.descriptionLabel, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.thumbnail, 0, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(110, 86); + this.tableLayoutPanel1.TabIndex = 0; + // + // slotLabel + // + this.slotLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.slotLabel.AutoSize = true; + this.slotLabel.BackColor = System.Drawing.SystemColors.InactiveCaption; + this.slotLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.slotLabel.ForeColor = System.Drawing.SystemColors.ActiveCaptionText; + this.slotLabel.Location = new System.Drawing.Point(0, 60); + this.slotLabel.Margin = new System.Windows.Forms.Padding(0); + this.slotLabel.Name = "slotLabel"; + this.slotLabel.Size = new System.Drawing.Size(19, 26); + this.slotLabel.TabIndex = 1; + this.slotLabel.Text = "1"; + this.slotLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.slotLabel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.child_MouseClick); + this.slotLabel.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.child_MouseDoubleClick); + // + // descriptionLabel + // + this.descriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.descriptionLabel.AutoEllipsis = true; + this.descriptionLabel.BackColor = System.Drawing.SystemColors.InactiveCaption; + this.descriptionLabel.ForeColor = System.Drawing.SystemColors.ActiveCaptionText; + this.descriptionLabel.Location = new System.Drawing.Point(19, 60); + this.descriptionLabel.Margin = new System.Windows.Forms.Padding(0); + this.descriptionLabel.Name = "descriptionLabel"; + this.descriptionLabel.Size = new System.Drawing.Size(91, 26); + this.descriptionLabel.TabIndex = 2; + this.descriptionLabel.Text = "Texture2D 117"; + this.descriptionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.descriptionLabel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.child_MouseClick); + this.descriptionLabel.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.child_MouseDoubleClick); + // + // thumbnail + // + this.thumbnail.BackColor = System.Drawing.Color.Chartreuse; + this.tableLayoutPanel1.SetColumnSpan(this.thumbnail, 2); + this.thumbnail.Dock = System.Windows.Forms.DockStyle.Fill; + this.thumbnail.Location = new System.Drawing.Point(0, 0); + this.thumbnail.Margin = new System.Windows.Forms.Padding(0); + this.thumbnail.Name = "thumbnail"; + this.thumbnail.Size = new System.Drawing.Size(110, 60); + this.thumbnail.TabIndex = 0; + this.thumbnail.Paint += new System.Windows.Forms.PaintEventHandler(this.thumbnail_Paint); + this.thumbnail.MouseClick += new System.Windows.Forms.MouseEventHandler(this.child_MouseClick); + this.thumbnail.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.child_MouseDoubleClick); + // + // ResourcePreview + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.Controls.Add(this.tableLayoutPanel1); + this.Margin = new System.Windows.Forms.Padding(5, 0, 0, 0); + this.Name = "ResourcePreview"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(116, 92); + this.Load += new System.EventHandler(this.ResourcePreview_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private Controls.NoScrollPanel thumbnail; + private System.Windows.Forms.Label slotLabel; + private System.Windows.Forms.Label descriptionLabel; + } +} diff --git a/renderdocui/Controls/ResourcePreview.cs b/renderdocui/Controls/ResourcePreview.cs new file mode 100644 index 0000000000..ae5a2ecb47 --- /dev/null +++ b/renderdocui/Controls/ResourcePreview.cs @@ -0,0 +1,173 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using renderdocui.Code; +using renderdoc; + +namespace renderdocui.Controls +{ + [Designer(typeof(System.Windows.Forms.Design.ControlDesigner))] + public partial class ResourcePreview : UserControl + { + private string m_Name; + private UInt32 m_Width, m_Height, m_Depth, m_NumMips; + private Core m_Core; + private ReplayOutput m_Output; + private IntPtr m_Handle; + + public ResourcePreview(Core core, ReplayOutput output) + { + InitializeComponent(); + + m_Name = "Unbound"; + m_Width = 1; + m_Height = 1; + m_Depth = 1; + m_NumMips = 0; + m_Unbound = true; + thumbnail.Painting = false; + + m_Unbound = true; + + slotLabel.Text = "0"; + + this.DoubleBuffered = true; + + SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); + + m_Handle = thumbnail.Handle; + + m_Core = core; + m_Output = output; + + Selected = false; + } + + public void Init() + { + descriptionLabel.Text = "Unbound"; + m_Unbound = true; + thumbnail.Painting = true; + } + + public void Init(string Name, UInt32 Width, UInt32 Height, UInt32 Depth, UInt32 NumMips) + { + m_Name = Name; + m_Width = Width; + m_Height = Height; + m_Depth = Depth; + m_NumMips = NumMips; + m_Unbound = false; + thumbnail.Painting = true; + + //descriptionLabel.Text = m_Width + "x" + m_Height + "x" + m_Depth + (m_NumMips > 0 ? "[" + m_NumMips + "]\n" : "\n") + m_Name; + descriptionLabel.Text = m_Name; + } + + public string SlotName + { + get { return slotLabel.Text; } + set { slotLabel.Text = value; } + } + + private bool m_Unbound = true; + public bool Unbound + { + get + { + return m_Unbound; + } + } + + private bool m_Selected; + public bool Selected + { + get { return m_Selected; } + set + { + m_Selected = value; + if (value) + { + BackColor = Color.Red; + } + else + { + BackColor = Color.Black; + } + } + } + + public IntPtr ThumbnailHandle + { + get { return m_Handle; } + } + + private void ResourcePreview_Load(object sender, EventArgs e) + { + Init(m_Name, m_Width, m_Height, m_Depth, m_NumMips); + } + + public void Clear() + { + thumbnail.Invalidate(); + } + + private void thumbnail_Paint(object sender, PaintEventArgs e) + { + if (m_Output == null || m_Core.Renderer == null) + { + e.Graphics.Clear(Color.Black); + return; + } + + if (m_Output != null) + m_Core.Renderer.Invoke((ReplayRenderer r) => { m_Output.Display(); }); + } + + public void SetSize(Size s) + { + MinimumSize = MaximumSize = s; + Size = s; + } + + private void child_MouseClick(object sender, MouseEventArgs e) + { + OnMouseClick(e); + } + + private void child_MouseDoubleClick(object sender, MouseEventArgs e) + { + OnMouseDoubleClick(e); + } + } +} diff --git a/renderdocui/Controls/ResourcePreview.resx b/renderdocui/Controls/ResourcePreview.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/renderdocui/Controls/ResourcePreview.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/renderdocui/Controls/TablessControl.cs b/renderdocui/Controls/TablessControl.cs new file mode 100644 index 0000000000..c1eb8d094d --- /dev/null +++ b/renderdocui/Controls/TablessControl.cs @@ -0,0 +1,50 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using renderdocui.Code; + +namespace renderdocui.Controls +{ + // thanks to Hans Passant - http://stackoverflow.com/a/6954785 + public class TablessControl : TabControl + { + protected override void WndProc(ref Message m) + { + // Hide tabs by trapping the TCM_ADJUSTRECT message + if (m.Msg == (int)Win32PInvoke.Win32Message.TCM_ADJUSTRECT && !DesignMode) + m.Result = (IntPtr)1; + else + base.WndProc(ref m); + } + } +} diff --git a/renderdocui/Controls/TextureListBox.cs b/renderdocui/Controls/TextureListBox.cs new file mode 100644 index 0000000000..2bc2bb588f --- /dev/null +++ b/renderdocui/Controls/TextureListBox.cs @@ -0,0 +1,233 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using renderdoc; +using renderdocui.Code; + +namespace renderdocui.Controls +{ + public partial class TextureListBox : ListBox + { + private List m_FilteredTextures = new List(); + + private static readonly object GoIconClickEvent = new object(); + public event EventHandler GoIconClick + { + add { Events.AddHandler(GoIconClickEvent, value); } + remove { Events.RemoveHandler(GoIconClickEvent, value); } + } + protected virtual void OnGoIconClick(GoIconClickEventArgs e) + { + EventHandler handler = (EventHandler)Events[GoIconClickEvent]; + if (handler != null) + handler(this, e); + } + + public Core m_Core = null; + + public TextureListBox() + { + DrawMode = DrawMode.OwnerDrawFixed; + DrawItem += new DrawItemEventHandler(TextureListBox_DrawItem); + + this.DoubleBuffered = true; + SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); + + Items.Clear(); + Items.Add("foobar"); + } + + void TextureListBox_DrawItem(object sender, DrawItemEventArgs e) + { + if (Items.Count > 0 && e.Index >= 0) + { + Rectangle stringBounds = e.Bounds; + + var image = global::renderdocui.Properties.Resources.action; + + if (m_HoverHighlight == e.Index) + { + image = global::renderdocui.Properties.Resources.action_hover; + e.Graphics.DrawRectangle(Pens.LightGray, e.Bounds); + } + + e.Graphics.DrawImage(image, e.Bounds.Width - 16, e.Bounds.Y, 16, 16); + + stringBounds.Width -= 18; + + var sf = new StringFormat(StringFormat.GenericDefault); + + sf.Trimming = StringTrimming.EllipsisCharacter; + sf.FormatFlags |= StringFormatFlags.NoWrap; + + using (Brush b = new SolidBrush(ForeColor)) + { + e.Graphics.DrawString(Items[e.Index].ToString(), + Font, b, stringBounds, sf); + } + } + } + + private int m_HoverHighlight = -1; + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + } + + protected override void OnMouseClick(MouseEventArgs e) + { + base.OnMouseClick(e); + + if (Items.Count > 0 && m_HoverHighlight >= 0) + { + var rect = GetItemRectangle(m_HoverHighlight); + + if (rect.Contains(e.Location)) + { + OnGoIconClick(new GoIconClickEventArgs(m_FilteredTextures[m_HoverHighlight].ID)); + } + } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + bool curhover = m_HoverHighlight != -1; + bool hover = false; + + for(int i=0; i < Items.Count; i++) + { + var rect = GetItemRectangle(i); + + bool highlight = rect.Contains(e.Location); + + hover |= highlight; + + if (m_HoverHighlight != i && highlight) + { + m_HoverHighlight = i; + Invalidate(); + } + } + + if (hover) + { + Cursor = Cursors.Hand; + } + else + { + Cursor = Cursors.Arrow; + m_HoverHighlight = -1; + } + + if (hover != curhover) + Invalidate(); + } + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + Cursor = Cursors.Arrow; + if (Items.Count > 0 && m_HoverHighlight >= 0) + Invalidate(GetItemRectangle(m_HoverHighlight)); + + m_HoverHighlight = -1; + } + + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged(e); + + if (Visible) + { + FillTextureList("", true, true); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + for (int i = 0; i < Items.Count; i++) + { + TextureListBox_DrawItem(this, new DrawItemEventArgs(e.Graphics, Font, GetItemRectangle(i), i, DrawItemState.Default)); + } + } + + public void FillTextureList(string filter, bool RTs, bool Texs) + { + m_FilteredTextures.Clear(); + Items.Clear(); + + if (m_Core == null ||!m_Core.LogLoaded) + { + return; + } + + for (int i = 0; i < m_Core.CurTextures.Length; i++) + { + bool include = false; + include |= (RTs && ((m_Core.CurTextures[i].creationFlags & TextureCreationFlags.RTV) > 0 || + (m_Core.CurTextures[i].creationFlags & TextureCreationFlags.DSV) > 0)); + include |= (Texs && (m_Core.CurTextures[i].creationFlags & TextureCreationFlags.RTV) == 0 && + (m_Core.CurTextures[i].creationFlags & TextureCreationFlags.DSV) == 0); + include |= (filter != "" && (m_Core.CurTextures[i].name.ToLowerInvariant().Contains(filter.ToLowerInvariant()))); + include |= (!RTs && !Texs && filter == ""); + + if (include) + { + m_FilteredTextures.Add(m_Core.CurTextures[i]); + Items.Add(m_Core.CurTextures[i].name); + } + } + } + } + + public class GoIconClickEventArgs : EventArgs + { + private ResourceId id; + + public GoIconClickEventArgs(ResourceId i) + { + id = i; + } + + public ResourceId ID + { + get { return id; } + } + } +} diff --git a/renderdocui/Controls/ThumbnailStrip.Designer.cs b/renderdocui/Controls/ThumbnailStrip.Designer.cs new file mode 100644 index 0000000000..a0b65a6142 --- /dev/null +++ b/renderdocui/Controls/ThumbnailStrip.Designer.cs @@ -0,0 +1,106 @@ +namespace renderdocui.Controls +{ + partial class ThumbnailStrip + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + this.panel = new System.Windows.Forms.Panel(); + this.hscroll = new System.Windows.Forms.HScrollBar(); + this.vscroll = new System.Windows.Forms.VScrollBar(); + tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel1.Controls.Add(this.panel, 0, 0); + tableLayoutPanel1.Controls.Add(this.hscroll, 0, 1); + tableLayoutPanel1.Controls.Add(this.vscroll, 1, 0); + tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 2; + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.Size = new System.Drawing.Size(791, 246); + tableLayoutPanel1.TabIndex = 1; + // + // panel + // + this.panel.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel.Location = new System.Drawing.Point(0, 0); + this.panel.Margin = new System.Windows.Forms.Padding(0); + this.panel.Name = "panel"; + this.panel.Size = new System.Drawing.Size(775, 230); + this.panel.TabIndex = 0; + this.panel.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.panel_ControlAddRemove); + this.panel.ControlRemoved += new System.Windows.Forms.ControlEventHandler(this.panel_ControlAddRemove); + this.panel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel_MouseClick); + // + // hscroll + // + this.hscroll.Dock = System.Windows.Forms.DockStyle.Bottom; + this.hscroll.Location = new System.Drawing.Point(0, 230); + this.hscroll.Name = "hscroll"; + this.hscroll.Size = new System.Drawing.Size(775, 16); + this.hscroll.TabIndex = 1; + this.hscroll.Scroll += new System.Windows.Forms.ScrollEventHandler(this.hscroll_Scroll); + // + // vscroll + // + this.vscroll.Dock = System.Windows.Forms.DockStyle.Right; + this.vscroll.Location = new System.Drawing.Point(775, 0); + this.vscroll.Name = "vscroll"; + this.vscroll.Size = new System.Drawing.Size(16, 230); + this.vscroll.TabIndex = 2; + this.vscroll.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vscroll_Scroll); + // + // ThumbnailStrip + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(tableLayoutPanel1); + this.Margin = new System.Windows.Forms.Padding(0); + this.Name = "ThumbnailStrip"; + this.Size = new System.Drawing.Size(791, 246); + this.Layout += new System.Windows.Forms.LayoutEventHandler(this.ThumbnailStrip_Layout); + tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panel; + private System.Windows.Forms.HScrollBar hscroll; + private System.Windows.Forms.VScrollBar vscroll; + } +} diff --git a/renderdocui/Controls/ThumbnailStrip.cs b/renderdocui/Controls/ThumbnailStrip.cs new file mode 100644 index 0000000000..cd0cf631ed --- /dev/null +++ b/renderdocui/Controls/ThumbnailStrip.cs @@ -0,0 +1,228 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace renderdocui.Controls +{ + public partial class ThumbnailStrip : UserControl + { + public ThumbnailStrip() + { + InitializeComponent(); + + MouseWheel += new MouseEventHandler(ThumbnailStrip_MouseWheel); + } + + void ThumbnailStrip_MouseWheel(object sender, MouseEventArgs e) + { + const int WHEEL_DELTA = 120; + + int movement = e.Delta / WHEEL_DELTA; + + if (vscroll.Visible) + vscroll.Value = Code.Helpers.Clamp(vscroll.Value - movement * vscroll.SmallChange, vscroll.Minimum, vscroll.Maximum - vscroll.LargeChange); + if (hscroll.Visible) + hscroll.Value = Code.Helpers.Clamp(hscroll.Value - movement * hscroll.SmallChange, hscroll.Minimum, hscroll.Maximum - hscroll.LargeChange); + + RefreshLayout(); + } + + private List m_Thumbnails = new List(); + public ResourcePreview[] Thumbnails { get { return m_Thumbnails.ToArray(); } } + + public void AddThumbnail(ResourcePreview r) + { + panel.Controls.Add(r); + m_Thumbnails.Add(r); + } + + public void ClearThumbnails() + { + m_Thumbnails.Clear(); + panel.Controls.Clear(); + } + + public void RefreshLayout() + { + Rectangle avail = ClientRectangle; + avail.Inflate(new Size(-6, -6)); + + int numVisible = 0; + foreach (ResourcePreview c in Thumbnails) + if (c.Visible) numVisible++; + + // depending on overall aspect ratio, we either lay out the strip horizontally or + // vertically. This tries to account for whether the strip is docked along one side + // or another of the texture viewer + if (avail.Width > avail.Height) + { + avail.Width += 6; // controls implicitly have a 6 margin on the right + + int aspectWidth = (int)(avail.Height * 1.3f); + + vscroll.Visible = false; + + int noscrollWidth = numVisible * (aspectWidth + 6); + + if (noscrollWidth <= avail.Width) + { + hscroll.Visible = false; + + int x = avail.X; + foreach (ResourcePreview c in Thumbnails) + { + if (c.Visible) + { + c.Location = new Point(x, avail.Y); + c.SetSize(new Size(aspectWidth, avail.Height)); + + x += aspectWidth + 6; + } + } + } + else + { + hscroll.Visible = true; + + avail.Height = avail.Height - SystemInformation.HorizontalScrollBarHeight; + + aspectWidth = (int)(avail.Height * 1.3f); + + int totalWidth = numVisible * (aspectWidth + 6); + hscroll.Enabled = totalWidth > avail.Width; + + if (hscroll.Enabled) + { + hscroll.Maximum = totalWidth - avail.Width; + hscroll.LargeChange = Code.Helpers.Clamp(avail.Height, 1, hscroll.Maximum/2); + hscroll.SmallChange = Math.Max(1, hscroll.LargeChange / 2); + } + + int x = avail.X - (int)(hscroll.Maximum*(float)hscroll.Value/(float)(hscroll.Maximum-hscroll.LargeChange)); + foreach (ResourcePreview c in Thumbnails) + { + if (c.Visible) + { + c.Location = new Point(x, avail.Y); + c.SetSize(new Size(aspectWidth, avail.Height)); + + x += aspectWidth + 6; + } + } + } + } + else + { + avail.Height += 6; // controls implicitly have a 6 margin on the bottom + + int aspectHeight = (int)(avail.Width / 1.3f); + + hscroll.Visible = false; + + int noscrollHeight = numVisible * (aspectHeight + 6); + + if (noscrollHeight <= avail.Height) + { + vscroll.Visible = false; + + int y = avail.Y; + foreach (ResourcePreview c in Thumbnails) + { + if (c.Visible) + { + c.Location = new Point(avail.X, y); + c.SetSize(new Size(avail.Width, aspectHeight)); + + y += aspectHeight + 6; + } + } + } + else + { + vscroll.Visible = true; + + avail.Width = avail.Width - SystemInformation.VerticalScrollBarWidth; + + aspectHeight = (int)(avail.Width / 1.3f); + + int totalHeight = numVisible * (aspectHeight + 6); + vscroll.Enabled = totalHeight > avail.Height; + + if (vscroll.Enabled) + { + vscroll.Maximum = totalHeight - avail.Height; + vscroll.LargeChange = Code.Helpers.Clamp(avail.Width, 1, vscroll.Maximum / 2); + vscroll.SmallChange = Math.Max(1, vscroll.LargeChange / 2); + } + + int y = avail.Y - (int)(vscroll.Maximum * (float)vscroll.Value / (float)(vscroll.Maximum - vscroll.LargeChange)); + foreach (ResourcePreview c in Thumbnails) + { + if (c.Visible) + { + c.Location = new Point(avail.X, y); + c.SetSize(new Size(avail.Width, aspectHeight)); + + y += aspectHeight + 6; + } + } + } + } + } + + private void ThumbnailStrip_Layout(object sender, LayoutEventArgs e) + { + RefreshLayout(); + } + + private void panel_ControlAddRemove(object sender, ControlEventArgs e) + { + RefreshLayout(); + } + + private void panel_MouseClick(object sender, MouseEventArgs e) + { + OnMouseClick(e); + } + + private void hscroll_Scroll(object sender, ScrollEventArgs e) + { + RefreshLayout(); + } + + private void vscroll_Scroll(object sender, ScrollEventArgs e) + { + RefreshLayout(); + } + } +} diff --git a/renderdocui/Controls/ThumbnailStrip.resx b/renderdocui/Controls/ThumbnailStrip.resx new file mode 100644 index 0000000000..9acfc22418 --- /dev/null +++ b/renderdocui/Controls/ThumbnailStrip.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + \ No newline at end of file diff --git a/renderdocui/Controls/ToolStripSpringTextBox.cs b/renderdocui/Controls/ToolStripSpringTextBox.cs new file mode 100644 index 0000000000..25ee2b6b48 --- /dev/null +++ b/renderdocui/Controls/ToolStripSpringTextBox.cs @@ -0,0 +1,109 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace renderdocui.Controls +{ + // toolstrip textbox that resizes to fit + // http://msdn.microsoft.com/en-us/library/ms404304(v=vs.90).aspx + public class ToolStripSpringTextBox : ToolStripTextBox + { + public override Size GetPreferredSize(Size constrainingSize) + { + // Use the default size if the text box is on the overflow menu + // or is on a vertical ToolStrip. + if (IsOnOverflow || Owner.Orientation == Orientation.Vertical) + { + return DefaultSize; + } + + // Declare a variable to store the total available width as + // it is calculated, starting with the display width of the + // owning ToolStrip. + Int32 width = Owner.DisplayRectangle.Width; + + // Subtract the width of the overflow button if it is displayed. + if (Owner.OverflowButton.Visible) + { + width = width - Owner.OverflowButton.Width - + Owner.OverflowButton.Margin.Horizontal; + } + + // Declare a variable to maintain a count of ToolStripSpringTextBox + // items currently displayed in the owning ToolStrip. + Int32 springBoxCount = 0; + + foreach (ToolStripItem item in Owner.Items) + { + // Ignore items on the overflow menu. + if (item.IsOnOverflow) continue; + + if (item is ToolStripSpringTextBox) + { + // For ToolStripSpringTextBox items, increment the count and + // subtract the margin width from the total available width. + springBoxCount++; + width -= item.Margin.Horizontal; + } + else + { + // For all other items, subtract the full width from the total + // available width. + width = width - item.Width - item.Margin.Horizontal; + } + } + + // If there are multiple ToolStripSpringTextBox items in the owning + // ToolStrip, divide the total available width between them. + if (springBoxCount > 1) width /= springBoxCount; + + // If the available width is less than the default width, use the + // default width, forcing one or more items onto the overflow menu. + if (width < DefaultSize.Width) width = DefaultSize.Width; + + // Retrieve the preferred size from the base class, but change the + // width to the calculated width. + Size size = base.GetPreferredSize(constrainingSize); + size.Width = width; + return size; + } + + protected override bool ProcessCmdKey(ref Message m, Keys keyData) + { + if (keyData == Keys.Escape) + { + OnKeyPress(new KeyPressEventArgs('\0')); + return true; + } + else + { + return false; + } + } + } +} diff --git a/renderdocui/Controls/TreeListView/LICENSE.htm b/renderdocui/Controls/TreeListView/LICENSE.htm new file mode 100644 index 0000000000..13f08839bc --- /dev/null +++ b/renderdocui/Controls/TreeListView/LICENSE.htm @@ -0,0 +1,251 @@ + + +The Code Project Open License (CPOL) + + + + +

The Code Project Open License (CPOL) 1.02

+
+ +
+
+ +

Preamble

+

+ This License governs Your use of the Work. This License is intended to allow developers + to use the Source Code and Executable Files provided as part of the Work in any + application in any form. +

+

+ The main points subject to the terms of the License are:

+
    +
  • Source Code and Executable Files can be used in commercial applications;
  • +
  • Source Code and Executable Files can be redistributed; and
  • +
  • Source Code can be modified to create derivative works.
  • +
  • No claim of suitability, guarantee, or any warranty whatsoever is provided. The software is + provided "as-is".
  • +
  • The Article accompanying the Work may not be distributed or republished without the + Author's consent
  • +
+ +

+ This License is entered between You, the individual or other entity reading or otherwise + making use of the Work licensed pursuant to this License and the individual or other + entity which offers the Work under the terms of this License ("Author").

+ +

License

+

+ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CODE PROJECT OPEN + LICENSE ("LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE + LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT + LAW IS PROHIBITED.

+

+ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HEREIN, YOU ACCEPT AND AGREE TO BE + BOUND BY THE TERMS OF THIS LICENSE. THE AUTHOR GRANTS YOU THE RIGHTS CONTAINED HEREIN + IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. IF YOU DO NOT + AGREE TO ACCEPT AND BE BOUND BY THE TERMS OF THIS LICENSE, YOU CANNOT MAKE ANY + USE OF THE WORK.

+ +
    +
  1. Definitions. + +
      +
    1. "Articles" means, collectively, all articles written by Author + which describes how the Source Code and Executable Files for the Work may be used + by a user.
    2. +
    3. "Author" means the individual or entity that offers the Work under the terms + of this License.
    4. +
    5. "Derivative Work" means a work based upon the Work or upon the + Work and other pre-existing works.
    6. +
    7. "Executable Files" refer to the executables, binary files, configuration + and any required data files included in the Work.
    8. +
    9. "Publisher" means the provider of the website, magazine, CD-ROM, DVD or other + medium from or by which the Work is obtained by You.
    10. +
    11. "Source Code" refers to the collection of source code and configuration files + used to create the Executable Files.
    12. +
    13. "Standard Version" refers to such a Work if it has not been modified, or + has been modified in accordance with the consent of the Author, such consent being + in the full discretion of the Author.
    14. +
    15. "Work" refers to the collection of files distributed by the Publisher, including + the Source Code, Executable Files, binaries, data files, documentation, whitepapers + and the Articles.
    16. +
    17. "You" is you, an individual or entity wishing to use the Work and exercise + your rights under this License. +
    18. +
    +
  2. + +
  3. Fair Use/Fair Use Rights. Nothing in this License is intended to + reduce, limit, or restrict any rights arising from fair use, fair dealing, first + sale or other limitations on the exclusive rights of the copyright owner under copyright + law or other applicable laws. +
  4. + +
  5. License Grant. Subject to the terms and conditions of this License, + the Author hereby grants You a worldwide, royalty-free, non-exclusive, perpetual + (for the duration of the applicable copyright) license to exercise the rights in + the Work as stated below: + +
      +
    1. You may use the standard version of the Source Code or Executable Files in Your + own applications.
    2. +
    3. You may apply bug fixes, portability fixes and other modifications obtained from + the Public Domain or from the Author. A Work modified in such a way shall still + be considered the standard version and will be subject to this License.
    4. +
    5. You may otherwise modify Your copy of this Work (excluding the Articles) in any + way to create a Derivative Work, provided that You insert a prominent notice in + each changed file stating how, when and where You changed that file.
    6. +
    7. You may distribute the standard version of the Executable Files and Source Code + or Derivative Work in aggregate with other (possibly commercial) programs as part + of a larger (possibly commercial) software distribution.
    8. +
    9. The Articles discussing the Work published in any form by the author may not be + distributed or republished without the Author's consent. The author retains + copyright to any such Articles. You may use the Executable Files and Source Code + pursuant to this License but you may not repost or republish or otherwise distribute + or make available the Articles, without the prior written consent of the Author.
    10. +
    + + Any subroutines or modules supplied by You and linked into the Source Code or Executable + Files of this Work shall not be considered part of this Work and will not be subject + to the terms of this License. +
  6. + +
  7. Patent License. Subject to the terms and conditions of this License, + each Author hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable (except as stated in this section) patent license to make, have made, use, import, + and otherwise transfer the Work.
  8. + +
  9. Restrictions. The license granted in Section 3 above is expressly + made subject to and limited by the following restrictions: + +
      +
    1. You agree not to remove any of the original copyright, patent, trademark, and + attribution notices and associated disclaimers that may appear in the Source Code + or Executable Files.
    2. +
    3. You agree not to advertise or in any way imply that this Work is a product of Your + own.
    4. +
    5. The name of the Author may not be used to endorse or promote products derived from + the Work without the prior written consent of the Author.
    6. +
    7. You agree not to sell, lease, or rent any part of the Work. This does not restrict + you from including the Work or any part of the Work inside a larger software + distribution that itself is being sold. The Work by itself, though, cannot be sold, + leased or rented.
    8. +
    9. You may distribute the Executable Files and Source Code only under the terms of + this License, and You must include a copy of, or the Uniform Resource Identifier + for, this License with every copy of the Executable Files or Source Code You distribute + and ensure that anyone receiving such Executable Files and Source Code agrees that + the terms of this License apply to such Executable Files and/or Source Code. You + may not offer or impose any terms on the Work that alter or restrict the terms of + this License or the recipients' exercise of the rights granted hereunder. You + may not sublicense the Work. You must keep intact all notices that refer to this + License and to the disclaimer of warranties. You may not distribute the Executable + Files or Source Code with any technological measures that control access or use + of the Work in a manner inconsistent with the terms of this License.
    10. +
    11. You agree not to use the Work for illegal, immoral or improper purposes, or on pages + containing illegal, immoral or improper material. The Work is subject to applicable + export laws. You agree to comply with all such laws and regulations that may apply + to the Work after Your receipt of the Work. +
    12. +
    +
  10. + +
  11. Representations, Warranties and Disclaimer. THIS WORK IS PROVIDED + "AS IS", "WHERE IS" AND "AS AVAILABLE", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES + OR CONDITIONS OR GUARANTEES. YOU, THE USER, ASSUME ALL RISK IN ITS USE, INCLUDING + COPYRIGHT INFRINGEMENT, PATENT INFRINGEMENT, SUITABILITY, ETC. AUTHOR EXPRESSLY + DISCLAIMS ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES OR CONDITIONS, INCLUDING + WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY + OR FITNESS FOR A PARTICULAR PURPOSE, OR ANY WARRANTY OF TITLE OR NON-INFRINGEMENT, + OR THAT THE WORK (OR ANY PORTION THEREOF) IS CORRECT, USEFUL, BUG-FREE OR FREE OF + VIRUSES. YOU MUST PASS THIS DISCLAIMER ON WHENEVER YOU DISTRIBUTE THE WORK OR DERIVATIVE + WORKS. +
  12. + +
  13. Indemnity. You agree to defend, indemnify and hold harmless the Author and + the Publisher from and against any claims, suits, losses, damages, liabilities, + costs, and expenses (including reasonable legal or attorneys’ fees) resulting from + or relating to any use of the Work by You. +
  14. + +
  15. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE + LAW, IN NO EVENT WILL THE AUTHOR OR THE PUBLISHER BE LIABLE TO YOU ON ANY LEGAL + THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES + ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK OR OTHERWISE, EVEN IF THE AUTHOR + OR THE PUBLISHER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +
  16. + +
  17. Termination. + +
      +
    1. This License and the rights granted hereunder will terminate automatically upon + any breach by You of any term of this License. Individuals or entities who have + received Derivative Works from You under this License, however, will not have their + licenses terminated provided such individuals or entities remain in full compliance + with those licenses. Sections 1, 2, 6, 7, 8, 9, 10 and 11 will survive any termination + of this License.
    2. + +
    3. If You bring a copyright, trademark, patent or any other infringement claim against + any contributor over infringements You claim are made by the Work, your License + from such contributor to the Work ends automatically.
    4. + +
    5. Subject to the above terms and conditions, this License is perpetual (for the duration + of the applicable copyright in the Work). Notwithstanding the above, the Author + reserves the right to release the Work under different license terms or to stop + distributing the Work at any time; provided, however that any such election will + not serve to withdraw this License (or any other license that has been, or is required + to be, granted under the terms of this License), and this License will continue + in full force and effect unless terminated as stated above. +
    6. +
    +
  18. + +
  19. Publisher. The parties hereby confirm that the Publisher shall + not, under any circumstances, be responsible for and shall not have any liability + in respect of the subject matter of this License. The Publisher makes no warranty + whatsoever in connection with the Work and shall not be liable to You or any party + on any legal theory for any damages whatsoever, including without limitation any + general, special, incidental or consequential damages arising in connection to this + license. The Publisher reserves the right to cease making the Work available to + You at any time without notice
  20. + +
  21. Miscellaneous + +
      +
    1. This License shall be governed by the laws of the location of the head office of + the Author or if the Author is an individual, the laws of location of the principal + place of residence of the Author.
    2. +
    3. If any provision of this License is invalid or unenforceable under applicable law, + it shall not affect the validity or enforceability of the remainder of the terms + of this License, and without further action by the parties to this License, such + provision shall be reformed to the minimum extent necessary to make such provision + valid and enforceable.
    4. +
    5. No term or provision of this License shall be deemed waived and no breach consented + to unless such waiver or consent shall be in writing and signed by the party to + be charged with such waiver or consent.
    6. +
    7. This License constitutes the entire agreement between the parties with respect to + the Work licensed herein. There are no understandings, agreements or representations + with respect to the Work not specified herein. The Author shall not be bound by + any additional provisions that may appear in any communication from You. This License + may not be modified without the mutual written agreement of the Author and You. +
    8. +
    + +
  22. +
+ +
+
+ + + diff --git a/renderdocui/Controls/TreeListView/README.txt b/renderdocui/Controls/TreeListView/README.txt new file mode 100644 index 0000000000..9f8fe39297 --- /dev/null +++ b/renderdocui/Controls/TreeListView/README.txt @@ -0,0 +1,7 @@ +This control is almost entirely taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns by jkristia. + +Minor changes have been made to clean up, rename or reorganise - as well as a few fixes to the non-visual styles rendering path +and some additional changes for my use of the control (like having the tree controls in a column other than the first, which mostly +'Just Worked' (tm) ). + +So all credit goes to the above author! \ No newline at end of file diff --git a/renderdocui/Controls/TreeListView/TreeListColumn.Design.cs b/renderdocui/Controls/TreeListView/TreeListColumn.Design.cs new file mode 100644 index 0000000000..aea21daeb3 --- /dev/null +++ b/renderdocui/Controls/TreeListView/TreeListColumn.Design.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Diagnostics; + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Reflection; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks +// and fixes for my purposes. +namespace TreelistView +{ + // http://msdn2.microsoft.com/en-us/library/9zky1t4k.aspx + + // Extending Design-Time Support + // ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxdeveloping/html/d6ac8a6a-42fd-4bc8-bf33-b212811297e2.htm + // http://msdn2.microsoft.com/en-us/library/37899azc.aspx + + // description of the property grid + // http://msdn2.microsoft.com/en-us/library/aa302326.aspx + // http://msdn2.microsoft.com/en-us/library/aa302334.aspx + + // another good one explaining + // http://www.codeproject.com/KB/cs/dzcollectioneditor.aspx?print=true + public class ColumnCollectionEditor : CollectionEditor + { + public ColumnCollectionEditor(Type type) : base(type) + { + } + protected override bool CanSelectMultipleInstances() + { + return false; + } + protected override Type CreateCollectionItemType() + { + return base.CreateCollectionItemType(); + } + protected override object CreateInstance(Type itemType) + { + TreeListView owner = this.Context.Instance as TreeListView; + // create new default fieldname + string fieldname; + string caption; + int cnt = owner.Columns.Count; + do + { + fieldname = "fieldname" + cnt.ToString(); + caption = "Column_" + cnt.ToString(); + cnt++; + } + while (owner.Columns[fieldname] != null); + return new TreeListColumn(fieldname, caption); + } + protected override string GetDisplayText(object value) + { + string Caption = (string)value.GetType().GetProperty("Caption").GetGetMethod().Invoke(value, null); + string Fieldname = (string)value.GetType().GetProperty("Fieldname").GetGetMethod().Invoke(value, null); + + if (Caption.Length > 0) + return string.Format("{0} ({1})", Caption, Fieldname); + return base.GetDisplayText(value); + } + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + object result = base.EditValue(context, provider, value); + TreeListView owner = this.Context.Instance as TreeListView; + owner.Invalidate(); + return result; + } + } + + internal class ColumnConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) + { + if (destType == typeof(InstanceDescriptor) || destType == typeof(string)) + return true; + else + return base.CanConvertTo(context, destType); + } + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo info, object value, Type destType) + { + if (destType == typeof(string)) + { + string Caption = (string)value.GetType().GetProperty("Caption").GetGetMethod().Invoke(value, null); + string Fieldname = (string)value.GetType().GetProperty("Fieldname").GetGetMethod().Invoke(value, null); + + return String.Format("{0}, {1}", Caption, Fieldname); + } + if (destType == typeof(InstanceDescriptor)) + { + ConstructorInfo cinfo = typeof(TreeListColumn).GetConstructor(new Type[] { typeof(string), typeof(string) }); + + string Caption = (string)value.GetType().GetProperty("Caption").GetGetMethod().Invoke(value, null); + string Fieldname = (string)value.GetType().GetProperty("Fieldname").GetGetMethod().Invoke(value, null); + + return new InstanceDescriptor(cinfo, new object[] {Fieldname, Caption}, false); + } + return base.ConvertTo(context, info, value, destType); + } + } + class ColumnsTypeConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(TreeListColumnCollection)) + return true; + return base.CanConvertTo(context, destinationType); + } + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string)) + return "(Columns Collection)"; + return base.ConvertTo(context, culture, value, destinationType); + } + } + + /// + /// Designer for the tree view control. + /// + class TreeListViewDesigner : ControlDesigner + { + IComponentChangeService onChangeService; + public override void Initialize(IComponent component) + { + base.Initialize(component); + + onChangeService = (IComponentChangeService)GetService(typeof(IComponentChangeService)); + if (onChangeService != null) + onChangeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged); + + // we need to be notified when columsn have been resized. + TreeListView tree = Control as TreeListView; + tree.AfterResizingColumn += new MouseEventHandler(OnAfterResizingColumn); + } + void OnAfterResizingColumn(object sender, MouseEventArgs e) + { + // This is to notify that component has changed. + // This is causing the code InitializeComponent code to be updated + RaiseComponentChanged(null, null, null); + } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + void OnComponentChanged(object sender, ComponentChangedEventArgs e) + { + // repaint the control when any properties have changed + if(Control != null) + Control.Invalidate(); + } + protected override bool GetHitTest(Point point) + { + // if mouse is over node, columns or scrollbar then return true + // which will cause the mouse event to be forwarded to the control + TreeListView tree = Control as TreeListView; + point = tree.PointToClient(point); + + Node node = tree.CalcHitNode(point); + if (node != null) + return true; + + TreelistView.HitInfo colinfo = tree.CalcColumnHit(point); + if ((int)(colinfo.HitType & HitInfo.eHitType.kColumnHeader) > 0) + return true; + + if (tree.HitTestScrollbar(point)) + return true; + return base.GetHitTest(point); + } + + protected override void PostFilterProperties(IDictionary properties) + { + //properties.Remove("Cursor"); + base.PostFilterProperties(properties); + } + } +} diff --git a/renderdocui/Controls/TreeListView/TreeListColumn.cs b/renderdocui/Controls/TreeListView/TreeListColumn.cs new file mode 100644 index 0000000000..b352d86bbf --- /dev/null +++ b/renderdocui/Controls/TreeListView/TreeListColumn.cs @@ -0,0 +1,624 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Diagnostics; + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Reflection; +using System.Windows.Forms; + +// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks +// and fixes for my purposes. +namespace TreelistView +{ + public class HitInfo + { + public enum eHitType + { + kColumnHeader = 0x0001, + kColumnHeaderResize = 0x0002, + } + + public eHitType HitType = 0; + public TreeListColumn Column = null; + } + + /// + /// DesignTimeVisible(false) prevents the columns from showing in the component tray (bottom of screen) + /// If the class implement IComponent it must also implement default (void) constructor and when overriding + /// the collection editors CreateInstance the return object must be used (if implementing IComponent), the reason + /// is that ISite is needed, and ISite is set when base.CreateInstance is called. + /// If no default constructor then the object will not be added to the collection in the initialize. + /// In addition if implementing IComponent then name and generatemember is shown in the property grid + /// Columns should just be added to the collection, no need for member, so no need to implement IComponent + /// + [DesignTimeVisible(false)] + [TypeConverter(typeof(ColumnConverter))] + public class TreeListColumn + { + TreeList.TextFormatting m_headerFormat = new TreeList.TextFormatting(); + TreeList.TextFormatting m_cellFormat = new TreeList.TextFormatting(); + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeList.TextFormatting HeaderFormat + { + get { return m_headerFormat; } + } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeList.TextFormatting CellFormat + { + get { return m_cellFormat; } + } + + TreeListColumnCollection m_owner = null; + Rectangle m_calculatedRect; + int m_visibleIndex = -1; + int m_colIndex = -1; + int m_width = 50; + string m_fieldName = string.Empty; + string m_caption = string.Empty; + + bool m_Moving = false; + + internal TreeListColumnCollection Owner + { + get { return m_owner; } + set { m_owner = value; } + } + internal Rectangle internalCalculatedRect + { + get { return m_calculatedRect; } + set { m_calculatedRect = value; } + } + internal int internalVisibleIndex + { + get { return m_visibleIndex; } + set { m_visibleIndex = value; } + } + internal int internalIndex + { + get { return m_colIndex; } + set { m_colIndex = value; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Moving + { + get { return m_Moving; } + set + { + m_Moving = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Rectangle CalculatedRect + { + get { return internalCalculatedRect; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public TreeListView TreeList + { + get + { + if (Owner == null) + return null; + return Owner.Owner; + } + } + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Font Font + { + get { return m_owner.Font; } + } + public int Width + { + get { return m_width; } + set + { + if (m_width == value) + return; + m_width = value; + if (m_owner != null && m_owner.DesignMode) + m_owner.RecalcVisibleColumsRect(); + } + } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Caption + { + get { return m_caption; } + set + { + m_caption = value; + if (m_owner != null) + m_owner.Invalidate(); + } + } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Fieldname + { + get { return m_fieldName; } + set + { + if (m_owner == null || m_owner.DesignMode == false) + throw new Exception("Fieldname can only be set at design time, Use Constructor to set programatically"); + if (value.Length == 0) + throw new Exception("empty Fieldname not value"); + if (m_owner[value] != null) + throw new Exception("fieldname already exist in collection"); + m_fieldName = value; + } + } + + public TreeListColumn(string fieldName) + { + m_fieldName = fieldName; + } + public TreeListColumn(string fieldName, string caption) + { + m_fieldName = fieldName; + m_caption = caption; + } + public TreeListColumn(string fieldName, string caption, int width) + { + m_fieldName = fieldName; + m_caption = caption; + m_width = width; + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int VisibleIndex + { + get { return internalVisibleIndex; } + set + { + if (m_owner != null) + m_owner.SetVisibleIndex(this, value); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Index + { + get { return internalIndex; } + } + public bool ishot = false; + public virtual void Draw(Graphics dc, ColumnHeaderPainter painter, Rectangle r) + { + painter.DrawHeader(dc, r, this, this.HeaderFormat, ishot, m_Moving); + } + + bool m_autoSize = false; + float m_autoSizeRatio = 100; + int m_autoSizeMinSize; + + [DefaultValue(false)] + public bool AutoSize + { + get { return m_autoSize; } + set { m_autoSize = value; } + } + [DefaultValue(100f)] + public float AutoSizeRatio + { + get { return m_autoSizeRatio; } + set { m_autoSizeRatio = value; } + } + public int AutoSizeMinSize + { + get { return m_autoSizeMinSize; } + set { m_autoSizeMinSize = value; } + } + int m_calculatedAutoSize; + internal int CalculatedAutoSize + { + get { return m_calculatedAutoSize; } + set { m_calculatedAutoSize = value; } + } + } + + [Description("This is the columns collection")] + //[TypeConverterAttribute(typeof(ColumnsTypeConverter))] + [Editor(typeof(ColumnCollectionEditor),typeof(System.Drawing.Design.UITypeEditor))] + public class TreeListColumnCollection : IList, IList + { + ColumnHeaderPainter m_painter; + TreeList.CollumnSetting m_options; + TreeListView m_owner; + List m_columns = new List(); + List m_visibleCols = new List(); + Dictionary m_columnMap = new Dictionary(); + + [Browsable(false)] + public TreeList.CollumnSetting Options + { + get { return m_options; } + } + [Browsable(false)] + public ColumnHeaderPainter Painter + { + get { return m_painter; } + set { m_painter = value; } + } + [Browsable(false)] + public TreeListView Owner + { + get { return m_owner; } + } + [Browsable(false)] + public Font Font + { + get { return m_owner.Font; } + } + [Browsable(false)] + public TreeListColumn[] VisibleColumns + { + get { return m_visibleCols.ToArray(); } + } + [Browsable(false)] + public int ColumnsWidth + { + get + { + int width = 0; + foreach (TreeListColumn col in m_visibleCols) + { + if (col.AutoSize) + width += col.CalculatedAutoSize; + else + width += col.Width; + } + return width; + } + } + public TreeListColumnCollection(TreeListView owner) + { + m_owner = owner; + m_options = new TreeList.CollumnSetting(owner); + m_painter = new ColumnHeaderPainter(owner); + } + public TreeListColumn this[int index] + { + get + { + return m_columns[index]; + } + set + { + m_columns[index] = value; + } + } + public TreeListColumn this[string fieldname] + { + get + { + TreeListColumn col; + m_columnMap.TryGetValue(fieldname, out col); + return col; + } + } + public void SetVisibleIndex(TreeListColumn col, int index) + { + m_visibleCols.Remove(col); + if (index >= 0) + { + if (index < m_visibleCols.Count) + m_visibleCols.Insert(index, col); + else + m_visibleCols.Add(col); + } + RecalcVisibleColumsRect(); + } + public HitInfo CalcHitInfo(Point point, int horzOffset) + { + HitInfo info = new HitInfo(); + info.Column = CalcHitColumn(point, horzOffset); + if ((info.Column != null) && (point.Y < Options.HeaderHeight)) + { + info.HitType |= HitInfo.eHitType.kColumnHeader; + int right = info.Column.CalculatedRect.Right - horzOffset; + if (info.Column.AutoSize == false || info.Column.internalIndex+1 < m_columns.Count) + { + if (point.X >= right - 4 && point.X <= right) + info.HitType |= HitInfo.eHitType.kColumnHeaderResize; + } + } + return info; + } + public TreeListColumn CalcHitColumn(Point point, int horzOffset) + { + if (point.X < Options.LeftMargin) + return null; + foreach (TreeListColumn col in m_visibleCols) + { + int left = col.CalculatedRect.Left - horzOffset; + int right = col.CalculatedRect.Right - horzOffset; + if (point.X >= left && point.X <= right) + return col; + } + return null; + } + public void RecalcVisibleColumsRect() + { + RecalcVisibleColumsRect(false); + } + public void RecalcVisibleColumsRect(bool isColumnResizing) + { + if (IsInitializing) + return; + int x = 0;//m_leftMargin; + if (m_owner.RowOptions.ShowHeader) + x = m_owner.RowOptions.HeaderWidth; + int y = 0; + int h = Options.HeaderHeight; + int index = 0; + foreach(TreeListColumn col in m_columns) + { + col.internalVisibleIndex = -1; + col.internalIndex = index++; + } + + // calculate size requierd by fix columns and auto adjusted columns + // at the same time calculate total ratio value + int widthFixedColumns = 0; + int widthAutoSizeColumns = 0; + float totalRatio = 0; + foreach (TreeListColumn col in m_visibleCols) + { + if (col.AutoSize) + { + widthAutoSizeColumns += col.AutoSizeMinSize; + totalRatio += col.AutoSizeRatio; + } + else + widthFixedColumns += col.Width; + } + + int clientWidth = m_owner.ClientRectangle.Width - m_owner.RowHeaderWidth(); + // find ratio 'unit' value + float remainingWidth = clientWidth - (widthFixedColumns + widthAutoSizeColumns); + float ratioUnit = 0; + if (totalRatio > 0 && remainingWidth > 0) + ratioUnit = remainingWidth / totalRatio; + + for (index = 0; index < m_visibleCols.Count; index++) + { + TreeListColumn col = m_visibleCols[index]; + int width = col.Width; + if (col.AutoSize) + { + // if doing column resizing then keep adjustable columns fixed at last width + if (m_options.FreezeWhileResizing && isColumnResizing) + width = col.CalculatedAutoSize; + else + width = Math.Max(10, col.AutoSizeMinSize + (int)Math.Round(ratioUnit * col.AutoSizeRatio - 1.0f)); + col.CalculatedAutoSize = width; + } + col.internalCalculatedRect = new Rectangle(x, y, width, h); + col.internalVisibleIndex = index; + x += width; + } + Invalidate(); + } + public void Draw(Graphics dc, Rectangle rect, int horzOffset) + { + foreach (TreeListColumn col in m_visibleCols) + { + Rectangle r = col.CalculatedRect; + r.X -= horzOffset; + if (r.Left > rect.Right) + break; + col.Draw(dc, m_painter, r); + } + // drwa row header filler + if (m_owner.RowOptions.ShowHeader) + { + Rectangle r = new Rectangle(0, 0, m_owner.RowOptions.HeaderWidth, Options.HeaderHeight); + m_painter.DrawHeaderFiller(dc, r); + } + } + public void AddRange(IEnumerable columns) + { + foreach (TreeListColumn col in columns) + Add(col); + } + /// + /// AddRange(Item[]) is required for the designer. + /// + /// + public void AddRange(TreeListColumn[] columns) + { + foreach (TreeListColumn col in columns) + Add(col); + } + public void Add(TreeListColumn item) + { + bool designmode = Owner.DesignMode; + if (!designmode) + { + Debug.Assert(m_columnMap.ContainsKey(item.Fieldname) == false); + Debug.Assert(item.Owner == null, "column.Owner == null"); + } + else + { + m_columns.Remove(item); + m_visibleCols.Remove(item); + } + + item.Owner = this; + m_columns.Add(item); + m_visibleCols.Add(item); + m_columnMap[item.Fieldname] = item; + RecalcVisibleColumsRect(); + //return item; + } + public void Clear() + { + m_columnMap.Clear(); + m_columns.Clear(); + m_visibleCols.Clear(); + } + public bool Contains(TreeListColumn item) + { + return m_columns.Contains(item); + } + [Browsable(false)] + public int Count + { + get { return m_columns.Count; } + } + [Browsable(false)] + public bool IsReadOnly + { + get { return false; } + } + #region IList Members + + public int IndexOf(TreeListColumn item) + { + return m_columns.IndexOf(item); + } + + public void Insert(int index, TreeListColumn item) + { + m_columns.Insert(index, item); + } + + public void RemoveAt(int index) + { + if (index >= 0 && index < m_columns.Count) + { + TreeListColumn col = m_columns[index]; + SetVisibleIndex(col, -1); + m_columnMap.Remove(col.Fieldname); + } + m_columns.RemoveAt(index); + } + + #endregion + #region ICollection Members + + + public void CopyTo(TreeListColumn[] array, int arrayIndex) + { + m_columns.CopyTo(array, arrayIndex); + } + + public bool Remove(TreeListColumn item) + { + SetVisibleIndex(item, -1); + m_columnMap.Remove(item.Fieldname); + return m_columns.Remove(item); + } + + #endregion + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return m_columns.GetEnumerator(); + } + + #endregion + #region IEnumerable Members + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + #endregion + #region IList Members + int IList.Add(object value) + { + Add((TreeListColumn)value); + return Count - 1; + } + bool IList.Contains(object value) + { + return Contains((TreeListColumn)value); + } + int IList.IndexOf(object value) + { + return IndexOf((TreeListColumn)value); + } + void IList.Insert(int index, object value) + { + Insert(index, (TreeListColumn)value); + } + + bool IList.IsFixedSize + { + get { return false; } + } + + void IList.Remove(object value) + { + Remove((TreeListColumn)value); + } + + object IList.this[int index] + { + get + { + throw new Exception("The method or operation is not implemented."); + } + set + { + throw new Exception("The method or operation is not implemented."); + } + } + #endregion + #region ICollection Members + + public void CopyTo(Array array, int index) + { + throw new Exception("The method or operation is not implemented."); + } + + public bool IsSynchronized + { + get { throw new Exception("The method or operation is not implemented."); } + } + + public object SyncRoot + { + get { throw new Exception("The method or operation is not implemented."); } + } + + #endregion + + internal bool DesignMode + { + get + { + if (m_owner != null) + return m_owner.DesignMode; + return false; + } + } + internal void Invalidate() + { + if (m_owner != null) + m_owner.Invalidate(); + } + bool IsInitializing = false; + internal void BeginInit() + { + IsInitializing = true; + } + internal void EndInit() + { + IsInitializing = false; + RecalcVisibleColumsRect(); + } + } +} diff --git a/renderdocui/Controls/TreeListView/TreeListNode.cs b/renderdocui/Controls/TreeListView/TreeListNode.cs new file mode 100644 index 0000000000..57f3000238 --- /dev/null +++ b/renderdocui/Controls/TreeListView/TreeListNode.cs @@ -0,0 +1,1016 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Diagnostics; + +// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks +// and fixes for my purposes. +namespace TreelistView +{ + public class Node + { + NodeCollection m_owner = null; + Node m_prevSibling = null; + Node m_nextSibling = null; + NodeCollection m_children = null; + bool m_hasChildren = false; + bool m_expanded = false; + Image m_image = null; + Image m_hoverImage = null; + int m_id = -1; + object m_tag = null; + bool m_bold = false; + bool m_italic = false; + Color m_backCol = Color.Transparent; + Color m_defbackCol = Color.Transparent; + + public TreeListView OwnerView = null; + + public Node Parent + { + get + { + if (m_owner != null) + return m_owner.Owner; + return null; + } + } + public Node PrevSibling + { + get { return m_prevSibling; } + } + public Node NextSibling + { + get { return m_nextSibling; } + } + public bool HasChildren + { + get + { + if (m_children != null && m_children.IsEmpty() == false) + return true; + return m_hasChildren; + } + set + { + m_hasChildren = value; + } + } + public Image Image + { + get { return m_image; } + set { m_image = value; } + } + public Image HoverImage + { + get { return m_hoverImage != null ? m_hoverImage : m_image; } + set { m_hoverImage = value; } + } + public virtual NodeCollection Owner + { + get { return m_owner; } + } + public virtual NodeCollection Nodes + { + get + { + if (m_children == null) + m_children = new NodeCollection(this); + return m_children; + } + } + public bool Expanded + { + get { return m_expanded && HasChildren; } + set + { + if (m_expanded == value) + return; + NodeCollection root = GetRootCollection(); + if (root != null) + root.NodetifyBeforeExpand(this, value); + + int oldcount = VisibleNodeCount; + m_expanded = value; + if (m_expanded) + UpdateOwnerTotalCount(1, VisibleNodeCount); + else + UpdateOwnerTotalCount(oldcount, 1); + + if (root != null) + root.NodetifyAfterExpand(this, value); + } + } + public void Collapse() + { + Expanded = false; + } + public void Expand() + { + Expanded = true; + } + public void ExpandAll() + { + Expanded = true; + if (HasChildren) + { + foreach (Node node in Nodes) + node.ExpandAll(); + } + } + public object Tag + { + get { return m_tag; } + set { m_tag = value; } + } + + public bool Italic + { + get { return m_italic; } + set { m_italic = value; } + } + public bool Bold + { + get { return m_bold; } + set { m_bold = value; } + } + public Color BackColor + { + get { return m_backCol; } + set { m_backCol = value; } + } + public Color DefaultBackColor + { + get { return m_defbackCol; } + set { m_defbackCol = value; } + } + + public Node() + { + m_data = new object[1]; + } + public Node(string text) + { + m_data = new object[1] {text}; + } + public Node(object[] fields) + { + SetData(fields); + } + public int Count + { + get + { + return m_data.Length; + } + } + object[] m_data = null; + public object this [string fieldname] + { + get + { + return this[Owner.FieldIndex(fieldname)]; + } + set + { + this[Owner.FieldIndex(fieldname)] = value; + } + } + public object this [int index] + { + get + { + if (index < 0 || index >= m_data.Length) + return null; + return m_data[index]; + } + set + { + AssertData(index); + m_data[index] = value; + } + } + public object[] GetData() + { + return m_data; + } + public void SetData(object[] fields) + { + m_data = new object[fields.Length]; + fields.CopyTo(m_data, 0); + } + public int VisibleNodeCount + { + get + { + // can not use Expanded property here as it returns false node has no children + if (m_expanded) + return m_childVisibleCount + 1; + return 1; + } + } + /// + /// MakeVisible will expand all the parents up the tree. + /// + public void MakeVisible() + { + Node parent = Parent; + while (parent != null) + { + parent.Expanded = true; + parent = parent.Parent; + } + } + /// + /// IsVisible returns true if all parents are expanded, else false + /// + public bool IsVisible() + { + Node parent = Parent; + while (parent != null) + { + // parent not expanded, so this node is not visible + if (parent.Expanded == false) + return false; + // parent not hooked up to a collection, so this node is not visible + if (parent.Owner == null) + return false; + parent = parent.Parent; + } + return true; + } + public Node GetRoot() + { + Node parent = this; + while (parent.Parent != null) + parent = parent.Parent; + return parent; + } + public NodeCollection GetRootCollection() + { + return GetRoot().Owner; + } + public string GetId() + { + StringBuilder sb = new StringBuilder(32); + Node node = this; + while (node != null) + { + node.Owner.UpdateChildIds(false); + if (node.Parent != null) + sb.Insert(0, "." + node.Id.ToString()); + else + sb.Insert(0, node.Id.ToString()); + node = node.Parent; + } + return sb.ToString(); + } + internal void InsertBefore(Node insertBefore, NodeCollection owner) + { + this.m_owner = owner; + Node next = insertBefore; + Node prev = null; + if (next != null) + { + prev = insertBefore.PrevSibling; + next.m_prevSibling = this; + } + if (prev != null) + prev.m_nextSibling = this; + + this.m_nextSibling = next; + this.m_prevSibling = prev; + UpdateOwnerTotalCount(0, VisibleNodeCount); + } + internal void InsertAfter(Node insertAfter, NodeCollection owner) + { + this.m_owner = owner; + Node prev = insertAfter; + Node next = null; + if (prev != null) + { + next = prev.NextSibling; + prev.m_nextSibling = this; + this.m_prevSibling = prev; + } + if (next != null) + next.m_prevSibling = this; + this.m_nextSibling = next; + UpdateOwnerTotalCount(0, VisibleNodeCount); + } + internal void Remove() + { + Node prev = this.PrevSibling; + Node next = this.NextSibling; + if (prev != null) + prev.m_nextSibling = next; + if (next != null) + next.m_prevSibling = prev; + + this.m_nextSibling = null; + this.m_prevSibling = null; + UpdateOwnerTotalCount(VisibleNodeCount, 0); + this.m_owner = null; + this.m_id = -1; + } + internal static void SetHasChildren(Node node, bool hasChildren) + { + if (node != null) + node.m_hasChildren = hasChildren; + } + public int NodeIndex + { + get { return Id;} + } + internal int Id + { + get + { + if (m_owner == null) + return -1; + m_owner.UpdateChildIds(false); + return m_id; + } + set { m_id = value; } + } + int m_childVisibleCount = 0; + void UpdateTotalCount(int oldValue, int newValue) + { + int old = VisibleNodeCount; + m_childVisibleCount += (newValue - oldValue); + UpdateOwnerTotalCount(old, VisibleNodeCount); + } + void UpdateOwnerTotalCount(int oldValue, int newValue) + { + if (Owner != null) + Owner.internalUpdateNodeCount(oldValue, newValue); + if (Parent != null) + Parent.UpdateTotalCount(oldValue, newValue); + } + + void AssertData(int index) + { + Debug.Assert(index >= 0, "index >= 0"); + Debug.Assert(index < m_data.Length, "index < m_data.Length"); + } + } + public class NodeCollection : IEnumerable + { + internal int m_version = 0; + int m_nextId = 0; + int m_IdDirty = 0; + + public TreeListView OwnerView = null; + + Node[] m_nodesInternal = null; + Node m_owner = null; + Node m_firstNode = null; + Node m_lastNode = null; + int m_count = 0; + public Node Owner + { + get { return m_owner; } + } + public Node FirstNode + { + get { return m_firstNode; } + } + public Node LastNode + { + get { return m_lastNode; } + } + public bool IsEmpty() + { + return m_firstNode == null; + } + public int Count + { + get { return m_count; } + } + public NodeCollection(Node owner) + { + m_owner = owner; + } + public virtual void Clear() + { + m_version++; + while (m_firstNode != null) + { + Node node = m_firstNode; + m_firstNode = node.NextSibling; + node.Remove(); + } + m_firstNode = null; + m_lastNode = null; + m_count = 0; + m_totalNodeCount = 0; + m_IdDirty = 0; + m_nextId = 0; + ClearInternalArray(); + Node.SetHasChildren(m_owner, m_count != 0); + } + public Node Add(string text) + { + return Add(new Node(text)); + } + public Node Add(object[] data) + { + return Add(new Node(data)); + } + public Node Add(Node newnode) + { + m_version++; + ClearInternalArray(); + Debug.Assert(newnode != null && newnode.Owner == null, "Add(Node newnode)"); + newnode.InsertAfter(m_lastNode, this); + m_lastNode = newnode; + if (m_firstNode == null) + m_firstNode = newnode; + newnode.Id = m_nextId++; + m_count++; + newnode.OwnerView = OwnerView; + return newnode; + } + public void Remove(Node node) + { + if (m_lastNode == null) + return; + m_version++; + ClearInternalArray(); + Debug.Assert(node != null && object.ReferenceEquals(node.Owner, this), "Remove(Node node)"); + + Node prev = node.PrevSibling; + Node next = node.NextSibling; + node.Remove(); + + if (prev == null) // first node + m_firstNode = next; + if (next == null) // last node + m_lastNode = prev; + m_IdDirty++; + m_count--; + Node.SetHasChildren(m_owner, m_count != 0); + } + public void InsertAfter(Node node, Node insertAfter) + { + m_version++; + ClearInternalArray(); + Debug.Assert(node.Owner == null, "node.Owner == null"); + if (insertAfter == null) + { + node.InsertBefore(m_firstNode, this); + m_firstNode = node; + } + else + { + node.InsertAfter(insertAfter, this); + } + if (m_lastNode == insertAfter) + { + m_lastNode = node; + node.Id = m_nextId++; + } + else + m_IdDirty++; + m_count++; + } + public Node this [int index] + { + get + { + Debug.Assert(index >= 0 && index < Count, "Index out of range"); + if (index >= Count) + throw new IndexOutOfRangeException(string.Format("Node this [{0}], Collection Count {1}", index, Count)); + EnsureInternalArray(); + return m_nodesInternal[index]; + } + } + + public Node NodeAtIndex(int index) + { + Node node = FirstNode; + while (index-- > 0 && node != null) + node = node.NextSibling; + return node; + } + public int GetNodeIndex(Node node) + { + int index = 0; + Node tmp = FirstNode; + while (tmp != null && tmp != node) + { + tmp = tmp.NextSibling; + index++; + } + if (tmp == null) + return -1; + return index; + } + public virtual int FieldIndex(string fieldname) + { + NodeCollection rootCollection = this; + while (rootCollection.Owner != null && rootCollection.Owner.Owner != null) + rootCollection = rootCollection.Owner.Owner; + return rootCollection.GetFieldIndex(fieldname); + } + public Node FirstVisibleNode() + { + return FirstNode; + } + public Node LastVisibleNode(bool recursive) + { + if (recursive) + return FindNodesBottomLeaf(LastNode, true); + return LastNode; + } + public virtual void NodetifyBeforeExpand(Node nodeToExpand, bool expanding) + { + } + public virtual void NodetifyAfterExpand(Node nodeToExpand, bool expanding) + { + } + internal void UpdateChildIds(bool recursive) + { + if (recursive == false && m_IdDirty == 0) + return; + m_IdDirty = 0; + m_nextId = 0; + foreach (Node node in this) + { + node.Id = m_nextId++; + if (node.HasChildren && recursive) + node.Nodes.UpdateChildIds(true); + } + } + protected virtual int GetFieldIndex(string fieldname) + { + return -1; + } + public Node slowGetNodeFromVisibleIndex(int index) + { + int startindex = index; + RecursiveNodesEnumerator iterator = new RecursiveNodesEnumerator(m_firstNode, true); + while (iterator.MoveNext()) + { + index--; + if (index < 0) + { + return iterator.Current as Node; + } + } + return null; + } + + public System.Collections.Generic.IEnumerator GetEnumerator() + { + var enm = new NodesEnumerator(m_firstNode); + + while (enm.MoveNext()) + { + yield return (Node)enm.Current; + } + } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return new NodesEnumerator(m_firstNode); + } + /// + /// TotalRowCount returns the total number of 'visible' nodes. Visible meaning visible for the + /// tree view, This is used to determine the size of the scroll bar + /// If 10 nodes each has 10 children and 9 of them are expanded, then 100 will be returned. + /// + /// + public virtual int slowTotalRowCount(bool mustBeVisible) + { + int cnt = 0; + RecursiveNodesEnumerator iterator = new RecursiveNodesEnumerator(this, mustBeVisible); + while (iterator.MoveNext()) + cnt++; + //Debug.Assert(cnt == m_totalNodeCount); + return cnt; + } + public virtual int VisibleNodeCount + { + get { return m_totalNodeCount; } + } + /// + /// Returns the number of pixels required to show all visible nodes + /// + + void EnsureInternalArray() + { + if (m_nodesInternal != null) + { + Debug.Assert(m_nodesInternal.Length == Count, "m_nodesInternal.Length == Count"); + return; + } + m_nodesInternal = new Node[Count]; + int index = 0; + foreach (Node xnode in this) + m_nodesInternal[index++] = xnode; + } + void ClearInternalArray() + { + m_nodesInternal = null; + } + + int m_totalNodeCount = 0; + protected virtual void UpdateNodeCount(int oldvalue, int newvalue) + { + m_totalNodeCount += (newvalue - oldvalue); + } + internal void internalUpdateNodeCount(int oldvalue, int newvalue) + { + UpdateNodeCount(oldvalue, newvalue); + } + internal class NodesEnumerator : IEnumerator + { + Node m_firstNode; + Node m_current = null; + public NodesEnumerator(Node firstNode) + { + m_firstNode = firstNode; + } + public object Current + { + get { return m_current; } + } + public bool MoveNext() + { + if (m_firstNode == null) + return false; + if (m_current == null) + { + m_current = m_firstNode; + return true; + } + m_current = m_current.NextSibling; + return m_current != null; + } + public void Reset() + { + m_current = null; + } + } + internal class RecursiveNodesEnumerator : IEnumerator + { + class NodeCollIterator : IEnumerator + { + Node m_firstNode; + Node m_current; + bool m_visible; + public NodeCollIterator(NodeCollection collection, bool mustBeVisible) + { + m_firstNode = collection.FirstNode; + m_visible = mustBeVisible; + } + public Node Current + { + get { return m_current; } + } + object IEnumerator.Current + { + get { return m_current; } + } + public bool MoveNext() + { + if (m_firstNode == null) + return false; + if (m_current == null) + { + m_current = m_firstNode; + return true; + } + if (m_current.HasChildren && m_current.Nodes.FirstNode != null) + { + if (m_visible == false || m_current.Expanded) + { + m_current = m_current.Nodes.FirstNode; + return true; + } + } + if (m_current == m_firstNode) + { + m_firstNode = m_firstNode.NextSibling; + m_current = m_firstNode; + return m_current != null; + } + if (m_current.NextSibling != null) + { + m_current = m_current.NextSibling; + return true; + } + + // search up the parent tree + while (m_current.Parent != null) + { + m_current = m_current.Parent; + // back at collection level, now go to next sibling + if (m_current == m_firstNode) + { + m_firstNode = m_firstNode.NextSibling; + m_current = m_firstNode; + return m_current != null; + } + if (m_current.NextSibling != null) + { + m_current = m_current.NextSibling; + return true; + } + } + m_current = null; + return false; + } + public void Reset() + { + m_current = null; + } + public void Dispose() + { + throw new Exception("The method or operation is not implemented."); + } + } + IEnumerator m_enumerator = null; + public RecursiveNodesEnumerator(Node firstNode, bool mustBeVisible) + { + m_enumerator = new ForwardNodeEnumerator(firstNode, mustBeVisible); + } + public RecursiveNodesEnumerator(NodeCollection collection, bool mustBeVisible) + { + m_enumerator = new NodeCollIterator(collection, mustBeVisible); + } + public Node Current + { + get { return m_enumerator.Current; } + } + object IEnumerator.Current + { + get { return m_enumerator.Current; } + } + public bool MoveNext() + { + return m_enumerator.MoveNext(); + } + public void Reset() + { + m_enumerator.Reset(); + } + public void Dispose() + { + m_enumerator.Dispose(); + } + } + internal class ForwardNodeEnumerator : IEnumerator + { + Node m_firstNode; + Node m_current; + bool m_visible; + public ForwardNodeEnumerator(Node firstNode, bool mustBeVisible) + { + m_firstNode = firstNode; + m_visible = mustBeVisible; + } + public Node Current + { + get { return m_current; } + } + public void Dispose() + { + } + object IEnumerator.Current + { + get { return m_current; } + } + public bool MoveNext() + { + if (m_firstNode == null) + return false; + if (m_current == null) + { + m_current = m_firstNode; + return true; + } + if (m_current.HasChildren && m_current.Nodes.FirstNode != null) + { + if (m_visible == false || m_current.Expanded) + { + m_current = m_current.Nodes.FirstNode; + return true; + } + } + if (m_current.NextSibling != null) + { + m_current = m_current.NextSibling; + return true; + } + // search up the paret tree until we find a parent with a sibling + while (m_current.Parent != null && m_current.Parent.NextSibling == null) + { + m_current = m_current.Parent; + } + + if (m_current.Parent != null && m_current.Parent.NextSibling != null) + { + m_current = m_current.Parent.NextSibling; + return true; + } + m_current = null; + return false; + } + public void Reset() + { + m_current = m_firstNode; + } + } + internal class ReverseNodeEnumerator : IEnumerator + { + Node m_firstNode; + Node m_current; + bool m_visible; + public ReverseNodeEnumerator(Node firstNode, bool mustBeVisible) + { + m_firstNode = firstNode; + m_visible = mustBeVisible; + } + public Node Current + { + get { return m_current; } + } + public void Dispose() + { + } + object IEnumerator.Current + { + get { return m_current; } + } + public bool MoveNext() + { + if (m_firstNode == null) + return false; + if (m_current == null) + { + m_current = m_firstNode; + return true; + } + if (m_current.PrevSibling != null) + { + m_current = FindNodesBottomLeaf(m_current.PrevSibling, m_visible); + return true; + } + if (m_current.Parent != null) + { + m_current = m_current.Parent; + return true; + } + m_current = null; + return false; + } + public void Reset() + { + m_current = m_firstNode; + } + } + + public static Node GetNextNode(Node startingNode, int searchOffset) + { + if (searchOffset == 0) + return startingNode; + if (searchOffset > 0) + { + ForwardNodeEnumerator iterator = new ForwardNodeEnumerator(startingNode, true); + while (searchOffset-- >= 0 && iterator.MoveNext()); + return iterator.Current; + } + if (searchOffset < 0) + { + ReverseNodeEnumerator iterator = new ReverseNodeEnumerator(startingNode, true); + while (searchOffset++ <= 0 && iterator.MoveNext()); + return iterator.Current; + } + return null; + } + + public static IEnumerable ReverseNodeIterator(Node firstNode, Node lastNode, bool mustBeVisible) + { + bool m_done = false; + ReverseNodeEnumerator iterator = new ReverseNodeEnumerator(firstNode, mustBeVisible); + while (iterator.MoveNext()) + { + if (m_done) + break; + if (iterator.Current == lastNode) + m_done = true; + yield return iterator.Current; + } + } + public static IEnumerable ForwardNodeIterator(Node firstNode, Node lastNode, bool mustBeVisible) + { + bool m_done = false; + ForwardNodeEnumerator iterator = new ForwardNodeEnumerator(firstNode, mustBeVisible); + while (iterator.MoveNext()) + { + if (m_done) + break; + if (iterator.Current == lastNode) + m_done = true; + yield return iterator.Current; + } + } + public static IEnumerable ForwardNodeIterator(Node firstNode, bool mustBeVisible) + { + ForwardNodeEnumerator iterator = new ForwardNodeEnumerator(firstNode, mustBeVisible); + while (iterator.MoveNext()) + yield return iterator.Current; + } + public static int GetVisibleNodeIndex(Node node) + { + if (node == null || node.IsVisible() == false || node.GetRootCollection() == null) + return -1; + + // Finding the node index is done by searching up the tree and use the visible node count from each node. + // First all previous siblings are searched, then when first sibling in the node collection is reached + // the node is switch to the parent node and the again a search is done up the sibling list. + // This way only higher up the tree are being iterated while nodes at the same level are skipped. + // Worst case scenario is if all nodes are at the same level. In that case the search is a linear search. + + // adjust count for the visible count of the current node. + int count = -node.VisibleNodeCount; + while (node != null) + { + count += node.VisibleNodeCount; + if (node.PrevSibling != null) + node = node.PrevSibling; + else + { + node = node.Parent; + if (node != null) + count -= node.VisibleNodeCount - 1; // -1 is for the node itself + } + } + return count; + } + public static Node FindNodesBottomLeaf(Node node, bool mustBeVisible) + { + if (mustBeVisible && node.Expanded == false) + return node; + if (node.HasChildren == false || node.Nodes.LastNode == null) + return node; + node = node.Nodes.LastNode; + return FindNodesBottomLeaf(node, mustBeVisible); + } + } + public class NodesSelection : IEnumerable + { + List m_nodes = new List(); + Dictionary m_nodesMap = new Dictionary(); + public void Clear() + { + m_nodes.Clear(); + m_nodesMap.Clear(); + } + public System.Collections.Generic.IEnumerator GetEnumerator() + { + foreach (var n in m_nodes) + { + yield return n; + } + } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return m_nodes.GetEnumerator(); + } + public Node this[int index] + { + get { return m_nodes[index]; } + } + public int Count + { + get { return m_nodes.Count; } + } + public void Add(Node node) + { + m_nodes.Add(node); + m_nodesMap.Add(node, 0); + } + public void Remove(Node node) + { + m_nodes.Remove(node); + m_nodesMap.Remove(node); + } + public bool Contains(Node node) + { + return m_nodesMap.ContainsKey(node); + } + + public IList GetSortedNodes() + { + SortedList list = new SortedList(); + foreach (Node node in m_nodes) + list.Add(node.GetId(), node); + return list.Values; + } + + } +} diff --git a/renderdocui/Controls/TreeListView/TreeListOptions.cs b/renderdocui/Controls/TreeListView/TreeListOptions.cs new file mode 100644 index 0000000000..680b746070 --- /dev/null +++ b/renderdocui/Controls/TreeListView/TreeListOptions.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Drawing; +using System.Windows.Forms; + +// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks +// and fixes for my purposes. +namespace TreelistView.TreeList +{ + [TypeConverterAttribute(typeof(OptionsSettingTypeConverter))] + public class TextFormatting + { + ContentAlignment m_alignment = ContentAlignment.MiddleLeft; + Color m_foreColor = SystemColors.ControlText; + Color m_backColor = Color.Transparent; + Padding m_padding = new Padding(0,0,0,0); + public TextFormatFlags GetFormattingFlags() + { + TextFormatFlags flags = 0; + switch (TextAlignment) + { + case ContentAlignment.TopLeft: + flags = TextFormatFlags.Top | TextFormatFlags.Left; + break; + case ContentAlignment.TopCenter: + flags = TextFormatFlags.Top | TextFormatFlags.HorizontalCenter; + break; + case ContentAlignment.TopRight: + flags = TextFormatFlags.Top | TextFormatFlags.Right; + break; + case ContentAlignment.MiddleLeft: + flags = TextFormatFlags.VerticalCenter | TextFormatFlags.Left; + break; + case ContentAlignment.MiddleCenter: + flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter; + break; + case ContentAlignment.MiddleRight: + flags = TextFormatFlags.VerticalCenter | TextFormatFlags.Right; + break; + case ContentAlignment.BottomLeft: + flags = TextFormatFlags.Bottom | TextFormatFlags.Left; + break; + case ContentAlignment.BottomCenter: + flags = TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter; + break; + case ContentAlignment.BottomRight: + flags = TextFormatFlags.Bottom | TextFormatFlags.Right; + break; + } + return flags; + } + + [DefaultValue(typeof(Padding), "0,0,0,0")] + public Padding Padding + { + get { return m_padding; } + set { m_padding = value; } + } + [DefaultValue(typeof(ContentAlignment), "MiddleLeft")] + public ContentAlignment TextAlignment + { + get { return m_alignment; } + set { m_alignment = value; } + } + [DefaultValue(typeof(Color), "ControlText")] + public Color ForeColor + { + get { return m_foreColor; } + set { m_foreColor = value; } + } + [DefaultValue(typeof(Color), "Transparent")] + public Color BackColor + { + get { return m_backColor; } + set { m_backColor = value; } + } + public TextFormatting() + { + } + public TextFormatting(TextFormatting aCopy) + { + m_alignment = aCopy.m_alignment; + m_foreColor = aCopy.m_foreColor; + m_backColor = aCopy.m_backColor; + m_padding = aCopy.m_padding; + } + } + + [TypeConverterAttribute(typeof(OptionsSettingTypeConverter))] + public class ViewSetting + { + TreeListView m_owner; + BorderStyle m_borderStyle = BorderStyle.None; + int m_indent = 16; + bool m_showLine = true; + bool m_showPlusMinus = true; + bool m_showGridLines = true; + bool m_rearrangeableColumns = false; + bool m_hoverHand = true; + + [Category("Behavior")] + [DefaultValue(typeof(int), "16")] + public int Indent + { + get { return m_indent; } + set + { + m_indent = value; + m_owner.Invalidate(); + } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "True")] + public bool ShowLine + { + get { return m_showLine; } + set + { + m_showLine = value; + m_owner.Invalidate(); + } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "True")] + public bool ShowPlusMinus + { + get { return m_showPlusMinus; } + set + { + m_showPlusMinus = value; + m_owner.Invalidate(); + } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "True")] + public bool ShowGridLines + { + get { return m_showGridLines; } + set + { + m_showGridLines = value; + m_owner.Invalidate(); + } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "False")] + public bool UserRearrangeableColumns + { + get { return m_rearrangeableColumns; } + set + { + m_rearrangeableColumns = value; + } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "True")] + public bool HoverHandTreeColumn + { + get { return m_hoverHand; } + set + { + m_hoverHand = value; + } + } + + [Category("Appearance")] + [DefaultValue(typeof(BorderStyle), "None")] + public BorderStyle BorderStyle + { + get { return m_borderStyle; } + set + { + if (m_borderStyle != value) + { + m_borderStyle = value; + m_owner.internalUpdateStyles(); + m_owner.Invalidate(); + } + } + } + + public ViewSetting(TreeListView owner) + { + m_owner = owner; + } + } + + [TypeConverterAttribute(typeof(OptionsSettingTypeConverter))] + public class CollumnSetting + { + bool m_FreezeWhileResizing = false; + int m_leftMargin = 5; + int m_headerHeight = 20; + TreeListView m_owner; + + [DefaultValue(false)] + public bool FreezeWhileResizing + { + get { return m_FreezeWhileResizing; } + set + { + m_FreezeWhileResizing = value; + } + } + [DefaultValue(5)] + public int LeftMargin + { + get { return m_leftMargin; } + set + { + m_leftMargin = value; + m_owner.Columns.RecalcVisibleColumsRect(); + m_owner.Invalidate(); + } + } + [DefaultValue(20)] + public int HeaderHeight + { + get { return m_headerHeight; } + set + { + m_headerHeight = value; + m_owner.Columns.RecalcVisibleColumsRect(); + m_owner.Invalidate(); + } + } + public CollumnSetting(TreeListView owner) + { + m_owner = owner; + } + } + + [TypeConverterAttribute(typeof(OptionsSettingTypeConverter))] + public class RowSetting + { + TreeListView m_owner; + bool m_showHeader = true; + bool m_hoverHighlight = false; + int m_headerWidth = 15; + int m_itemHeight = 16; + [DefaultValue(true)] + public bool ShowHeader + { + get { return m_showHeader; } + set + { + if (m_showHeader == value) + return; + m_showHeader = value; + m_owner.Columns.RecalcVisibleColumsRect(); + m_owner.Invalidate(); + } + } + [DefaultValue(false)] + public bool HoverHighlight + { + get { return m_hoverHighlight; } + set + { + if (m_hoverHighlight == value) + return; + m_hoverHighlight = value; + m_owner.Invalidate(); + } + } + [DefaultValue(15)] + public int HeaderWidth + { + get { return m_headerWidth; } + set + { + if (m_headerWidth == value) + return; + m_headerWidth = value; + m_owner.Columns.RecalcVisibleColumsRect(); + m_owner.Invalidate(); + } + } + + [Category("Behavior")] + [DefaultValue(typeof(int), "16")] + public int ItemHeight + { + get { return m_itemHeight; } + set + { + m_itemHeight = value; + m_owner.Invalidate(); + } + } + + public RowSetting(TreeListView owner) + { + m_owner = owner; + } + } + + class OptionsSettingTypeConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(ViewSetting)) + return true; + if (destinationType == typeof(RowSetting)) + return true; + if (destinationType == typeof(CollumnSetting)) + return true; + if (destinationType == typeof(TextFormatting)) + return true; + return base.CanConvertTo(context, destinationType); + } + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(ViewSetting)) + return "(View Options)"; + if (destinationType == typeof(string) && value.GetType() == typeof(RowSetting)) + return "(Row Header Options)"; + if (destinationType == typeof(string) && value.GetType() == typeof(CollumnSetting)) + return "(Columns Options)"; + if (destinationType == typeof(string) && value.GetType() == typeof(TextFormatting)) + return "(Formatting)"; + return base.ConvertTo(context, culture, value, destinationType); + } + } +} diff --git a/renderdocui/Controls/TreeListView/TreeListPainter.cs b/renderdocui/Controls/TreeListView/TreeListPainter.cs new file mode 100644 index 0000000000..76ef0c927a --- /dev/null +++ b/renderdocui/Controls/TreeListView/TreeListPainter.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Text; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; +using System.Runtime.InteropServices; + +// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks +// and fixes for my purposes. +namespace TreelistView +{ + public class VisualStyleItemBackground // can't find system provided visual style for this. + { + [StructLayout(LayoutKind.Sequential)] + public class RECT + { + public int left; + public int top; + public int right; + public int bottom; + public RECT() + { + } + + public RECT(Rectangle r) + { + this.left = r.X; + this.top = r.Y; + this.right = r.Right; + this.bottom = r.Bottom; + } + } + + [DllImport("uxtheme.dll", CharSet=CharSet.Auto)] + public static extern int DrawThemeBackground(IntPtr hTheme, IntPtr hdc, int partId, int stateId, [In] RECT pRect, [In] RECT pClipRect); + + [DllImport("uxtheme.dll", CharSet=CharSet.Auto)] + public static extern IntPtr OpenThemeData(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszClassList); + + [DllImport("uxtheme.dll", CharSet=CharSet.Auto)] + public static extern int CloseThemeData(IntPtr hTheme); + + //http://www.ookii.org/misc/vsstyle.h + //http://msdn2.microsoft.com/en-us/library/bb773210(VS.85).aspx + enum ITEMSTATES + { + LBPSI_HOT = 1, + LBPSI_HOTSELECTED = 2, + LBPSI_SELECTED = 3, + LBPSI_SELECTEDNOTFOCUS = 4, + }; + + enum LISTBOXPARTS + { + LBCP_BORDER_HSCROLL = 1, + LBCP_BORDER_HVSCROLL = 2, + LBCP_BORDER_NOSCROLL = 3, + LBCP_BORDER_VSCROLL = 4, + LBCP_ITEM = 5, + }; + + public enum Style + { + Normal, + Inactive, // when not focused + } + Style m_style; + public VisualStyleItemBackground(Style style) + { + m_style = style; + } + public void DrawBackground(Control owner, Graphics dc, Rectangle r, Color col) + { + /* + IntPtr themeHandle = OpenThemeData(owner.Handle, "Explorer"); + if (themeHandle != IntPtr.Zero) + { + DrawThemeBackground(themeHandle, dc.GetHdc(), (int)LISTBOXPARTS.LBCP_ITEM, (int)ITEMSTATES.LBPSI_SELECTED, new RECT(r), new RECT(r)); + dc.ReleaseHdc(); + CloseThemeData(themeHandle); + return; + } + */ + + Pen pen = new Pen(col); + GraphicsPath path = new GraphicsPath(); + path.AddLine(r.Left + 2, r.Top, r.Right - 2, r.Top); + path.AddLine(r.Right, r.Top + 2, r.Right, r.Bottom - 2); + path.AddLine(r.Right - 2, r.Bottom, r.Left + 2, r.Bottom); + path.AddLine(r.Left, r.Bottom - 2, r.Left, r.Top + 2); + path.CloseFigure(); + dc.DrawPath(pen, path); + + //r.Inflate(-1, -1); + LinearGradientBrush brush = new LinearGradientBrush(r, Color.FromArgb(120, col), col, 90); + dc.FillRectangle(brush, r); + // for some reason in some cases the 'white' end of the gradient brush is drawn with the starting color + // therefore this redraw of the 'top' line of the rectangle + //dc.DrawLine(Pens.White, r.Left + 1, r.Top, r.Right - 1, r.Top); + + pen.Dispose(); + brush.Dispose(); + path.Dispose(); + } + } + + public delegate string CellDataToString(TreeListColumn column, object data); + + public class CellPainter + { + public static Rectangle AdjustRectangle(Rectangle r, Padding padding) + { + r.X += padding.Left; + r.Width -= padding.Left + padding.Right; + r.Y += padding.Top; + r.Height -= padding.Top + padding.Bottom; + return r; + } + protected TreeListView m_owner; + protected CellDataToString m_converter = null; + + public CellDataToString CellDataConverter + { + get { return m_converter; } + set { m_converter = value; } + } + + public CellPainter(TreeListView owner) + { + m_owner = owner; + } + public virtual void DrawSelectionBackground(Graphics dc, Rectangle nodeRect, Node node) + { + Point mousePoint = m_owner.PointToClient(Cursor.Position); + Node hoverNode = m_owner.CalcHitNode(mousePoint); + + if (m_owner.NodesSelection.Contains(node) || m_owner.FocusedNode == node) + { + Color col = m_owner.Focused ? SystemColors.Highlight : SystemColors.ControlLight; + + if (!Application.RenderWithVisualStyles) + { + // have to fill the solid background only before the node is painted + dc.FillRectangle(SystemBrushes.FromSystemColor(col), nodeRect); + } + else + { + col = m_owner.Focused ? SystemColors.Highlight : Color.FromArgb(180, SystemColors.ControlDark); + + // have to draw the transparent background after the node is painted + VisualStyleItemBackground.Style style = VisualStyleItemBackground.Style.Normal; + if (m_owner.Focused == false) + style = VisualStyleItemBackground.Style.Inactive; + VisualStyleItemBackground rendere = new VisualStyleItemBackground(style); + rendere.DrawBackground(m_owner, dc, nodeRect, col); + } + } + else if (hoverNode == node && m_owner.RowOptions.HoverHighlight) + { + Color col = SystemColors.ControlLight; + + if (!Application.RenderWithVisualStyles) + { + // have to fill the solid background only before the node is painted + dc.FillRectangle(SystemBrushes.FromSystemColor(col), nodeRect); + } + else + { + // have to draw the transparent background after the node is painted + VisualStyleItemBackground.Style style = VisualStyleItemBackground.Style.Normal; + if (m_owner.Focused == false) + style = VisualStyleItemBackground.Style.Inactive; + VisualStyleItemBackground rendere = new VisualStyleItemBackground(style); + rendere.DrawBackground(m_owner, dc, nodeRect, col); + } + } + + if (m_owner.Focused && (m_owner.FocusedNode == node)) + { + nodeRect.Height += 1; + nodeRect.Inflate(-1,-1); + ControlPaint.DrawFocusRectangle(dc, nodeRect); + } + } + public virtual void PaintCellBackground(Graphics dc, + Rectangle cellRect, + Node node, + TreeListColumn column, + TreeList.TextFormatting format, + object data) + { + Color c = Color.Transparent; + + Point mousePoint = m_owner.PointToClient(Cursor.Position); + Node hoverNode = m_owner.CalcHitNode(mousePoint); + + if (format.BackColor != Color.Transparent) + c = format.BackColor; + + if (node.BackColor != Color.Transparent) + c = node.BackColor; + + if (!m_owner.NodesSelection.Contains(node) && m_owner.FocusedNode != node && + !(hoverNode == node && m_owner.RowOptions.HoverHighlight) && + node.DefaultBackColor != Color.Transparent) + c = node.DefaultBackColor; + + if (c != Color.Transparent) + { + Rectangle r = cellRect; + r.X -= Math.Max(0, column.CalculatedRect.Width - cellRect.Width); + r.Width += Math.Max(0, column.CalculatedRect.Width - cellRect.Width); + SolidBrush brush = new SolidBrush(c); + dc.FillRectangle(brush, r); + brush.Dispose(); + } + } + + public virtual void PaintCellText(Graphics dc, + Rectangle cellRect, + Node node, + TreeListColumn column, + TreeList.TextFormatting format, + object data) + { + if (data != null) + { + cellRect = AdjustRectangle(cellRect, format.Padding); + //dc.DrawRectangle(Pens.Black, cellRect); + + Color color = format.ForeColor; + if (m_owner.FocusedNode == node && Application.RenderWithVisualStyles == false && m_owner.Focused) + color = SystemColors.HighlightText; + TextFormatFlags flags= TextFormatFlags.EndEllipsis | format.GetFormattingFlags(); + + Font f = m_owner.Font; + Font disposefont = null; + + if(node.Bold && node.Italic) + disposefont = f = new Font(f, FontStyle.Bold|FontStyle.Italic); + else if (node.Bold) + disposefont = f = new Font(f, FontStyle.Bold); + else if (node.Italic) + disposefont = f = new Font(f, FontStyle.Italic); + + string datastring = ""; + + if(m_converter != null) + datastring = m_converter(column, data); + else + datastring = data.ToString(); + + TextRenderer.DrawText(dc, datastring, f, cellRect, color, flags); + + if (disposefont != null) disposefont.Dispose(); + } + } + public virtual void PaintCellPlusMinus(Graphics dc, Rectangle glyphRect, Node node, TreeListColumn column, TreeList.TextFormatting format) + { + if (!Application.RenderWithVisualStyles) + { + // find square rect first + int diff = glyphRect.Height-glyphRect.Width; + glyphRect.Y += diff/2; + glyphRect.Height -= diff; + + // draw 8x8 box centred + while (glyphRect.Height > 8) + { + glyphRect.Height -= 2; + glyphRect.Y += 1; + glyphRect.X += 1; + } + + // make a box + glyphRect.Width = glyphRect.Height; + + // clear first + SolidBrush brush = new SolidBrush(format.BackColor); + if (format.BackColor == Color.Transparent) + brush = new SolidBrush(m_owner.BackColor); + dc.FillRectangle(brush, glyphRect); + brush.Dispose(); + + // draw outline + Pen p = new Pen(SystemColors.ControlDark); + dc.DrawRectangle(p, glyphRect); + p.Dispose(); + + p = new Pen(SystemColors.ControlText); + + // reduce box for internal lines + glyphRect.X += 2; glyphRect.Y += 2; + glyphRect.Width -= 4; glyphRect.Height -= 4; + + // draw horizontal line always + dc.DrawLine(p, glyphRect.X, glyphRect.Y + glyphRect.Height / 2, glyphRect.X + glyphRect.Width, glyphRect.Y + glyphRect.Height / 2); + + // draw vertical line if this should be a + + if(!node.Expanded) + dc.DrawLine(p, glyphRect.X + glyphRect.Width / 2, glyphRect.Y, glyphRect.X + glyphRect.Width / 2, glyphRect.Y + glyphRect.Height); + + p.Dispose(); + return; + } + + VisualStyleElement element = VisualStyleElement.TreeView.Glyph.Closed; + if (node.Expanded) + element = VisualStyleElement.TreeView.Glyph.Opened; + + if (VisualStyleRenderer.IsElementDefined(element)) + { + VisualStyleRenderer renderer = new VisualStyleRenderer(element); + renderer.DrawBackground(dc, glyphRect); + } + } + } + public class ColumnHeaderPainter + { + TreeListView m_owner; + public ColumnHeaderPainter(TreeListView owner) + { + m_owner = owner; + } + + public static Rectangle AdjustRectangle(Rectangle r, Padding padding) + { + r.X += padding.Left; + r.Width -= padding.Left + padding.Right; + r.Y += padding.Top; + r.Height -= padding.Top + padding.Bottom; + return r; + } + public virtual void DrawHeaderFiller(Graphics dc, Rectangle r) + { + if (!Application.RenderWithVisualStyles) + { + ControlPaint.DrawButton(dc, r, ButtonState.Flat); + return; + } + VisualStyleElement element = VisualStyleElement.Header.Item.Normal; + if (VisualStyleRenderer.IsElementDefined(element)) + { + VisualStyleRenderer renderer = new VisualStyleRenderer(element); + renderer.DrawBackground(dc, r); + } + } + public void DrawHeaderText(Graphics dc, Rectangle cellRect, TreeListColumn column, TreeList.TextFormatting format) + { + Color color = format.ForeColor; + TextFormatFlags flags = TextFormatFlags.EndEllipsis | format.GetFormattingFlags(); + TextRenderer.DrawText(dc, column.Caption, column.Font, cellRect, color, flags); + } + public virtual void DrawHeader(Graphics dc, Rectangle cellRect, TreeListColumn column, TreeList.TextFormatting format, bool isHot, bool highlight) + { + Rectangle textRect = AdjustRectangle(cellRect, format.Padding); + if (!Application.RenderWithVisualStyles) + { + ControlPaint.DrawButton(dc, cellRect, + m_owner.ViewOptions.UserRearrangeableColumns && highlight ? ButtonState.Pushed : ButtonState.Flat); + DrawHeaderText(dc, textRect, column, format); + return; + } + VisualStyleElement element = VisualStyleElement.Header.Item.Normal; + if (isHot || highlight) + element = VisualStyleElement.Header.Item.Hot; + if (VisualStyleRenderer.IsElementDefined(element)) + { + VisualStyleRenderer renderer = new VisualStyleRenderer(element); + renderer.DrawBackground(dc, cellRect); + + if (format.BackColor != Color.Transparent) + { + SolidBrush brush = new SolidBrush(format.BackColor); + dc.FillRectangle(brush, cellRect); + brush.Dispose(); + } + //dc.DrawRectangle(Pens.Black, cellRect); + + DrawHeaderText(dc, textRect, column, format); + } + } + public virtual void DrawVerticalGridLines(TreeListColumnCollection columns, Graphics dc, Rectangle r, int hScrollOffset) + { + foreach (TreeListColumn col in columns.VisibleColumns) + { + int rightPos = col.CalculatedRect.Right - hScrollOffset; + if (rightPos < 0) + continue; + Pen p = new Pen(columns.Owner.GridLineColour); + dc.DrawLine(p, rightPos, r.Top, rightPos, r.Bottom); + p.Dispose(); + } + } + } + public class RowPainter + { + public void DrawHeader(Graphics dc, Rectangle r, bool isHot) + { + if (!Application.RenderWithVisualStyles) + { + if (r.Width > 0 && r.Height > 0) + { + ControlPaint.DrawButton(dc, r, ButtonState.Flat); + } + return; + } + + VisualStyleElement element = VisualStyleElement.Header.Item.Normal; + if (isHot) + element = VisualStyleElement.Header.Item.Hot; + if (VisualStyleRenderer.IsElementDefined(element)) + { + VisualStyleRenderer renderer = new VisualStyleRenderer(element); + renderer.DrawBackground(dc, r); + } + } + public void DrawHorizontalGridLine(Graphics dc, Rectangle r, Color col) + { + Pen p = new Pen(col); + dc.DrawLine(p, r.Left, r.Bottom, r.Right, r.Bottom); + p.Dispose(); + } + } +} diff --git a/renderdocui/Controls/TreeListView/TreeListView.cs b/renderdocui/Controls/TreeListView/TreeListView.cs new file mode 100644 index 0000000000..982a128b7e --- /dev/null +++ b/renderdocui/Controls/TreeListView/TreeListView.cs @@ -0,0 +1,1362 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Design; +using System.Windows.Forms; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Windows.Forms.VisualStyles; + +// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks +// and fixes for my purposes. +namespace TreelistView +{ + [Designer(typeof(TreeListViewDesigner))] + public class TreeListView : Control, ISupportInitialize + { + public event TreeViewEventHandler AfterSelect; + protected virtual void OnAfterSelect(Node node) + { + raiseAfterSelect(node); + } + protected virtual void raiseAfterSelect(Node node) + { + if (AfterSelect != null && node != null) + AfterSelect(this, new TreeViewEventArgs(null)); + } + + public delegate void NotifyBeforeExpandHandler(Node node, bool isExpanding); + public event NotifyBeforeExpandHandler NotifyBeforeExpand; + public virtual void OnNotifyBeforeExpand(Node node, bool isExpanding) + { + raiseNotifyBeforeExpand(node, isExpanding); + } + protected virtual void raiseNotifyBeforeExpand(Node node, bool isExpanding) + { + if (NotifyBeforeExpand != null) + NotifyBeforeExpand(node, isExpanding); + } + + public delegate void NotifyAfterHandler(Node node, bool isExpanding); + public event NotifyAfterHandler NotifyAfterExpand; + public virtual void OnNotifyAfterExpand(Node node, bool isExpanded) + { + raiseNotifyAfterExpand(node, isExpanded); + } + protected virtual void raiseNotifyAfterExpand(Node node, bool isExpanded) + { + if (NotifyAfterExpand != null) + NotifyAfterExpand(node, isExpanded); + } + + public delegate void NodeDoubleClickedHandler(Node node); + public event NodeDoubleClickedHandler NodeDoubleClicked; + public virtual void OnNodeDoubleClicked(Node node) + { + raiseNodeDoubleClicked(node); + } + protected virtual void raiseNodeDoubleClicked(Node node) + { + if (NodeDoubleClicked != null) + NodeDoubleClicked(node); + } + + public delegate void NodeClickedHandler(Node node); + public event NodeClickedHandler NodeClicked; + public virtual void OnNodeClicked(Node node) + { + raiseNodeClicked(node); + } + protected virtual void raiseNodeClicked(Node node) + { + if (NodeClicked != null) + NodeClicked(node); + } + + TreeListViewNodes m_nodes; + TreeListColumnCollection m_columns; + TreeList.RowSetting m_rowSetting; + TreeList.ViewSetting m_viewSetting; + + Color m_GridLineColour = SystemColors.Control; + Image m_SelectedImage = null; + + [Category("Columns")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeListColumnCollection Columns + { + get { return m_columns; } + } + + [Category("Options")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeList.CollumnSetting ColumnsOptions + { + get { return m_columns.Options; } + } + + [Category("Options")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeList.RowSetting RowOptions + { + get { return m_rowSetting; } + } + + [Category("Options")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeList.ViewSetting ViewOptions + { + get { return m_viewSetting; } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "True")] + public bool MultiSelect + { + get { return m_multiSelect; } + set { m_multiSelect = value; } + } + + [Category("Behavior")] + [DefaultValue(typeof(int), "0")] + public int TreeColumn + { + get { return m_treeColumn; } + set { m_treeColumn = value; } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "False")] + public bool AlwaysDisplayVScroll + { + get { return m_vScrollAlways; } + set { m_vScrollAlways = value; } + } + + [Category("Behavior")] + [DefaultValue(typeof(bool), "False")] + public bool AlwaysDisplayHScroll + { + get { return m_hScrollAlways; } + set { m_hScrollAlways = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Image), null)] + public Image SelectedImage + { + get { return m_SelectedImage; } + set { m_SelectedImage = value; } + } + + [DefaultValue(typeof(Color), "Window")] + public new Color BackColor + { + get { return base.BackColor; } + set { base.BackColor = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Color), "Control")] + public Color GridLineColour + { + get { return m_GridLineColour; } + set { m_GridLineColour = value; } + } + + //[Browsable(false)] + public TreeListViewNodes Nodes + { + get { return m_nodes; } + } + public TreeListView() + { + this.DoubleBuffered = true; + this.BackColor = SystemColors.Window; + this.TabStop = true; + + m_rowPainter = new RowPainter(); + m_cellPainter = new CellPainter(this); + + m_nodes = new TreeListViewNodes(this); + m_rowSetting = new TreeList.RowSetting(this); + m_viewSetting = new TreeList.ViewSetting(this); + m_columns = new TreeListColumnCollection(this); + AddScrollBars(); + } + public void RecalcLayout() + { + if (m_firstVisibleNode == null) + m_firstVisibleNode = Nodes.FirstNode; + if (Nodes.Count == 0) + m_firstVisibleNode = null; + + UpdateScrollBars(); + m_columns.RecalcVisibleColumsRect(); + UpdateScrollBars(); + m_columns.RecalcVisibleColumsRect(); + + int vscroll = VScrollValue(); + if (vscroll == 0) + m_firstVisibleNode = Nodes.FirstNode; + else + m_firstVisibleNode = NodeCollection.GetNextNode(Nodes.FirstNode, vscroll); + Invalidate(); + } + void AddScrollBars() + { + // I was not able to get the wanted behavior by using ScrollableControl with AutoScroll enabled. + // horizontal scrolling is ok to do it by pixels, but for vertical I want to maintain the headers + // and only scroll the rows. + // I was not able to manually overwrite the vscroll bar handling to get this behavior, instead I opted for + // custom implementation of scrollbars + + // to get the 'filler' between hscroll and vscroll I dock scroll + filler in a panel + m_hScroll = new HScrollBar(); + m_hScroll.Scroll += new ScrollEventHandler(OnHScroll); + m_hScroll.Dock = DockStyle.Fill; + + m_vScroll = new VScrollBar(); + m_vScroll.Scroll += new ScrollEventHandler(OnVScroll); + m_vScroll.Dock = DockStyle.Right; + + m_hScrollFiller = new Panel(); + m_hScrollFiller.BackColor = Color.Transparent; + m_hScrollFiller.Size = new Size(m_vScroll.Width-1, m_hScroll.Height); + m_hScrollFiller.Dock = DockStyle.Right; + + Controls.Add(m_vScroll); + + m_hScrollPanel = new Panel(); + m_hScrollPanel.Height = m_hScroll.Height; + m_hScrollPanel.Dock = DockStyle.Bottom; + m_hScrollPanel.Controls.Add(m_hScroll); + m_hScrollPanel.Controls.Add(m_hScrollFiller); + Controls.Add(m_hScrollPanel); + } + + VScrollBar m_vScroll; + HScrollBar m_hScroll; + Panel m_hScrollFiller; + Panel m_hScrollPanel; + bool m_multiSelect = true; + int m_treeColumn = 0; + bool m_vScrollAlways = false; + bool m_hScrollAlways = false; + Node m_firstVisibleNode = null; + + RowPainter m_rowPainter; + CellPainter m_cellPainter; + [Browsable(false)] + public CellPainter CellPainter + { + get { return m_cellPainter; } + set { m_cellPainter = value; } + } + + TreeListColumn m_resizingColumn; + int m_resizingColumnScrollOffset; + int m_resizingColumnLeft; + + TreeListColumn m_movingColumn; + + NodesSelection m_nodesSelection = new NodesSelection(); + Node m_focusedNode = null; + + [Browsable(false)] + public NodesSelection NodesSelection + { + get { return m_nodesSelection; } + } + + [Browsable(false)] + public Node SelectedNode + { + get { return m_nodesSelection.Count == 0 ? FocusedNode : m_nodesSelection[0]; } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Node FocusedNode + { + get { return m_focusedNode; } + set + { + Node curNode = FocusedNode; + if (object.ReferenceEquals(curNode, value)) + return; + if (MultiSelect == false) + NodesSelection.Clear(); + + int oldrow = NodeCollection.GetVisibleNodeIndex(curNode); + int newrow = NodeCollection.GetVisibleNodeIndex(value); + + m_focusedNode = value; + OnAfterSelect(value); + InvalidateRow(oldrow); + InvalidateRow(newrow); + EnsureVisible(m_focusedNode); + } + } + public void EnsureVisible(Node node) + { + int screenvisible = MaxVisibleRows() - 1; + int visibleIndex = NodeCollection.GetVisibleNodeIndex(node); + if (visibleIndex < VScrollValue()) + { + SetVScrollValue(visibleIndex); + } + if (visibleIndex > VScrollValue() + screenvisible) + { + SetVScrollValue(visibleIndex - screenvisible); + } + } + public Node CalcHitNode(Point mousepoint) + { + if (!ClientRectangle.Contains(mousepoint)) + return null; + + int hitrow = CalcHitRow(mousepoint); + if (hitrow < 0) + return null; + return NodeCollection.GetNextNode(m_firstVisibleNode, hitrow); + } + public Node GetHitNode() + { + return CalcHitNode(PointToClient(Control.MousePosition)); + } + public TreelistView.HitInfo CalcColumnHit(Point mousepoint) + { + return Columns.CalcHitInfo(mousepoint, HScrollValue()); + } + public bool HitTestScrollbar(Point mousepoint) + { + if (m_hScroll.Visible && mousepoint.Y >= ClientRectangle.Height - m_hScroll.Height) + return true; + return false; + } + + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + if (ClientRectangle.Width > 0 && ClientRectangle.Height > 0) + { + Columns.RecalcVisibleColumsRect(); + UpdateScrollBars(); + Columns.RecalcVisibleColumsRect(); + } + } + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged(e); + RecalcLayout(); + } + protected virtual void BeforeShowContextMenu() + { + } + protected void InvalidateRow(int absoluteRowIndex) + { + int visibleRowIndex = absoluteRowIndex - VScrollValue(); + Rectangle r = CalcRowRectangle(visibleRowIndex); + if (r != Rectangle.Empty) + { + r.Inflate(1,1); + Invalidate(r); + } + } + + void OnVScroll(object sender, ScrollEventArgs e) + { + int diff = e.NewValue - e.OldValue; + //assumedScrollPos += diff; + if (e.NewValue == 0) + { + m_firstVisibleNode = Nodes.FirstNode; + diff = 0; + } + m_firstVisibleNode = NodeCollection.GetNextNode(m_firstVisibleNode, diff); + Invalidate(); + } + void OnHScroll(object sender, ScrollEventArgs e) + { + Invalidate(); + } + void SetVScrollValue(int value) + { + if (value < 0) + value = 0; + int max = m_vScroll.Maximum - m_vScroll.LargeChange + 1; + if (value > max) + value = max; + + if ((value >= 0 && value <= max) && (value != m_vScroll.Value)) + { + ScrollEventArgs e = new ScrollEventArgs(ScrollEventType.ThumbPosition, m_vScroll.Value, value, ScrollOrientation.VerticalScroll); + // setting the scroll value does not cause a Scroll event + m_vScroll.Value = value; + // so we have to fake it + OnVScroll(m_vScroll, e); + } + } + int VScrollValue() + { + if (m_vScroll.Visible == false) + return 0; + return m_vScroll.Value; + } + int HScrollValue() + { + if (m_hScroll.Visible == false) + return 0; + return m_hScroll.Value; + } + void UpdateScrollBars() + { + if (ClientRectangle.Width < 0) + return; + int maxvisiblerows = MaxVisibleRows(); + int totalrows = Nodes.VisibleNodeCount; + m_vScroll.SmallChange = 1; + m_vScroll.LargeChange = Math.Max(1, maxvisiblerows); + m_vScroll.Enabled = true; + m_vScroll.Minimum = 0; + m_vScroll.Maximum = Math.Max(1,totalrows - 1); + if (maxvisiblerows >= totalrows) + { + m_vScroll.Visible = false; + SetVScrollValue(0); + + if (m_vScrollAlways) + { + m_vScroll.Visible = true; + m_vScroll.Enabled = false; + } + } + else + { + m_vScroll.Visible = true; + + int maxscrollvalue = m_vScroll.Maximum - m_vScroll.LargeChange; + if (maxscrollvalue < m_vScroll.Value) + SetVScrollValue(maxscrollvalue); + } + + m_hScroll.Enabled = true; + if (ClientRectangle.Width > MinWidth()) + { + m_hScrollPanel.Visible = false; + m_hScroll.Value = 0; + + if (m_hScrollAlways) + { + m_hScroll.Enabled = false; + m_hScrollPanel.Visible = true; + m_hScroll.Minimum = 0; + m_hScroll.Maximum = 0; + m_hScroll.SmallChange = 1; + m_hScroll.LargeChange = 1; + m_hScrollFiller.Visible = m_vScroll.Visible; + } + } + else + { + m_hScroll.Minimum = 0; + m_hScroll.Maximum = Math.Max(1, MinWidth()); + m_hScroll.SmallChange = 5; + m_hScroll.LargeChange = Math.Max(1, ClientRectangle.Width); + m_hScrollFiller.Visible = m_vScroll.Visible; + m_hScrollPanel.Visible = true; + } + } + int m_hotrow = -1; + int CalcHitRow(Point mousepoint) + { + if (mousepoint.Y <= Columns.Options.HeaderHeight) + return -1; + return (mousepoint.Y - Columns.Options.HeaderHeight) / RowOptions.ItemHeight; + } + int VisibleRowToYPoint(int visibleRowIndex) + { + return Columns.Options.HeaderHeight + (visibleRowIndex * RowOptions.ItemHeight); + } + Rectangle CalcRowRectangle(int visibleRowIndex) + { + Rectangle r = ClientRectangle; + r.Y = VisibleRowToYPoint(visibleRowIndex); + if (r.Top < Columns.Options.HeaderHeight || r.Top > ClientRectangle.Height) + return Rectangle.Empty; + r.Height = RowOptions.ItemHeight; + return r; + } + + void MultiSelectAdd(Node clickedNode, Keys modifierKeys) + { + if (Control.ModifierKeys == Keys.None) + { + foreach (Node node in NodesSelection) + { + int newrow = NodeCollection.GetVisibleNodeIndex(node); + InvalidateRow(newrow); + } + NodesSelection.Clear(); + NodesSelection.Add(clickedNode); + } + if (Control.ModifierKeys == Keys.Shift) + { + if (NodesSelection.Count == 0) + NodesSelection.Add(clickedNode); + else + { + int startrow = NodeCollection.GetVisibleNodeIndex(NodesSelection[0]); + int currow = NodeCollection.GetVisibleNodeIndex(clickedNode); + if (currow > startrow) + { + Node startingNode = NodesSelection[0]; + NodesSelection.Clear(); + foreach (Node node in NodeCollection.ForwardNodeIterator(startingNode, clickedNode, true)) + NodesSelection.Add(node); + Invalidate(); + } + if (currow < startrow) + { + Node startingNode = NodesSelection[0]; + NodesSelection.Clear(); + foreach (Node node in NodeCollection.ReverseNodeIterator(startingNode, clickedNode, true)) + NodesSelection.Add(node); + Invalidate(); + } + } + } + if (Control.ModifierKeys == Keys.Control) + { + if (NodesSelection.Contains(clickedNode)) + NodesSelection.Remove(clickedNode); + else + NodesSelection.Add(clickedNode); + } + InvalidateRow(NodeCollection.GetVisibleNodeIndex(clickedNode)); + FocusedNode = clickedNode; + } + internal event MouseEventHandler AfterResizingColumn; + protected override void OnMouseClick(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + Point mousePoint = new Point(e.X, e.Y); + Node clickedNode = CalcHitNode(mousePoint); + if (clickedNode != null && Columns.Count > 0) + { + int clickedRow = CalcHitRow(mousePoint); + Rectangle glyphRect = Rectangle.Empty; + if (m_treeColumn >= 0) + glyphRect = GetPlusMinusRectangle(clickedNode, Columns[m_treeColumn], clickedRow); + if (clickedNode.HasChildren && glyphRect != Rectangle.Empty && glyphRect.Contains(mousePoint)) + clickedNode.Expanded = !clickedNode.Expanded; + + var columnHit = CalcColumnHit(mousePoint); + + if (glyphRect == Rectangle.Empty && columnHit.Column != null && + columnHit.Column.Index == m_treeColumn && GetNodeBitmap(clickedNode) != null) + { + OnNodeClicked(clickedNode); + } + + if (MultiSelect) + { + MultiSelectAdd(clickedNode, Control.ModifierKeys); + } + else + FocusedNode = clickedNode; + } + /* + else + { + FocusedNode = null; + NodesSelection.Clear(); + }*/ + } + base.OnMouseClick(e); + } + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (m_movingColumn != null) + { + m_movingColumn.Moving = true; + Cursor = Cursors.SizeAll; + + var idx = m_movingColumn.VisibleIndex; + if (idx + 1 < Columns.VisibleColumns.Length) + { + var nextcol = Columns.VisibleColumns[idx + 1]; + if (nextcol.CalculatedRect.X + (nextcol.CalculatedRect.Width * 3) / 4 < e.X) + { + Columns.SetVisibleIndex(m_movingColumn, idx + 1); + } + } + if (idx - 1 >= 0) + { + var prevcol = Columns.VisibleColumns[idx - 1]; + if (prevcol.CalculatedRect.Right - (prevcol.CalculatedRect.Width * 3) / 4 > e.X) + { + Columns.SetVisibleIndex(m_movingColumn, idx - 1); + } + } + + Columns.RecalcVisibleColumsRect(true); + Invalidate(); + return; + } + if (m_resizingColumn != null) + { + // if we've clicked on an autosize column, actually resize the next one along. + if (m_resizingColumn.AutoSize) + { + if (Columns.VisibleColumns.Length > m_resizingColumn.VisibleIndex + 1) + { + TreeListColumn realResizeColumn = Columns.VisibleColumns[m_resizingColumn.VisibleIndex + 1]; + + int right = realResizeColumn.CalculatedRect.Right - m_resizingColumnScrollOffset; + int width = right - e.X; + if (width < 10) + width = 10; + + bool resize = true; + + if (Columns.VisibleColumns.Length > realResizeColumn.VisibleIndex + 1) + if (Columns.VisibleColumns[realResizeColumn.VisibleIndex + 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width) + resize = false; + + if (realResizeColumn.VisibleIndex > 1) + if (Columns.VisibleColumns[realResizeColumn.VisibleIndex - 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width) + resize = false; + + if (resize) + { + realResizeColumn.Width = width; + } + } + } + else + { + int left = m_resizingColumnLeft; + int width = e.X - left; + if (width < 10) + width = 10; + + bool resize = true; + + if (Columns.VisibleColumns.Length > m_resizingColumn.VisibleIndex + 1) + if (Columns.VisibleColumns[m_resizingColumn.VisibleIndex + 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width) + resize = false; + + if (m_resizingColumn.internalIndex > 1) + if (Columns.VisibleColumns[m_resizingColumn.VisibleIndex - 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width) + resize = false; + + if (resize) + m_resizingColumn.Width = width; + } + + Columns.RecalcVisibleColumsRect(true); + Invalidate(); + return; + } + + TreeListColumn hotcol = null; + TreelistView.HitInfo info = Columns.CalcHitInfo(new Point(e.X, e.Y), HScrollValue()); + if ((int)(info.HitType & HitInfo.eHitType.kColumnHeader) > 0) + hotcol = info.Column; + + Node clickedNode = CalcHitNode(new Point(e.X, e.Y)); + + if ((int)(info.HitType & HitInfo.eHitType.kColumnHeaderResize) > 0) + Cursor = Cursors.VSplit; + else if (info.Column != null && info.Column.Index == m_treeColumn && GetNodeBitmap(clickedNode) != null && m_viewSetting.HoverHandTreeColumn) + Cursor = Cursors.Hand; + else + Cursor = Cursors.Arrow; + + if (GetHoverNodeBitmap(clickedNode) != null && + GetNodeBitmap(clickedNode) != GetHoverNodeBitmap(clickedNode)) + Invalidate(); + + SetHotColumn(hotcol, true); + + int vScrollOffset = VScrollValue(); + + int newhotrow = -1; + if (hotcol == null) + { + int row = (e.Y - Columns.Options.HeaderHeight) / RowOptions.ItemHeight; + newhotrow = row + vScrollOffset; + } + if (newhotrow != m_hotrow) + { + InvalidateRow(m_hotrow); + m_hotrow = newhotrow; + InvalidateRow(m_hotrow); + } + } + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + SetHotColumn(null, false); + Cursor = Cursors.Arrow; + Invalidate(); + } + protected override void OnMouseWheel(MouseEventArgs e) + { + int value = m_vScroll.Value - (e.Delta * SystemInformation.MouseWheelScrollLines / 120); + if (m_vScroll.Visible) + SetVScrollValue(value); + base.OnMouseWheel(e); + } + protected override void OnMouseDown(MouseEventArgs e) + { + this.Focus(); + if (e.Button == MouseButtons.Right) + { + Point mousePoint = new Point(e.X, e.Y); + Node clickedNode = CalcHitNode(mousePoint); + if (clickedNode != null) + { + // if multi select the selection is cleard if clicked node is not in selection + if (MultiSelect) + { + if (NodesSelection.Contains(clickedNode) == false) + MultiSelectAdd(clickedNode, Control.ModifierKeys); + } + FocusedNode = clickedNode; + Invalidate(); + } + BeforeShowContextMenu(); + } + + if (e.Button == MouseButtons.Left) + { + TreelistView.HitInfo info = Columns.CalcHitInfo(new Point(e.X, e.Y), HScrollValue()); + if ((int)(info.HitType & HitInfo.eHitType.kColumnHeaderResize) > 0) + { + m_resizingColumn = info.Column; + m_resizingColumnScrollOffset = HScrollValue(); + m_resizingColumnLeft = m_resizingColumn.CalculatedRect.Left - m_resizingColumnScrollOffset; + return; + } + if ((int)(info.HitType & HitInfo.eHitType.kColumnHeader) > 0 && m_viewSetting.UserRearrangeableColumns) + { + m_movingColumn = info.Column; + return; + } + } + base.OnMouseDown(e); + } + protected override void OnMouseUp(MouseEventArgs e) + { + if (m_resizingColumn != null) + { + m_resizingColumn = null; + Columns.RecalcVisibleColumsRect(); + UpdateScrollBars(); + Invalidate(); + if (AfterResizingColumn != null) + AfterResizingColumn(this, e); + } + if (m_movingColumn != null) + { + m_movingColumn.Moving = false; + m_movingColumn = null; + Cursor = Cursors.Arrow; + Columns.RecalcVisibleColumsRect(); + UpdateScrollBars(); + Invalidate(); + } + base.OnMouseUp(e); + } + protected override void OnMouseDoubleClick(MouseEventArgs e) + { + base.OnMouseDoubleClick(e); + Point mousePoint = new Point(e.X, e.Y); + Node clickedNode = CalcHitNode(mousePoint); + if (clickedNode != null && clickedNode.HasChildren) + clickedNode.Expanded = !clickedNode.Expanded; + if (clickedNode != null) + OnNodeDoubleClicked(clickedNode); + } + + // Somewhere I read that it could be risky to do any handling in GetFocus / LostFocus. + // The reason is that it will throw exception incase you make a call which recreates the windows handle (e.g. + // change the border style. Instead one should always use OnEnter and OnLeave instead. That is why I'm using + // OnEnter and OnLeave instead, even though I'm only doing Invalidate. + protected override void OnEnter(EventArgs e) + { + base.OnEnter(e); + Invalidate(); + } + protected override void OnLeave(EventArgs e) + { + base.OnLeave(e); + Invalidate(); + } + + protected override void OnLostFocus(EventArgs e) + { + base.OnLostFocus(e); + Invalidate(); + } + + void SetHotColumn(TreeListColumn col, bool ishot) + { + int scrolloffset = HScrollValue(); + if (col != m_hotColumn) + { + if (m_hotColumn != null) + { + m_hotColumn.ishot = false; + Rectangle r = m_hotColumn.CalculatedRect; + r.X -= scrolloffset; + Invalidate(r); + } + m_hotColumn = col; + if (m_hotColumn != null) + { + m_hotColumn.ishot = ishot; + Rectangle r = m_hotColumn.CalculatedRect; + r.X -= scrolloffset; + Invalidate(r); + } + } + } + internal int RowHeaderWidth() + { + if (RowOptions.ShowHeader) + return RowOptions.HeaderWidth; + return 0; + } + int MinWidth() + { + return RowHeaderWidth() + Columns.ColumnsWidth; + } + int MaxVisibleRows(out int remainder) + { + remainder = 0; + if (ClientRectangle.Height < 0) + return 0; + int height = ClientRectangle.Height - Columns.Options.HeaderHeight; + //return (int) Math.Ceiling((double)(ClientRectangle.Height - Columns.HeaderHeight) / (double)Nodes.ItemHeight); + remainder = (ClientRectangle.Height - Columns.Options.HeaderHeight) % RowOptions.ItemHeight ; + return Math.Max(0, (ClientRectangle.Height - Columns.Options.HeaderHeight) / RowOptions.ItemHeight); + } + int MaxVisibleRows() + { + int unused; + return MaxVisibleRows(out unused); + } + public void BeginUpdate() + { + m_nodes.BeginUpdate(); + } + public void EndUpdate() + { + m_nodes.EndUpdate(); + RecalcLayout(); + Invalidate(); + } + protected override CreateParams CreateParams + { + get + { + const int WS_BORDER = 0x00800000; + const int WS_EX_CLIENTEDGE = 0x00000200; + CreateParams p = base.CreateParams; + p.Style &= ~(int)WS_BORDER; + p.ExStyle &= ~(int)WS_EX_CLIENTEDGE; + switch (ViewOptions.BorderStyle) + { + case BorderStyle.Fixed3D: + p.ExStyle |= (int)WS_EX_CLIENTEDGE; + break; + case BorderStyle.FixedSingle: + p.Style |= (int)WS_BORDER; + break; + default: + break; + } + return p; + } + } + + TreeListColumn m_hotColumn = null; + + object GetDataDesignMode(Node node, TreeListColumn column) + { + string id = string.Empty; + while (node != null) + { + id = node.Owner.GetNodeIndex(node).ToString() + ":" + id; + node = node.Parent; + } + return "" + id; + } + protected virtual object GetData(Node node, TreeListColumn column) + { + if (node[column.Index] != null) + return node[column.Index]; + return null; + } + public new Rectangle ClientRectangle + { + get + { + Rectangle r = base.ClientRectangle; + if (m_vScroll.Visible) + r.Width -= m_vScroll.Width+1; + if (m_hScroll.Visible) + r.Height -= m_hScroll.Height+1; + return r; + } + } + + protected virtual TreelistView.TreeList.TextFormatting GetFormatting(TreelistView.Node node, TreelistView.TreeListColumn column) + { + return column.CellFormat; + } + protected virtual void PaintCellPlusMinus(Graphics dc, Rectangle glyphRect, Node node, TreeListColumn column) + { + CellPainter.PaintCellPlusMinus(dc, glyphRect, node, column, GetFormatting(node, column)); + } + protected virtual void PaintCellBackground(Graphics dc, Rectangle cellRect, Node node, TreeListColumn column) + { + if (this.DesignMode) + CellPainter.PaintCellBackground(dc, cellRect, node, column, GetFormatting(node, column), GetDataDesignMode(node, column)); + else + CellPainter.PaintCellBackground(dc, cellRect, node, column, GetFormatting(node, column), GetData(node, column)); + } + protected virtual void PaintCellText(Graphics dc, Rectangle cellRect, Node node, TreeListColumn column) + { + if (this.DesignMode) + CellPainter.PaintCellText(dc, cellRect, node, column, GetFormatting(node, column), GetDataDesignMode(node, column)); + else + CellPainter.PaintCellText(dc, cellRect, node, column, GetFormatting(node, column), GetData(node, column)); + } + protected virtual void PaintImage(Graphics dc, Rectangle imageRect, Node node, Image image) + { + if (image != null) + dc.DrawImage(image, imageRect.X, imageRect.Y, imageRect.Width, imageRect.Height); + } + protected virtual void PaintNode(Graphics dc, Rectangle rowRect, Node node, TreeListColumn[] visibleColumns, int visibleRowIndex) + { + CellPainter.DrawSelectionBackground(dc, rowRect, node); + foreach (TreeListColumn col in visibleColumns) + { + if (col.CalculatedRect.Right - HScrollValue() < RowHeaderWidth()) + continue; + + Rectangle cellRect = rowRect; + cellRect.X = col.CalculatedRect.X - HScrollValue(); + cellRect.Width = col.CalculatedRect.Width; + + dc.SetClip(cellRect); + + if (col.Index == m_treeColumn) + { + int lineindet = 10; + // add left margin + cellRect.X += Columns.Options.LeftMargin; + cellRect.Width -= Columns.Options.LeftMargin; + + // add indent size + int indentSize = GetIndentSize(node) + 5; + cellRect.X += indentSize; + cellRect.Width -= indentSize; + if (ViewOptions.ShowLine) + PaintLines(dc, cellRect, node); + cellRect.X += lineindet; + cellRect.Width -= lineindet; + + Rectangle glyphRect = GetPlusMinusRectangle(node, col, visibleRowIndex); + + if (!ViewOptions.ShowLine && !ViewOptions.ShowPlusMinus) + { + cellRect.X -= (lineindet + 5); + cellRect.Width += (lineindet + 5); + } + + Point mousePoint = PointToClient(Cursor.Position); + Node hoverNode = CalcHitNode(mousePoint); + + Image icon = hoverNode != null && hoverNode == node ? GetHoverNodeBitmap(node) : GetNodeBitmap(node); + + if (icon == null && + (NodesSelection.Contains(node) || FocusedNode == node) + ) + { + icon = SelectedImage; + } + + Rectangle plusminusRect = glyphRect; + + PaintCellBackground(dc, cellRect, node, col); + + if (icon != null) + { + // center the image vertically + glyphRect.Y = cellRect.Y + (cellRect.Height / 2) - (icon.Height / 2); + glyphRect.X = cellRect.X; + glyphRect.Width = icon.Width; + glyphRect.Height = icon.Height; + + PaintImage(dc, glyphRect, node, icon); + cellRect.X += (glyphRect.Width + 2); + cellRect.Width -= (glyphRect.Width + 2); + } + + PaintCellText(dc, cellRect, node, col); + + if (plusminusRect != Rectangle.Empty && ViewOptions.ShowPlusMinus) + PaintCellPlusMinus(dc, plusminusRect, node, col); + } + else + { + PaintCellBackground(dc, cellRect, node, col); + PaintCellText(dc, cellRect, node, col); + } + + dc.ResetClip(); + } + } + protected virtual void PaintLines(Graphics dc, Rectangle cellRect, Node node) + { + Pen pen = new Pen(Color.Gray); + pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; + + int halfPoint = cellRect.Top + (cellRect.Height / 2); + // line should start from center at first root node + if (node.Parent == null && node.PrevSibling == null) + { + cellRect.Y += (cellRect.Height / 2); + cellRect.Height -= (cellRect.Height / 2); + } + if (node.NextSibling != null || node.HasChildren) // draw full height line + dc.DrawLine(pen, cellRect.X, cellRect.Top, cellRect.X, cellRect.Bottom); + else + dc.DrawLine(pen, cellRect.X, cellRect.Top, cellRect.X, halfPoint); + dc.DrawLine(pen, cellRect.X, halfPoint, cellRect.X + 10, halfPoint); + + // now draw the lines for the parents sibling + Node parent = node.Parent; + while (parent != null) + { + cellRect.X -= ViewOptions.Indent; + dc.DrawLine(pen, cellRect.X, cellRect.Top, cellRect.X, cellRect.Bottom); + parent = parent.Parent; + } + + pen.Dispose(); + } + protected virtual int GetIndentSize(Node node) + { + int indent = 0; + Node parent = node.Parent; + while (parent != null) + { + indent += ViewOptions.Indent; + parent = parent.Parent; + } + return indent; + } + protected virtual Rectangle GetPlusMinusRectangle(Node node, TreeListColumn firstColumn, int visibleRowIndex) + { + if (node.HasChildren == false) + return Rectangle.Empty; + int hScrollOffset = HScrollValue(); + if (firstColumn.CalculatedRect.Right - hScrollOffset < RowHeaderWidth()) + return Rectangle.Empty; + //System.Diagnostics.Debug.Assert(firstColumn.VisibleIndex == 0); + + Rectangle glyphRect = firstColumn.CalculatedRect; + glyphRect.X -= hScrollOffset; + glyphRect.X += GetIndentSize(node); + glyphRect.X += Columns.Options.LeftMargin; + glyphRect.Width = 10; + glyphRect.Y = VisibleRowToYPoint(visibleRowIndex); + glyphRect.Height = RowOptions.ItemHeight; + return glyphRect; + } + protected virtual Image GetNodeBitmap(Node node) + { + if (node != null) + return node.Image; + return null; + } + protected virtual Image GetHoverNodeBitmap(Node node) + { + if (node != null) + return node.HoverImage; + return null; + } + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + int hScrollOffset = HScrollValue(); + int remainder = 0; + int visiblerows = MaxVisibleRows(out remainder); + if (remainder > 0) + visiblerows++; + + bool drawColumnHeaders = true; + // draw columns + if (drawColumnHeaders) + { + Rectangle headerRect = e.ClipRectangle; + Columns.Draw(e.Graphics, headerRect, hScrollOffset); + } + + int visibleRowIndex = 0; + TreeListColumn[] visibleColumns = this.Columns.VisibleColumns; + int columnsWidth = Columns.ColumnsWidth; + foreach (Node node in NodeCollection.ForwardNodeIterator(m_firstVisibleNode, true)) + { + Rectangle rowRect = CalcRowRectangle(visibleRowIndex); + if (rowRect == Rectangle.Empty || rowRect.Bottom <= e.ClipRectangle.Top || rowRect.Top >= e.ClipRectangle.Bottom) + { + if (visibleRowIndex > visiblerows) + break; + visibleRowIndex++; + continue; + } + rowRect.X = RowHeaderWidth() - hScrollOffset; + rowRect.Width = columnsWidth; + + // draw the current node + PaintNode(e.Graphics, rowRect, node, visibleColumns, visibleRowIndex); + + // drow row header for current node + Rectangle headerRect = rowRect; + headerRect.X = 0; + headerRect.Width = RowHeaderWidth(); + + int absoluteRowIndex = visibleRowIndex + VScrollValue(); + headerRect.Width = RowHeaderWidth(); + m_rowPainter.DrawHeader(e.Graphics, headerRect, absoluteRowIndex == m_hotrow); + + visibleRowIndex++; + } + + visibleRowIndex = 0; + foreach (Node node in NodeCollection.ForwardNodeIterator(m_firstVisibleNode, true)) + { + Rectangle rowRect = CalcRowRectangle(visibleRowIndex); + // draw horizontal grid line for current node + if (ViewOptions.ShowGridLines) + { + Rectangle r = rowRect; + r.X = RowHeaderWidth(); + r.Width = columnsWidth - hScrollOffset; + m_rowPainter.DrawHorizontalGridLine(e.Graphics, r, GridLineColour); + } + + visibleRowIndex++; + } + + // draw vertical grid lines + if (ViewOptions.ShowGridLines) + { + // visible row count + int remainRows = Nodes.VisibleNodeCount - m_vScroll.Value; + if (visiblerows > remainRows) + visiblerows = remainRows; + + Rectangle fullRect = ClientRectangle; + if (drawColumnHeaders) + fullRect.Y += Columns.Options.HeaderHeight; + fullRect.Height = visiblerows * RowOptions.ItemHeight; + Columns.Painter.DrawVerticalGridLines(Columns, e.Graphics, fullRect, hScrollOffset); + } + } + + protected override bool IsInputKey(Keys keyData) + { + if ((int)(keyData & Keys.Shift) > 0) + return true; + switch (keyData) + { + case Keys.Left: + case Keys.Right: + case Keys.Down: + case Keys.Up: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Home: + case Keys.End: + return true; + } + return false; + } + protected override void OnKeyDown(KeyEventArgs e) + { + Node newnode = null; + if (e.KeyCode == Keys.PageUp) + { + int remainder = 0; + int diff = MaxVisibleRows(out remainder)-1; + newnode = NodeCollection.GetNextNode(FocusedNode, -diff); + if (newnode == null) + newnode = Nodes.FirstVisibleNode(); + } + if (e.KeyCode == Keys.PageDown) + { + int remainder = 0; + int diff = MaxVisibleRows(out remainder)-1; + newnode = NodeCollection.GetNextNode(FocusedNode, diff); + if (newnode == null) + newnode = Nodes.LastVisibleNode(true); + } + + if (e.KeyCode == Keys.Down) + { + newnode = NodeCollection.GetNextNode(FocusedNode, 1); + } + if (e.KeyCode == Keys.Up) + { + newnode = NodeCollection.GetNextNode(FocusedNode, -1); + } + if (e.KeyCode == Keys.Home) + { + newnode = Nodes.FirstNode; + } + if (e.KeyCode == Keys.End) + { + newnode = Nodes.LastVisibleNode(true); + } + if (e.KeyCode == Keys.Left) + { + if (FocusedNode != null) + { + if (FocusedNode.Expanded) + { + FocusedNode.Collapse(); + EnsureVisible(FocusedNode); + return; + } + if (FocusedNode.Parent != null) + { + FocusedNode = FocusedNode.Parent; + EnsureVisible(FocusedNode); + } + } + } + if (e.KeyCode == Keys.Right) + { + if (FocusedNode != null) + { + if (FocusedNode.Expanded == false && FocusedNode.HasChildren) + { + FocusedNode.Expand(); + EnsureVisible(FocusedNode); + return; + } + if (FocusedNode.Expanded == true && FocusedNode.HasChildren) + { + FocusedNode = FocusedNode.Nodes.FirstNode; + EnsureVisible(FocusedNode); + } + } + } + if (newnode != null) + { + if (MultiSelect) + { + // tree behavior is + // keys none, the selected node is added as the focused and selected node + // keys control, only focused node is moved, the selected nodes collection is not modified + // keys shift, selection from first selected node to current node is done + if (Control.ModifierKeys == Keys.Control) + FocusedNode = newnode; + else + MultiSelectAdd(newnode, Control.ModifierKeys); + } + else + FocusedNode = newnode; + EnsureVisible(FocusedNode); + } + base.OnKeyDown(e); + } + + internal void internalUpdateStyles() + { + base.UpdateStyles(); + } + + #region ISupportInitialize Members + + public void BeginInit() + { + Columns.BeginInit(); + } + public void EndInit() + { + Columns.EndInit(); + } + + #endregion + internal new bool DesignMode + { + get { return base.DesignMode; } + } + } + + public class TreeListViewNodes : NodeCollection + { + TreeListView m_tree; + bool m_isUpdating = false; + public void BeginUpdate() + { + m_isUpdating = true; + } + public void EndUpdate() + { + m_isUpdating = false; + } + public TreeListViewNodes(TreeListView owner) : base(null) + { + m_tree = owner; + OwnerView = owner; + } + protected override void UpdateNodeCount(int oldvalue, int newvalue) + { + base.UpdateNodeCount(oldvalue, newvalue); + if (!m_isUpdating) + m_tree.RecalcLayout(); + } + public override void Clear() + { + base.Clear(); + m_tree.RecalcLayout(); + } + public override void NodetifyBeforeExpand(Node nodeToExpand, bool expanding) + { + if (!m_tree.DesignMode) + m_tree.OnNotifyBeforeExpand(nodeToExpand, expanding); + } + public override void NodetifyAfterExpand(Node nodeToExpand, bool expanded) + { + m_tree.OnNotifyAfterExpand(nodeToExpand, expanded); + } + protected override int GetFieldIndex(string fieldname) + { + TreeListColumn col = m_tree.Columns[fieldname]; + if (col != null) + return col.Index; + return -1; + } + } +} diff --git a/renderdocui/Interop/Camera.cs b/renderdocui/Interop/Camera.cs new file mode 100644 index 0000000000..09951744dd --- /dev/null +++ b/renderdocui/Interop/Camera.cs @@ -0,0 +1,103 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace renderdoc +{ + public class Camera + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void Maths_CameraArcball(float dist, ref FloatVector rot, IntPtr pos, IntPtr fwd, IntPtr right); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void Maths_CameraFPSLook(ref FloatVector lookpos, ref FloatVector rot, IntPtr pos, IntPtr fwd, IntPtr right); + + public void Arcball(float dist, Vec3f rot) + { + IntPtr p = CustomMarshal.Alloc(typeof(FloatVector)); + IntPtr f = CustomMarshal.Alloc(typeof(FloatVector)); + IntPtr r = CustomMarshal.Alloc(typeof(FloatVector)); + + isarc = true; + parampos.x = dist; + parampos.y = 0.0f; + parampos.z = 0.0f; + paramrot = new Vec3f(rot); + + var rt = new FloatVector(rot); + + Maths_CameraArcball(dist, ref rt, p, f, r); + + pos = new Vec3f((FloatVector)CustomMarshal.PtrToStructure(p, typeof(FloatVector), false)); + fwd = new Vec3f((FloatVector)CustomMarshal.PtrToStructure(f, typeof(FloatVector), false)); + right = new Vec3f((FloatVector)CustomMarshal.PtrToStructure(r, typeof(FloatVector), false)); + + CustomMarshal.Free(p); + CustomMarshal.Free(f); + CustomMarshal.Free(r); + } + public void fpsLook(Vec3f pos, Vec3f rot) + { + IntPtr p = CustomMarshal.Alloc(typeof(FloatVector)); + IntPtr f = CustomMarshal.Alloc(typeof(FloatVector)); + IntPtr r = CustomMarshal.Alloc(typeof(FloatVector)); + + isarc = false; + parampos = new Vec3f(pos); + paramrot = new Vec3f(rot); + + var ps = new FloatVector(pos); + var rt = new FloatVector(rot); + + Maths_CameraFPSLook(ref ps, ref rt, p, f, r); + + pos = new Vec3f((FloatVector)CustomMarshal.PtrToStructure(p, typeof(FloatVector), false)); + fwd = new Vec3f((FloatVector)CustomMarshal.PtrToStructure(f, typeof(FloatVector), false)); + right = new Vec3f((FloatVector)CustomMarshal.PtrToStructure(r, typeof(FloatVector), false)); + + CustomMarshal.Free(p); + CustomMarshal.Free(f); + CustomMarshal.Free(r); + } + + private Vec3f pos = new Vec3f(0.0f, 0.0f, 0.0f); + private Vec3f fwd = new Vec3f(0.0f, 0.0f, 1.0f); + private Vec3f right = new Vec3f(1.0f, 0.0f, 0.0f); + + public Vec3f Position { get { return pos; } } + public Vec3f Forward { get { return fwd; } } + public Vec3f Right { get { return right; } } + + private bool isarc = false; + private Vec3f parampos = new Vec3f(0.0f, 0.0f, 0.0f); + private Vec3f paramrot = new Vec3f(0.0f, 0.0f, 0.0f); + + public bool IsArcball { get { return isarc; } } + public Vec3f PositionParam { get { return parampos; } } + public Vec3f RotationParam { get { return paramrot; } } + } +} diff --git a/renderdocui/Interop/CaptureOptions.cs b/renderdocui/Interop/CaptureOptions.cs new file mode 100644 index 0000000000..65f23599b1 --- /dev/null +++ b/renderdocui/Interop/CaptureOptions.cs @@ -0,0 +1,82 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace renderdoc +{ + [DebuggerDisplay("{m_ID}")] + [StructLayout(LayoutKind.Sequential)] + public struct ResourceId + { + private UInt64 m_ID; + + public override string ToString() + { + return String.Format("{0}", m_ID); + } + + public override bool Equals(Object obj) + { + return obj is ResourceId && this == (ResourceId)obj; + } + public override int GetHashCode() + { + return m_ID.GetHashCode(); + } + public static bool operator ==(ResourceId x, ResourceId y) + { + return x.m_ID == y.m_ID; + } + public static bool operator !=(ResourceId x, ResourceId y) + { + return !(x == y); + } + + public static ResourceId Null = new ResourceId(0, true); + + private ResourceId(UInt64 id, bool explicitConstruct) + { + m_ID = id; + } + }; + + [StructLayout(LayoutKind.Sequential)] + public class CaptureOptions + { + public bool AllowVSync; + public bool AllowFullscreen; + public bool DebugDeviceMode; + public bool CaptureCallstacks; + public bool CaptureCallstacksOnlyDraws; + public UInt32 DelayForDebugger; + public bool CacheStateObjects; + public bool HookIntoChildren; + public bool RefAllResources; + public bool SaveAllInitials; + public bool CaptureAllCmdLists; + }; +}; diff --git a/renderdocui/Interop/CustomMarshaling.cs b/renderdocui/Interop/CustomMarshaling.cs new file mode 100644 index 0000000000..72fd7980ce --- /dev/null +++ b/renderdocui/Interop/CustomMarshaling.cs @@ -0,0 +1,606 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; +using System.Reflection; +using System.Collections.Generic; + +namespace renderdoc +{ + // corresponds to rdctype::array on the C side + [StructLayout(LayoutKind.Sequential)] + public struct templated_array + { + public IntPtr elems; + public Int32 count; + }; + + // convenience - for when we want to define an array of strings, this + // struct lets us do that + [StructLayout(LayoutKind.Sequential)] + public struct rdctype_wstr + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + string s; + }; + + public enum CustomUnmanagedType + { + TemplatedArray = 0, + AsciiTemplatedString, + WideTemplatedString, + FixedArray, + Union, + Skip, + CustomClass, + CustomClassPointer, + } + + public enum CustomFixedType + { + None = 0, + Float, + UInt32, + Int32, + UInt16, + } + + // custom attribute that we can apply to structures we want to serialise + public sealed class CustomMarshalAsAttribute : Attribute + { + public CustomMarshalAsAttribute(CustomUnmanagedType unmanagedType) + { + m_UnmanagedType = unmanagedType; + } + + public CustomUnmanagedType CustomType + { + get { return m_UnmanagedType; } + } + + public int FixedLength + { + get { return m_FixedLen; } + set { m_FixedLen = value; } + } + + public CustomFixedType FixedType + { + get { return m_FixedType; } + set { m_FixedType = value; } + } + + private CustomUnmanagedType m_UnmanagedType; + private int m_FixedLen; + private CustomFixedType m_FixedType = CustomFixedType.None; + } + + // custom marshalling code to handle converting complex data types with our given formatting + // over to .NET managed copies. + public static class CustomMarshal + { + [DllImport("kernel32.dll", EntryPoint = "RtlFillMemory", SetLastError = false)] + private static extern void FillMemory(IntPtr destination, int length, byte fill); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RENDERDOC_FreeArrayMem(IntPtr mem); + + // utility functions usable by wrappers around actual functions calling into the C++ core + public static IntPtr Alloc(Type T) + { + IntPtr mem = Marshal.AllocHGlobal(CustomMarshal.SizeOf(T)); + FillMemory(mem, CustomMarshal.SizeOf(T), 0); + + return mem; + } + + public static void Free(IntPtr mem) + { + Marshal.FreeHGlobal(mem); + } + + // note that AlignOf and AddFieldSize and others are called rarely as the results + // are cached lower down + + // match C/C++ alignment rules + private static int AlignOf(FieldInfo field) + { + var cma = GetCustomAttr(field); + + if (cma != null && + (cma.CustomType == CustomUnmanagedType.AsciiTemplatedString || + cma.CustomType == CustomUnmanagedType.WideTemplatedString || + cma.CustomType == CustomUnmanagedType.TemplatedArray || + cma.CustomType == CustomUnmanagedType.CustomClassPointer) + ) + return IntPtr.Size; + + if (cma != null && cma.CustomType == CustomUnmanagedType.Skip) + return 1; + + if (field.FieldType.IsPrimitive || + (field.FieldType.IsArray && field.FieldType.GetElementType().IsPrimitive)) + return Marshal.SizeOf(NonArrayType(field.FieldType)); + + // Get instance fields of the structure type. + FieldInfo[] fieldInfo = NonArrayType(field.FieldType).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + int align = 0; + + foreach (FieldInfo f in fieldInfo) + align = Math.Max(align, AlignOf(f)); + + return align; + } + + private static Type NonArrayType(Type t) + { + return t.IsArray ? t.GetElementType() : t; + } + + private static Dictionary m_CustomAttrCache = new Dictionary(); + + private static CustomMarshalAsAttribute GetCustomAttr(Type t, FieldInfo[] fields, int fieldIdx) + { + if (!m_CustomAttrCache.ContainsKey(t)) + { + var arr = new CustomMarshalAsAttribute[fields.Length]; + + for (int i = 0; i < fields.Length; i++) + arr[i] = GetCustomAttr(fields[i]); + + m_CustomAttrCache.Add(t, arr); + } + + return m_CustomAttrCache[t][fieldIdx]; + } + + private static CustomMarshalAsAttribute GetCustomAttr(FieldInfo field) + { + if (CustomAttributeDefined(field)) + { + object[] attributes = field.GetCustomAttributes(false); + foreach (object attribute in attributes) + { + if (attribute is CustomMarshalAsAttribute) + { + return (attribute as CustomMarshalAsAttribute); + } + } + } + + return null; + } + + // add a field's size to the size parameter, respecting alignment + private static void AddFieldSize(FieldInfo field, ref long size) + { + int a = AlignOf(field); + int alignment = (int)size % a; + if (alignment != 0) size += a - alignment; + + var cma = GetCustomAttr(field); + if (cma != null) + { + switch (cma.CustomType) + { + case CustomUnmanagedType.CustomClass: + size += SizeOf(field.FieldType); + break; + case CustomUnmanagedType.CustomClassPointer: + size += IntPtr.Size; + break; + case CustomUnmanagedType.Union: + { + FieldInfo[] fieldInfo = field.FieldType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + long unionsize = 0; + + foreach (FieldInfo unionfield in fieldInfo) + { + long maxsize = 0; + + AddFieldSize(unionfield, ref maxsize); + + unionsize = Math.Max(unionsize, maxsize); + } + + size += unionsize; + break; + } + case CustomUnmanagedType.TemplatedArray: + case CustomUnmanagedType.AsciiTemplatedString: + case CustomUnmanagedType.WideTemplatedString: + size += Marshal.SizeOf(typeof(templated_array)); + break; + case CustomUnmanagedType.FixedArray: + size += cma.FixedLength * SizeOf(NonArrayType(field.FieldType)); + break; + case CustomUnmanagedType.Skip: + break; + default: + throw new NotImplementedException("Unexpected attribute"); + } + } + else + { + size += SizeOf(field.FieldType); + } + + alignment = (int)size % a; + if (alignment != 0) size += a - alignment; + } + + // cache for sizes of types, since this will get called a lot + private static Dictionary m_SizeCache = new Dictionary(); + + // return the size of the C++ equivalent of this type (so that we can allocate enough) + // space to pass a pointer for example. + private static int SizeOf(Type structureType) + { + if (structureType.IsPrimitive || + (structureType.IsArray && structureType.GetElementType().IsPrimitive)) + return Marshal.SizeOf(structureType); + + if (m_SizeCache.ContainsKey(structureType)) + return m_SizeCache[structureType]; + + // Get instance fields of the structure type. + FieldInfo[] fieldInfo = structureType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + long size = 0; + + int a = 0; + + foreach (FieldInfo field in fieldInfo) + { + AddFieldSize(field, ref size); + a = Math.Max(a, AlignOf(field)); + } + + int alignment = (int)size % a; + if (alignment != 0) size += a - alignment; + + m_SizeCache.Add(structureType, (int)size); + + return (int)size; + } + + // caching the offset to the nth field from a base pointer to the type + private static Dictionary m_OffsetCache = new Dictionary(); + // caching how much to align up a pointer by to the first field (above offsets take care after that) + private static Dictionary m_OffsetAlignCache = new Dictionary(); + + // offset a pointer to the idx'th field of a type + private static IntPtr OffsetPtr(Type structureType, FieldInfo[] fieldInfo, int idx, IntPtr ptr) + { + if (fieldInfo.Length == 0) + return ptr; + + if (!m_OffsetAlignCache.ContainsKey(structureType)) + { + Int64[] cacheOffsets = new Int64[fieldInfo.Length]; + int initialAlign = AlignOf(fieldInfo[0]); + + Int64 p = 0; + + for (int i = 0; i < fieldInfo.Length; i++) + { + FieldInfo field = fieldInfo[i]; + + int a = AlignOf(field); + int alignment = (int)p % a; + if (alignment != 0) p += a - alignment; + + cacheOffsets[i] = p; + + AddFieldSize(field, ref p); + } + + m_OffsetAlignCache.Add(structureType, initialAlign); + m_OffsetCache.Add(structureType, cacheOffsets); + } + + { + var p = ptr.ToInt64(); + + int a = m_OffsetAlignCache[structureType]; + int alignment = (int)p % a; + if (alignment != 0) p += a - alignment; + + p += m_OffsetCache[structureType][idx]; + + return new IntPtr(p); + } + } + + private static bool CustomAttributeDefined(FieldInfo field) + { + return field.IsDefined(typeof(CustomMarshalAsAttribute), false); + } + + // this function takes a pointer to a templated array (ie. a pointer to a list of Types, and a length) + // and returns an array of that object type, and cleans up the memory if specified. + public static object GetTemplatedArray(IntPtr sourcePtr, Type structureType, bool freeMem) + { + templated_array arr = (templated_array)Marshal.PtrToStructure(sourcePtr, typeof(templated_array)); + + if (structureType == typeof(byte)) + { + byte[] val = new byte[arr.count]; + if(val.Length > 0) + Marshal.Copy(arr.elems, val, 0, val.Length); + return val; + } + else + { + Array val = Array.CreateInstance(structureType, arr.count); + + int sizeInBytes = SizeOf(structureType); + + for (int i = 0; i < val.Length; i++) + { + IntPtr p = new IntPtr((arr.elems.ToInt64() + i * sizeInBytes)); + + val.SetValue(PtrToStructure(p, structureType, freeMem), i); + } + + if (freeMem) + RENDERDOC_FreeArrayMem(arr.elems); + + return val; + } + } + + // specific versions of the above GetTemplatedArray for convenience. + public static string TemplatedArrayToUniString(IntPtr sourcePtr, bool freeMem) + { + templated_array arr = (templated_array)Marshal.PtrToStructure(sourcePtr, typeof(templated_array)); + + string val = Marshal.PtrToStringUni(arr.elems, arr.count); + + if (freeMem) + RENDERDOC_FreeArrayMem(arr.elems); + + return val; + } + + public static string[] TemplatedArrayToUniStringArray(IntPtr sourcePtr, bool freeMem) + { + templated_array arr = (templated_array)Marshal.PtrToStructure(sourcePtr, typeof(templated_array)); + + int arrSize = SizeOf(typeof(templated_array)); + + string[] ret = new string[arr.count]; + for (int i = 0; i < arr.count; i++) + { + IntPtr ptr = new IntPtr((arr.elems.ToInt64() + i * arrSize)); + + ret[i] = TemplatedArrayToUniString(ptr, freeMem); + } + + if (freeMem) + RENDERDOC_FreeArrayMem(arr.elems); + + return ret; + } + + public static object PtrToStructure(IntPtr sourcePtr, Type structureType, bool freeMem) + { + return PtrToStructure(sourcePtr, structureType, freeMem, false); + } + + // take a pointer to a C++ structure of a given type, and convert it into the managed equivalent, + // while handling alignment etc and freeing memory returned if it should be caller-freed + private static object PtrToStructure(IntPtr sourcePtr, Type structureType, bool freeMem, bool isUnion) + { + if (sourcePtr == IntPtr.Zero) + return null; + + // Get instance fields of the structure type. + FieldInfo[] fields = structureType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + object ret = Activator.CreateInstance(structureType); + + try + { + for (int fieldIdx = 0; fieldIdx < fields.Length; fieldIdx++) + { + FieldInfo field = fields[fieldIdx]; + + string name = field.Name; + IntPtr fieldPtr = isUnion ? sourcePtr : OffsetPtr(structureType, fields, fieldIdx, sourcePtr); + + var arrayType = NonArrayType(field.FieldType); + int sizeInBytes = SizeOf(arrayType); + + // no custom attribute, so just use the regular Marshal code + var cma = GetCustomAttr(structureType, fields, fieldIdx); + if (cma == null) + { + if (field.FieldType.IsEnum) + field.SetValue(ret, (VarType)Marshal.ReadInt32(fieldPtr)); + else + field.SetValue(ret, Marshal.PtrToStructure(fieldPtr, field.FieldType)); + } + else + { + switch (cma.CustomType) + { + case CustomUnmanagedType.CustomClass: + field.SetValue(ret, PtrToStructure(fieldPtr, field.FieldType, freeMem)); + break; + case CustomUnmanagedType.CustomClassPointer: + IntPtr ptr = Marshal.ReadIntPtr(fieldPtr); + if (ptr == IntPtr.Zero) + field.SetValue(ret, null); + else + field.SetValue(ret, PtrToStructure(ptr, field.FieldType, freeMem)); + break; + case CustomUnmanagedType.Union: + field.SetValue(ret, PtrToStructure(fieldPtr, field.FieldType, freeMem, true)); + break; + case CustomUnmanagedType.Skip: + break; + case CustomUnmanagedType.FixedArray: + { + if(cma.FixedType == CustomFixedType.Float) + { + float[] val = new float[cma.FixedLength]; + Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); + field.SetValue(ret, val); + } + else if (cma.FixedType == CustomFixedType.UInt16) + { + Int16[] val = new Int16[cma.FixedLength]; + Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); + UInt16[] realval = new UInt16[cma.FixedLength]; + for (int i = 0; i < val.Length; i++) + realval[i] = unchecked((UInt16)val[i]); + field.SetValue(ret, val); + } + else if (cma.FixedType == CustomFixedType.Int32) + { + Int32[] val = new Int32[cma.FixedLength]; + Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); + field.SetValue(ret, val); + } + else if (cma.FixedType == CustomFixedType.UInt32) + { + Int32[] val = new Int32[cma.FixedLength]; + Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); + UInt32[] realval = new UInt32[cma.FixedLength]; + for (int i = 0; i < val.Length; i++) + realval[i] = unchecked((UInt32)val[i]); + field.SetValue(ret, realval); + } + else + { + Array val = Array.CreateInstance(arrayType, cma.FixedLength); + + for (int i = 0; i < val.Length; i++) + { + IntPtr p = new IntPtr((fieldPtr.ToInt64() + i * sizeInBytes)); + + val.SetValue(PtrToStructure(p, arrayType, freeMem), i); + } + + field.SetValue(ret, val); + } + break; + } + case CustomUnmanagedType.AsciiTemplatedString: + { + // templated_array must be pointer-aligned + long alignment = fieldPtr.ToInt64() % IntPtr.Size; + if (alignment != 0) + { + fieldPtr = new IntPtr(fieldPtr.ToInt64() + IntPtr.Size - alignment); + } + + templated_array arr = (templated_array)Marshal.PtrToStructure(fieldPtr, typeof(templated_array)); + if (field.FieldType == typeof(string)) + { + if (arr.elems == IntPtr.Zero) + field.SetValue(ret, ""); + else + field.SetValue(ret, Marshal.PtrToStringAnsi(arr.elems, arr.count)); + } + else + { + throw new NotImplementedException("non-string element marked to marshal as AsciiTemplatedString"); + } + if(freeMem) + RENDERDOC_FreeArrayMem(arr.elems); + break; + } + case CustomUnmanagedType.WideTemplatedString: + case CustomUnmanagedType.TemplatedArray: + { + // templated_array must be pointer-aligned + long alignment = fieldPtr.ToInt64() % IntPtr.Size; + if (alignment != 0) + { + fieldPtr = new IntPtr(fieldPtr.ToInt64() + IntPtr.Size - alignment); + } + + templated_array arr = (templated_array)Marshal.PtrToStructure(fieldPtr, typeof(templated_array)); + if (field.FieldType == typeof(string)) + { + if (arr.elems == IntPtr.Zero) + field.SetValue(ret, ""); + else + field.SetValue(ret, Marshal.PtrToStringUni(arr.elems, arr.count)); + } + else + { + if (field.FieldType.IsArray && arrayType == typeof(byte)) + { + byte[] val = new byte[arr.count]; + if(val.Length > 0) + Marshal.Copy(arr.elems, val, 0, val.Length); + field.SetValue(ret, val); + } + else if (field.FieldType.IsArray) + { + Array val = Array.CreateInstance(arrayType, arr.count); + + for (int i = 0; i < val.Length; i++) + { + IntPtr p = new IntPtr((arr.elems.ToInt64() + i * sizeInBytes)); + + val.SetValue(PtrToStructure(p, arrayType, freeMem), i); + } + + field.SetValue(ret, val); + } + else + { + throw new NotImplementedException("non-array element marked to marshal as TemplatedArray"); + } + } + if(freeMem) + RENDERDOC_FreeArrayMem(arr.elems); + break; + } + default: + throw new NotImplementedException("Unexpected attribute"); + } + } + } + + MethodInfo postMarshal = structureType.GetMethod("PostMarshal", BindingFlags.NonPublic | BindingFlags.Instance); + if (postMarshal != null) + postMarshal.Invoke(ret, new object[] { }); + } + catch (Exception ex) + { + System.Diagnostics.Debug.Fail(ex.Message); + } + + return ret; + } + } +} \ No newline at end of file diff --git a/renderdocui/Interop/D3D11PipelineState.cs b/renderdocui/Interop/D3D11PipelineState.cs new file mode 100644 index 0000000000..196446a834 --- /dev/null +++ b/renderdocui/Interop/D3D11PipelineState.cs @@ -0,0 +1,344 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace renderdoc +{ + [StructLayout(LayoutKind.Sequential)] + public class D3D11PipelineState + { + [StructLayout(LayoutKind.Sequential)] + public class InputAssembler + { + private void PostMarshal() + { + if (_ptr_Bytecode != IntPtr.Zero) + Bytecode = (ShaderReflection)CustomMarshal.PtrToStructure(_ptr_Bytecode, typeof(ShaderReflection), false); + else + Bytecode = null; + + _ptr_Bytecode = IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + public class LayoutInput + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string SemanticName; + public UInt32 SemanticIndex; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ResourceFormat Format; + public UInt32 InputSlot; + public UInt32 ByteOffset; + public bool PerInstance; + public UInt32 InstanceDataStepRate; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public LayoutInput[] layouts; + public ResourceId layout; + private IntPtr _ptr_Bytecode; + [CustomMarshalAs(CustomUnmanagedType.Skip)] + public ShaderReflection Bytecode; + + [StructLayout(LayoutKind.Sequential)] + public class VertexBuffer + { + public ResourceId Buffer; + public UInt32 Stride; + public UInt32 Offset; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public VertexBuffer[] vbuffers; + + [StructLayout(LayoutKind.Sequential)] + public class IndexBuffer + { + public ResourceId Buffer; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ResourceFormat Format; + public UInt32 Offset; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public IndexBuffer ibuffer; + + public PrimitiveTopology Topology; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public InputAssembler m_IA; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderStage + { + private void PostMarshal() + { + if (_ptr_ShaderDetails != IntPtr.Zero) + ShaderDetails = (ShaderReflection)CustomMarshal.PtrToStructure(_ptr_ShaderDetails, typeof(ShaderReflection), false); + else + ShaderDetails = null; + + _ptr_ShaderDetails = IntPtr.Zero; + } + + public ResourceId Shader; + private IntPtr _ptr_ShaderDetails; + [CustomMarshalAs(CustomUnmanagedType.Skip)] + public ShaderReflection ShaderDetails; + + public ShaderStageType stage; + + [StructLayout(LayoutKind.Sequential)] + public class ResourceView + { + public ResourceId View; + public ResourceId Resource; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Type; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ResourceFormat Format; + + public bool Structured; + public UInt32 BufferStructCount; + + // Buffer (SRV) + public UInt32 ElementOffset; + public UInt32 ElementWidth; + + // Buffer (UAV) + public UInt32 FirstElement; + public UInt32 NumElements; + + // BufferEx + public UInt32 Flags; + + // Texture + public UInt32 HighestMip; + public UInt32 NumMipLevels; + + public UInt32 MipSlice; + + // Texture Array + public UInt32 ArraySize; + public UInt32 FirstArraySlice; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ResourceView[] SRVs; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ResourceView[] UAVs; + + [StructLayout(LayoutKind.Sequential)] + public class Sampler + { + public ResourceId Samp; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string AddressU, AddressV, AddressW; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4)] + public float[] BorderColor; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Comparison; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Filter; + public UInt32 MaxAniso; + public float MaxLOD; + public float MinLOD; + public float MipLODBias; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public Sampler[] Samplers; + + [StructLayout(LayoutKind.Sequential)] + public class CBuffer + { + public ResourceId Buffer; + public UInt32 VecOffset; + public UInt32 VecCount; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public CBuffer[] ConstantBuffers; + + [StructLayout(LayoutKind.Sequential)] + public class ClassInstance + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + string name; + }; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ClassInstance[] ClassInstances; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderStage m_VS, m_HS, m_DS, m_GS, m_PS, m_CS; + + [StructLayout(LayoutKind.Sequential)] + public class Streamout + { + [StructLayout(LayoutKind.Sequential)] + public class Output + { + public ResourceId Buffer; + public UInt32 Offset; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public Output[] Outputs; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public Streamout m_SO; + + [StructLayout(LayoutKind.Sequential)] + public class Rasterizer + { + [StructLayout(LayoutKind.Sequential)] + public class Viewport + { + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 2)] + public float[] TopLeft; + public float Width, Height; + public float MinDepth, MaxDepth; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public Viewport[] Viewports; + + [StructLayout(LayoutKind.Sequential)] + public class Scissor + { + public Int32 left, top, right, bottom; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public Scissor[] Scissors; + + [StructLayout(LayoutKind.Sequential)] + public class RasterizerState + { + public ResourceId State; + public TriangleFillMode FillMode; + public TriangleCullMode CullMode; + public bool FrontCCW; + public Int32 DepthBias; + public float DepthBiasClamp; + public float SlopeScaledDepthBias; + public bool DepthClip; + public bool ScissorEnable; + public bool MultisampleEnable; + public bool AntialiasedLineEnable; + public UInt32 ForcedSampleCount; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public RasterizerState m_State; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public Rasterizer m_RS; + + [StructLayout(LayoutKind.Sequential)] + public class OutputMerger + { + [StructLayout(LayoutKind.Sequential)] + public class DepthStencilState + { + public ResourceId State; + public bool DepthEnable; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string DepthFunc; + public bool DepthWrites; + public bool StencilEnable; + public byte StencilReadMask; + public byte StencilWriteMask; + + [StructLayout(LayoutKind.Sequential)] + public class StencilOp + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string FailOp; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string DepthFailOp; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string PassOp; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Func; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public StencilOp m_FrontFace, m_BackFace; + + public UInt32 StencilRef; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public DepthStencilState m_State; + + [StructLayout(LayoutKind.Sequential)] + public class BlendState + { + public ResourceId State; + + public bool AlphaToCoverage; + public bool IndependentBlend; + + [StructLayout(LayoutKind.Sequential)] + public class RTBlend + { + [StructLayout(LayoutKind.Sequential)] + public class BlendOp + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Source; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Destination; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string Operation; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public BlendOp m_Blend, m_AlphaBlend; + + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string LogicOp; + + public bool Enabled; + public bool LogicEnabled; + public byte WriteMask; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public RTBlend[] Blends; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4)] + public float[] BlendFactor; + public UInt32 SampleMask; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public BlendState m_BlendState; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderStage.ResourceView[] RenderTargets; + + public UInt32 UAVStartSlot; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderStage.ResourceView[] UAVs; + + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderStage.ResourceView DepthTarget; + public bool DepthReadOnly; + public bool StencilReadOnly; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public OutputMerger m_OM; + }; +} diff --git a/renderdocui/Interop/Enums.cs b/renderdocui/Interop/Enums.cs new file mode 100644 index 0000000000..816ac811d3 --- /dev/null +++ b/renderdocui/Interop/Enums.cs @@ -0,0 +1,467 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; + +// from replay_enums.h + +namespace renderdoc +{ + public enum VarType + { + Float = 0, + Int, + UInt, + Double, + }; + + public enum FormatComponentType + { + None = 0, + Float, + UNorm, + UNorm_SRGB, + SNorm, + UInt, + SInt, + Depth, + Double, + }; + + public enum ShaderResourceType + { + None, + Buffer, + Texture1D, + Texture1DArray, + Texture2D, + Texture2DArray, + Texture2DMS, + Texture2DMSArray, + Texture3D, + TextureCube, + TextureCubeArray, + }; + + public enum SystemAttribute + { + None = 0, + Position, + ClipDistance, + CullDistance, + RTIndex, + ViewportIndex, + VertexIndex, + PrimitiveIndex, + InstanceIndex, + DispatchThreadIndex, + GroupIndex, + GroupFlatIndex, + GroupThreadIndex, + GSInstanceIndex, + OutputControlPointIndex, + DomainLocation, + IsFrontFace, + MSAACoverage, + MSAASampleIndex, + OuterTessFactor, + InsideTessFactor, + ColourOutput, + DepthOutput, + DepthOutputGreaterEqual, + DepthOutputLessEqual, + }; + + // replay_render.h + + public enum OutputType + { + None = 0, + TexDisplay, + MeshDisplay, + }; + + public enum MeshDataStage + { + Unknown = 0, + VSIn, + VSOut, + GSOut, + }; + + public enum TextureDisplayOverlay + { + None = 0, + Drawcall, + Wireframe, + DepthBoth, + StencilBoth, + ViewportScissor, + NaN, + Clipping, + }; + + public enum SpecialFormat + { + Unknown = 0, + BC1, + BC2, + BC3, + BC4, + BC5, + BC6, + BC7, + R10G10B10A2, + R11G11B10, + B5G6R5, + B5G5R5A1, + R9G9B9E5, + B8G8R8A8, + B4G4R4A4, + D24S8, + D32S8, + YUV, + }; + + public enum APIPipelineStateType + { + D3D11, + OpenGL, + }; + + public enum PrimitiveTopology + { + Unknown, + PointList, + LineList, + LineStrip, + LineLoop, + TriangleList, + TriangleStrip, + TriangleFan, + LineList_Adj, + LineStrip_Adj, + TriangleList_Adj, + TriangleStrip_Adj, + PatchList, + PatchList_1CPs = PatchList, + PatchList_2CPs, + PatchList_3CPs, + PatchList_4CPs, + PatchList_5CPs, + PatchList_6CPs, + PatchList_7CPs, + PatchList_8CPs, + PatchList_9CPs, + PatchList_10CPs, + PatchList_11CPs, + PatchList_12CPs, + PatchList_13CPs, + PatchList_14CPs, + PatchList_15CPs, + PatchList_16CPs, + PatchList_17CPs, + PatchList_18CPs, + PatchList_19CPs, + PatchList_20CPs, + PatchList_21CPs, + PatchList_22CPs, + PatchList_23CPs, + PatchList_24CPs, + PatchList_25CPs, + PatchList_26CPs, + PatchList_27CPs, + PatchList_28CPs, + PatchList_29CPs, + PatchList_30CPs, + PatchList_31CPs, + PatchList_32CPs, + }; + + [Flags] + public enum BufferCreationFlags + { + VB = 0x1, + IB = 0x2, + }; + + [Flags] + public enum TextureCreationFlags + { + SRV = 0x1, + RTV = 0x2, + DSV = 0x4, + UAV = 0x8, + SwapBuffer = 0x10, + }; + + public enum ShaderStageType + { + Vertex = 0, + + Hull, + Tess_Control = Hull, + + Domain, + Tess_Eval = Domain, + + Geometry, + + Pixel, + Fragment = Pixel, + + Compute, + }; + + public enum DebugMessageCategory + { + Defined = 0, + Miscellaneous, + Initialization, + Cleanup, + Compilation, + Creation, + Setting, + Getting, + Manipulation, + Execution, + Shaders, + Deprecated, + Undefined, + Portability, + Performance, + }; + + public enum DebugMessageSeverity + { + Corruption = 0, + Error, + Warning, + Info, + }; + + public enum ResourceUsage + { + None, + + IA_VB, + IA_IB, + + VS_CB, + HS_CB, + DS_CB, + GS_CB, + PS_CB, + CS_CB, + + SO, + + VS_SRV, + HS_SRV, + DS_SRV, + GS_SRV, + PS_SRV, + CS_SRV, + + CS_UAV, + PS_UAV, + + OM_RTV, + OM_DSV, + + Clear, + }; + + [Flags] + public enum DrawcallFlags + { + // types + Clear = 0x01, + Drawcall = 0x02, + Dispatch = 0x04, + CmdList = 0x08, + SetMarker = 0x10, + PushMarker = 0x20, + Present = 0x40, + + // flags + UseIBuffer = 0x100, + Instanced = 0x200, + Auto = 0x400, + Indirect = 0x800, + }; + + public enum SolidShadeMode + { + None = 0, + Solid, + Lit, + Tex, + VertCol, + }; + + public enum TriangleFillMode + { + Solid = 0, + Wireframe, + }; + + public enum TriangleCullMode + { + None = 0, + Front, + Back, + }; + + public enum ReplayCreateStatus + { + Success = 0, + UnknownError, + InternalError, + NetworkIOFailed, + FileIOFailed, + FileIncompatibleVersion, + FileCorrupted, + APIUnsupported, + APIInitFailed, + APIIncompatibleVersion, + APIHardwareUnsupported, + }; + + public enum RemoteMessageType + { + Unknown = 0, + Disconnected, + Busy, + Noop, + NewCapture, + CaptureCopied, + RegisterAPI, + }; + + public static class EnumString + { + public static string Str(this VarType type) + { + switch (type) + { + case VarType.Double: return "double"; + case VarType.Float: return "float"; + case VarType.Int: return "int"; + case VarType.UInt: return "uint"; + } + + return "Unknown Type"; + } + + public static string Str(this ReplayCreateStatus status) + { + switch (status) + { + case ReplayCreateStatus.Success: return "Success"; + case ReplayCreateStatus.UnknownError: return "Unknown Error"; + case ReplayCreateStatus.InternalError: return "Internal Error"; + case ReplayCreateStatus.NetworkIOFailed: return "Network I/O operation failed"; + case ReplayCreateStatus.FileIOFailed: return "File I/O operation failed"; + case ReplayCreateStatus.FileIncompatibleVersion: return "Logfile is of an incompatible version"; + case ReplayCreateStatus.FileCorrupted: return "Logfile data is corrupted"; + case ReplayCreateStatus.APIUnsupported: return "API used in logfile is not supported"; + case ReplayCreateStatus.APIInitFailed: return "Replay API failed to initialise"; + case ReplayCreateStatus.APIIncompatibleVersion: return "API-speciifc data used in logfile is of an incompatible version"; + case ReplayCreateStatus.APIHardwareUnsupported: return "Your hardware or software configuration doesn't meet this API's minimum requirements"; + } + + return "Unknown Error Code"; + } + + public static string Str(this ResourceUsage usage) + { + switch (usage) + { + case ResourceUsage.IA_VB: return "Vertex Buffer"; + case ResourceUsage.IA_IB: return "Index Buffer"; + + case ResourceUsage.VS_CB: return "VS - Constant Buffer"; + case ResourceUsage.GS_CB: return "GS - Constant Buffer"; + case ResourceUsage.HS_CB: return "HS - Constant Buffer"; + case ResourceUsage.DS_CB: return "DS - Constant Buffer"; + case ResourceUsage.CS_CB: return "CS - Constant Buffer"; + case ResourceUsage.PS_CB: return "PS - Constant Buffer"; + + case ResourceUsage.SO: return "Stream Out"; + + case ResourceUsage.VS_SRV: return "VS - Resource"; + case ResourceUsage.GS_SRV: return "GS - Resource"; + case ResourceUsage.HS_SRV: return "HS - Resource"; + case ResourceUsage.DS_SRV: return "DS - Resource"; + case ResourceUsage.CS_SRV: return "CS - Resource"; + case ResourceUsage.PS_SRV: return "PS - Resource"; + + case ResourceUsage.CS_UAV: return "CS - UAV"; + case ResourceUsage.PS_UAV: return "PS - UAV"; + + case ResourceUsage.OM_RTV: return "Rendertarget"; + case ResourceUsage.OM_DSV: return "Depthstencil"; + + case ResourceUsage.Clear: return "Clear"; + } + + return "Unknown Usage String"; + } + + public static string Str(this SystemAttribute systemValue) + { + switch (systemValue) + { + case SystemAttribute.None: return ""; + case SystemAttribute.Position: return "SV_Position"; + case SystemAttribute.ClipDistance: return "SV_ClipDistance"; + case SystemAttribute.CullDistance: return "SV_CullDistance"; + case SystemAttribute.RTIndex: return "SV_RenderTargetIndex"; + case SystemAttribute.ViewportIndex: return "SV_ViewportIndex"; + case SystemAttribute.VertexIndex: return "SV_VertexID"; + case SystemAttribute.PrimitiveIndex: return "SV_PrimitiveID"; + case SystemAttribute.InstanceIndex: return "SV_InstanceID"; + case SystemAttribute.DispatchThreadIndex: return "SV_DispatchThreadID"; + case SystemAttribute.GroupIndex: return "SV_GroupID"; + case SystemAttribute.GroupFlatIndex: return "SV_GroupIndex"; + case SystemAttribute.GroupThreadIndex: return "SV_GroupThreadID"; + case SystemAttribute.GSInstanceIndex: return "SV_GSInstanceID"; + case SystemAttribute.OutputControlPointIndex: return "SV_OutputControlPointID"; + case SystemAttribute.DomainLocation: return "SV_DomainLocation"; + case SystemAttribute.IsFrontFace: return "SV_IsFrontFace"; + case SystemAttribute.MSAACoverage: return "SV_Coverage"; + case SystemAttribute.MSAASampleIndex: return "SV_SampleIndex"; + case SystemAttribute.OuterTessFactor: return "SV_TessFactor"; + case SystemAttribute.InsideTessFactor: return "SV_InsideTessFactor"; + case SystemAttribute.ColourOutput: return "SV_Target"; + case SystemAttribute.DepthOutput: return "SV_Depth"; + case SystemAttribute.DepthOutputGreaterEqual: return "SV_DepthGreaterEqual"; + case SystemAttribute.DepthOutputLessEqual: return "SV_DepthLessEqual"; + } + + return "SV_Unknown"; + } + } +} diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs new file mode 100644 index 0000000000..76bec0a0d3 --- /dev/null +++ b/renderdocui/Interop/FetchInfo.cs @@ -0,0 +1,467 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace renderdoc +{ + public struct Vec3f + { + public Vec3f(float X, float Y, float Z) { x = X; y = Y; z = Z; } + public Vec3f(Vec3f v) { x = v.x; y = v.y; z = v.z; } + public Vec3f(FloatVector v) { x = v.x; y = v.y; z = v.z; } + + public float Length() + { + return (float)Math.Sqrt(x * x + y * y + z * z); + } + + public Vec3f Sub(Vec3f o) + { + return new Vec3f(x - o.x, + y - o.y, + z - o.z); + } + + public void Mul(float f) + { + x *= f; + y *= f; + z *= f; + } + + public float x, y, z; + }; + + public struct Vec4f + { + public float x, y, z, w; + }; + + [StructLayout(LayoutKind.Sequential)] + public struct FloatVector + { + public FloatVector(float X, float Y, float Z, float W) { x = X; y = Y; z = Z; w = W; } + public FloatVector(float X, float Y, float Z) { x = X; y = Y; z = Z; w = 1; } + public FloatVector(Vec3f v) { x = v.x; y = v.y; z = v.z; w = 1; } + + public float x, y, z, w; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ResourceFormat + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern float Maths_HalfToFloat(UInt16 half); + + public ResourceFormat() + { + rawType = 0; + special = false; + specialFormat = SpecialFormat.Unknown; + + compType = FormatComponentType.None; + compCount = 0; + compByteWidth = 0; + srgbCorrected = false; + + strname = ""; + } + + public ResourceFormat(FormatComponentType type, UInt32 count, UInt32 byteWidth) + { + rawType = 0; + special = false; + specialFormat = SpecialFormat.Unknown; + + compType = type; + compCount = count; + compByteWidth = byteWidth; + srgbCorrected = false; + + strname = ""; + } + + public UInt32 rawType; + + // indicates it's not a type represented with the members below + // usually this means non-uniform across components or block compressed + public bool special; + public SpecialFormat specialFormat; + + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string strname; + + public UInt32 compCount; + public UInt32 compByteWidth; + public FormatComponentType compType; + + public bool srgbCorrected; + + public override string ToString() + { + return strname; + } + + public override bool Equals(Object obj) + { + return obj is ResourceFormat && this == (ResourceFormat)obj; + } + public override int GetHashCode() + { + return rawType.GetHashCode(); + } + public static bool operator ==(ResourceFormat x, ResourceFormat y) + { + return x.rawType == y.rawType; + } + public static bool operator !=(ResourceFormat x, ResourceFormat y) + { + return !(x == y); + } + + public float ConvertFromHalf(UInt16 comp) + { + return Maths_HalfToFloat(comp); + } + + public string Interpret(UInt32 comp) + { + if (compByteWidth != 4 || compType == FormatComponentType.Float) throw new ArgumentException(); + + if (compType == FormatComponentType.SInt) + { + int cast = (int)comp; + return String.Format("{0}", cast); + } + else if (compType == FormatComponentType.UInt) + { + return String.Format("{0}", comp); + } + + throw new ArgumentException(); + } + + public string Interpret(UInt16 comp) + { + if (compByteWidth != 2 || compType == FormatComponentType.Float) throw new ArgumentException(); + + if (compType == FormatComponentType.SInt) + { + Int16 cast = (Int16)comp; + return String.Format("{0}", cast); + } + else if (compType == FormatComponentType.UInt) + { + return String.Format("{0}", comp); + } + else if (compType == FormatComponentType.UNorm) + { + float f = (float)comp / (float)UInt16.MaxValue; + return Formatter.Format(f); + } + else if (compType == FormatComponentType.UNorm_SRGB) + { + float f = (float)comp / (float)UInt16.MaxValue; + return Formatter.Format(f); + } + else if (compType == FormatComponentType.SNorm) + { + Int16 cast = (Int16)comp; + + float f = -1.0f; + + if (cast == -32768) + f = -1.0f; + else + f = ((float)cast) / 32767.0f; + + return Formatter.Format(f); + } + + throw new ArgumentException(); + } + + public string Interpret(byte comp) + { + if (compByteWidth != 1 || compType == FormatComponentType.Float) throw new ArgumentException(); + + if (compType == FormatComponentType.SInt) + { + sbyte cast = (sbyte)comp; + return String.Format("{0}", cast); + } + else if (compType == FormatComponentType.UInt) + { + return String.Format("{0}", comp); + } + else if (compType == FormatComponentType.UNorm) + { + float f = ((float)comp) / 255.0f; + return Formatter.Format(f); + } + else if (compType == FormatComponentType.UNorm_SRGB) + { + float f = ((float)comp) / 255.0f; + return Formatter.Format(f); + } + else if (compType == FormatComponentType.SNorm) + { + sbyte cast = (sbyte)comp; + + float f = -1.0f; + + if (cast == -128) + f = -1.0f; + else + f = ((float)cast) / 127.0f; + + return Formatter.Format(f); + } + + throw new ArgumentException(); + } + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchBuffer + { + public ResourceId ID; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string name; + public bool customName; + public UInt32 length; + public UInt32 structureSize; + public BufferCreationFlags creationFlags; + public UInt64 byteSize; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchTexture + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string name; + public bool customName; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ResourceFormat format; + public UInt32 dimension; + public UInt32 width, height, depth; + public ResourceId ID; + public bool cubemap; + public UInt32 mips; + public UInt32 arraysize; + public UInt32 numSubresources; + public TextureCreationFlags creationFlags; + public UInt32 msQual, msSamp; + public UInt64 byteSize; + }; + + [StructLayout(LayoutKind.Sequential)] + public class OutputConfig + { + public OutputType m_Type = OutputType.None; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameInfo + { + public UInt32 frameNumber; + public UInt32 firstEvent; + public UInt64 fileOffset; + public ResourceId immContextId; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchAPIEvent + { + public UInt32 eventID; + + public ResourceId context; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt64[] callstack; + + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string eventDesc; + + public UInt64 fileOffset; + }; + + [StructLayout(LayoutKind.Sequential)] + public class DebugMessage + { + public DebugMessageCategory category; + public DebugMessageSeverity severity; + public UInt32 messageID; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string description; + }; + + [StructLayout(LayoutKind.Sequential)] + public class EventUsage + { + public UInt32 eventID; + public ResourceUsage usage; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchDrawcall + { + public UInt32 eventID, drawcallID; + + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string name; + + public DrawcallFlags flags; + + public UInt32 numIndices; + public UInt32 numInstances; + public UInt32 indexOffset; + public UInt32 vertexOffset; + public UInt32 instanceOffset; + + public ResourceId context; + + public double duration; + + public Int64 parentDrawcall; + public Int64 previousDrawcall; + public Int64 nextDrawcall; + + [CustomMarshalAs(CustomUnmanagedType.Skip)] + public FetchDrawcall parent; + [CustomMarshalAs(CustomUnmanagedType.Skip)] + public FetchDrawcall previous; + [CustomMarshalAs(CustomUnmanagedType.Skip)] + public FetchDrawcall next; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 8)] + public ResourceId[] outputs; + public ResourceId depthOut; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public FetchAPIEvent[] events; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public FetchDrawcall[] children; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public DebugMessage[] debugMessages; + }; + + [StructLayout(LayoutKind.Sequential)] + public class MeshDisplay + { + public MeshDataStage type = MeshDataStage.Unknown; + + public bool arcballCamera = true; + public FloatVector cameraPos = new FloatVector(); + public FloatVector cameraRot = new FloatVector(); + + public bool ortho = false; + public float fov = 90.0f; + public float aspect = 0.0f, nearPlane = 0.0f, farPlane = 0.0f; + + public bool thisDrawOnly = true; + + public bool showVerts; + + [StructLayout(LayoutKind.Sequential)] + public struct HighlightVerts + { + public FloatVector v0; + public FloatVector v1; + public FloatVector v2; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public HighlightVerts highlight = new HighlightVerts(); + + public FloatVector prevMeshColour = new FloatVector(); + public FloatVector currentMeshColour = new FloatVector(); + + public SolidShadeMode solidShadeMode = SolidShadeMode.None; + public bool wireframeDraw = true; + }; + + [StructLayout(LayoutKind.Sequential)] + public class TextureDisplay + { + public ResourceId texid = ResourceId.Null; + public float rangemin = 0.0f; + public float rangemax = 1.0f; + public float scale = 1.0f; + public bool Red = true, Green = true, Blue = true, Alpha = false; + public float HDRMul = -1.0f; + public ResourceId CustomShader = ResourceId.Null; + public UInt32 mip = 0; + public UInt32 sliceFace = 0; + public bool rawoutput = false; + + public float offx = 0.0f, offy = 0.0f; + + public FloatVector lightBackgroundColour = new FloatVector(0.666f, 0.666f, 0.666f); + public FloatVector darkBackgroundColour = new FloatVector(0.333f, 0.333f, 0.333f); + + public TextureDisplayOverlay overlay = TextureDisplayOverlay.None; + }; + + [StructLayout(LayoutKind.Sequential)] + public class APIProperties + { + public APIPipelineStateType pipelineType; + }; + + [StructLayout(LayoutKind.Sequential)] + public class PixelValue + { + [StructLayout(LayoutKind.Sequential)] + public struct ValueUnion + { + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4, FixedType = CustomFixedType.UInt32)] + public UInt32[] u; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4, FixedType = CustomFixedType.Float)] + public float[] f; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4, FixedType = CustomFixedType.Int32)] + public Int32[] i; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4, FixedType = CustomFixedType.UInt16)] + public UInt16[] u16; + }; + + [CustomMarshalAs(CustomUnmanagedType.Union)] + public ValueUnion value; + }; + + [StructLayout(LayoutKind.Sequential)] + public class PostVSMeshData + { + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public byte[] buf; + public UInt32 numVerts; + public PrimitiveTopology topo; + }; +} diff --git a/renderdocui/Interop/Formatter.cs b/renderdocui/Interop/Formatter.cs new file mode 100644 index 0000000000..57ea8685e1 --- /dev/null +++ b/renderdocui/Interop/Formatter.cs @@ -0,0 +1,154 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace renderdoc +{ + public class Formatter + { + public static String Format(double f) + { + if (f != 0 && (Math.Abs(f) < m_ExponentialNegValue || Math.Abs(f) > m_ExponentialPosValue)) + return String.Format(m_EFormatter, f); + + return String.Format(m_FFormatter, f); + } + + public static String Format(float f) + { + if (f != 0 && (Math.Abs(f) < m_ExponentialNegValue || Math.Abs(f) > m_ExponentialPosValue)) + return String.Format(m_EFormatter, f); + + return String.Format(m_FFormatter, f); + } + + public static String Format(UInt32 u) + { + return String.Format("{0}", u); + } + + public static String Format(Int32 i) + { + return String.Format("{0}", i); + } + + public static int MaxFigures + { + get + { + return m_MaxFigures; + } + + set + { + if (value >= 2) + m_MaxFigures = value; + else + m_MaxFigures = 2; + + UpdateFormatters(); + } + } + + public static int MinFigures + { + get + { + return m_MinFigures; + } + + set + { + if (value >= 0) + m_MinFigures = value; + else + m_MinFigures = 0; + + UpdateFormatters(); + } + } + + public static int ExponentialNegCutoff + { + get + { + return m_ExponentialNegCutoff; + } + + set + { + if (value >= 0) + m_ExponentialNegCutoff = value; + else + m_ExponentialNegCutoff = 0; + + m_ExponentialNegValue = Math.Pow(10.0, -m_ExponentialNegCutoff); + } + } + + public static int ExponentialPosCutoff + { + get + { + return m_ExponentialPosCutoff; + } + + set + { + if (value >= 0) + m_ExponentialPosCutoff = value; + else + m_ExponentialPosCutoff = 0; + + m_ExponentialPosValue = Math.Pow(10.0, m_ExponentialPosCutoff); + } + } + + private static int m_MinFigures = 2; + private static int m_MaxFigures = 5; + private static int m_ExponentialNegCutoff = 5; + private static int m_ExponentialPosCutoff = 7; + + private static double m_ExponentialNegValue = 0.00001; // 10(-5) + private static double m_ExponentialPosValue = 10000000.0; // 10(7) + private static string m_EFormatter = "{0:E5}"; + private static string m_FFormatter = "{0:0.00###}"; + + private static void UpdateFormatters() + { + m_EFormatter = "{0:" + String.Format("E{0}", m_MaxFigures) + "}"; + m_FFormatter = "{0:0."; + + int i = 0; + + for (; i < m_MinFigures; i++) m_FFormatter += "0"; + for (; i < m_MaxFigures; i++) m_FFormatter += "#"; + m_FFormatter += "}"; + } + }; +} diff --git a/renderdocui/Interop/GLPipelineState.cs b/renderdocui/Interop/GLPipelineState.cs new file mode 100644 index 0000000000..5f46406a61 --- /dev/null +++ b/renderdocui/Interop/GLPipelineState.cs @@ -0,0 +1,122 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace renderdoc +{ + [StructLayout(LayoutKind.Sequential)] + public class GLPipelineState + { + [StructLayout(LayoutKind.Sequential)] + public class VertexInputs + { + [StructLayout(LayoutKind.Sequential)] + public class VertexAttribute + { + public bool Enabled; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ResourceFormat Format; + public UInt32 BufferSlot; + public UInt32 RelativeOffset; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public VertexAttribute[] attributes; + + [StructLayout(LayoutKind.Sequential)] + public class VertexBuffer + { + public ResourceId Buffer; + public UInt32 Stride; + public UInt32 Offset; + public bool PerInstance; + public UInt32 Divisor; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public VertexBuffer[] vbuffers; + + [StructLayout(LayoutKind.Sequential)] + public class IndexBuffer + { + public ResourceId Buffer; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ResourceFormat Format; + public UInt32 Offset; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public IndexBuffer ibuffer; + + public PrimitiveTopology Topology; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public VertexInputs m_VtxIn; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderStage + { + private void PostMarshal() + { + if (_ptr_ShaderDetails != IntPtr.Zero) + ShaderDetails = (ShaderReflection)CustomMarshal.PtrToStructure(_ptr_ShaderDetails, typeof(ShaderReflection), false); + else + ShaderDetails = null; + + _ptr_ShaderDetails = IntPtr.Zero; + } + + public ResourceId Shader; + private IntPtr _ptr_ShaderDetails; + [CustomMarshalAs(CustomUnmanagedType.Skip)] + public ShaderReflection ShaderDetails; + + public ShaderStageType stage; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderStage m_VS, m_TCS, m_TES, m_GS, m_FS, m_CS; + + [StructLayout(LayoutKind.Sequential)] + public class Texture + { + public ResourceId Resource; + + public UInt32 FirstSlice; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public Texture[] Textures; + + [StructLayout(LayoutKind.Sequential)] + public class FrameBuffer + { + public ResourceId FBO; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ResourceId[] Color; + public ResourceId Depth; + public ResourceId Stencil; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FrameBuffer m_FB; + } +} diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs new file mode 100644 index 0000000000..ce3df5dc8e --- /dev/null +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -0,0 +1,874 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; + +namespace renderdoc +{ + [StructLayout(LayoutKind.Sequential)] + public class RemoteMessage + { + public RemoteMessageType Type; + + [StructLayout(LayoutKind.Sequential)] + public struct NewCaptureData + { + public UInt32 ID; + public UInt64 timestamp; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public byte[] thumbnail; + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string localpath; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public NewCaptureData NewCapture; + + [StructLayout(LayoutKind.Sequential)] + public struct RegisterAPIData + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string APIName; + }; + + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public RegisterAPIData RegisterAPI; + + [StructLayout(LayoutKind.Sequential)] + public struct BusyData + { + [CustomMarshalAs(CustomUnmanagedType.WideTemplatedString)] + public string ClientName; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public BusyData Busy; + }; + + public class ReplayOutput + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_SetOutputConfig(IntPtr real, OutputConfig o); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_SetTextureDisplay(IntPtr real, TextureDisplay o); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_SetMeshDisplay(IntPtr real, MeshDisplay o); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_ClearThumbnails(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_AddThumbnail(IntPtr real, IntPtr wnd, ResourceId texID); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_Display(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_SetPixelContext(IntPtr real, IntPtr wnd); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_SetPixelContextLocation(IntPtr real, UInt32 x, UInt32 y); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void ReplayOutput_DisablePixelContext(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayOutput_PickPixel(IntPtr real, ResourceId texID, bool customShader, + UInt32 x, UInt32 y, UInt32 sliceFace, UInt32 mip, IntPtr outval); + + private IntPtr m_Real = IntPtr.Zero; + + public ReplayOutput(IntPtr real) { m_Real = real; } + + public bool SetOutputConfig(OutputConfig o) + { + return ReplayOutput_SetOutputConfig(m_Real, o); + } + public bool SetTextureDisplay(TextureDisplay o) + { + return ReplayOutput_SetTextureDisplay(m_Real, o); + } + public bool SetMeshDisplay(MeshDisplay o) + { + return ReplayOutput_SetMeshDisplay(m_Real, o); + } + + public bool ClearThumbnails() + { + return ReplayOutput_ClearThumbnails(m_Real); + } + public bool AddThumbnail(IntPtr wnd, ResourceId texID) + { + return ReplayOutput_AddThumbnail(m_Real, wnd, texID); + } + + public bool Display() + { + return ReplayOutput_Display(m_Real); + } + + public bool SetPixelContext(IntPtr wnd) + { + return ReplayOutput_SetPixelContext(m_Real, wnd); + } + public bool SetPixelContextLocation(UInt32 x, UInt32 y) + { + return ReplayOutput_SetPixelContextLocation(m_Real, x, y); + } + public void DisablePixelContext() + { + ReplayOutput_DisablePixelContext(m_Real); + } + + public PixelValue PickPixel(ResourceId texID, bool customShader, UInt32 x, UInt32 y, UInt32 sliceFace, UInt32 mip) + { + IntPtr mem = CustomMarshal.Alloc(typeof(PixelValue)); + + bool success = ReplayOutput_PickPixel(m_Real, texID, customShader, x, y, sliceFace, mip, mem); + + PixelValue ret = null; + + if(success) + ret = (PixelValue)CustomMarshal.PtrToStructure(mem, typeof(PixelValue), false); + + CustomMarshal.Free(mem); + + return ret; + } + + }; + + public class ReplayRenderer + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void ReplayRenderer_Shutdown(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void ReplayRenderer_GetAPIProperties(IntPtr real, IntPtr propsOut); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr ReplayRenderer_CreateOutput(IntPtr real, IntPtr WindowHandle); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void ReplayRenderer_ShutdownOutput(IntPtr real, IntPtr replayOutput); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_HasCallstacks(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_InitResolver(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_SetContextFilter(IntPtr real, ResourceId id, UInt32 firstDefEv, UInt32 lastDefEv); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_SetFrameEvent(IntPtr real, UInt32 frameID, UInt32 eventID); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetD3D11PipelineState(IntPtr real, IntPtr mem); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetGLPipelineState(IntPtr real, IntPtr mem); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_BuildCustomShader(IntPtr real, string entry, string source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_FreeCustomShader(IntPtr real, ResourceId id); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_BuildTargetShader(IntPtr real, string entry, string source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_ReplaceResource(IntPtr real, ResourceId from, ResourceId to); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_RemoveReplacement(IntPtr real, ResourceId id); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_FreeTargetResource(IntPtr real, ResourceId id); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetFrameInfo(IntPtr real, IntPtr outframe); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetDrawcalls(IntPtr real, UInt32 frameID, bool includeTimes, IntPtr outdraws); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetTextures(IntPtr real, IntPtr outtexs); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetBuffers(IntPtr real, IntPtr outbufs); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetResolve(IntPtr real, UInt64[] callstack, UInt32 callstackLen, IntPtr outtrace); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr ReplayRenderer_GetShaderDetails(IntPtr real, ResourceId shader); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_VSGetDebugStates(IntPtr real, UInt32 vertid, UInt32 instid, UInt32 idx, UInt32 instOffset, UInt32 vertOffset, IntPtr outtrace); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_PSGetDebugStates(IntPtr real, UInt32 x, UInt32 y, IntPtr outtrace); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_CSGetDebugStates(IntPtr real, UInt32[] groupid, UInt32[] threadid, IntPtr outtrace); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetUsage(IntPtr real, ResourceId id, IntPtr outusage); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetCBufferVariableContents(IntPtr real, ResourceId shader, UInt32 cbufslot, ResourceId buffer, UInt32 offs, IntPtr outvars); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_SaveTexture(IntPtr real, ResourceId texID, UInt32 mip, string path); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetPostVSData(IntPtr real, MeshDataStage stage, IntPtr outdata); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetMinMax(IntPtr real, ResourceId tex, UInt32 sliceFace, UInt32 mip, IntPtr outminval, IntPtr outmaxval); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetHistogram(IntPtr real, ResourceId tex, UInt32 sliceFace, UInt32 mip, float minval, float maxval, bool[] channels, IntPtr outhistogram); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_GetBufferData(IntPtr real, ResourceId buff, UInt32 offset, UInt32 len, IntPtr outdata); + + private IntPtr m_Real = IntPtr.Zero; + + public ReplayRenderer(IntPtr real) { m_Real = real; } + + public void Shutdown() + { + if (m_Real != IntPtr.Zero) + { + ReplayRenderer_Shutdown(m_Real); + m_Real = IntPtr.Zero; + } + } + + public APIProperties GetAPIProperties() + { + IntPtr mem = CustomMarshal.Alloc(typeof(APIProperties)); + + ReplayRenderer_GetAPIProperties(m_Real, mem); + + APIProperties ret = (APIProperties)CustomMarshal.PtrToStructure(mem, typeof(APIProperties), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ReplayOutput CreateOutput(IntPtr WindowHandle) + { + IntPtr ret = ReplayRenderer_CreateOutput(m_Real, WindowHandle); + + if (ret == IntPtr.Zero) + return null; + + return new ReplayOutput(ret); + } + + public bool HasCallstacks() + { return ReplayRenderer_HasCallstacks(m_Real); } + + public bool InitResolver() + { return ReplayRenderer_InitResolver(m_Real); } + + public bool SetContextFilter(ResourceId id, UInt32 firstDefEv, UInt32 lastDefEv) + { return ReplayRenderer_SetContextFilter(m_Real, id, firstDefEv, lastDefEv); } + public bool SetFrameEvent(UInt32 frameID, UInt32 eventID) + { return ReplayRenderer_SetFrameEvent(m_Real, frameID, eventID); } + + public GLPipelineState GetGLPipelineState() + { + IntPtr mem = CustomMarshal.Alloc(typeof(GLPipelineState)); + + bool success = ReplayRenderer_GetGLPipelineState(m_Real, mem); + + GLPipelineState ret = null; + + if (success) + ret = (GLPipelineState)CustomMarshal.PtrToStructure(mem, typeof(GLPipelineState), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public D3D11PipelineState GetD3D11PipelineState() + { + IntPtr mem = CustomMarshal.Alloc(typeof(D3D11PipelineState)); + + bool success = ReplayRenderer_GetD3D11PipelineState(m_Real, mem); + + D3D11PipelineState ret = null; + + if (success) + ret = (D3D11PipelineState)CustomMarshal.PtrToStructure(mem, typeof(D3D11PipelineState), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ResourceId BuildCustomShader(string entry, string source, UInt32 compileFlags, ShaderStageType type, out string errors) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + ResourceId ret = ResourceId.Null; + + bool success = ReplayRenderer_BuildCustomShader(m_Real, entry, source, compileFlags, type, ref ret, mem); + + if (!success) + ret = ResourceId.Null; + + errors = CustomMarshal.TemplatedArrayToUniString(mem, true); + + CustomMarshal.Free(mem); + + return ret; + } + + public bool FreeCustomShader(ResourceId id) + { return ReplayRenderer_FreeCustomShader(m_Real, id); } + + public ResourceId BuildTargetShader(string entry, string source, UInt32 compileFlags, ShaderStageType type, out string errors) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + ResourceId ret = ResourceId.Null; + + bool success = ReplayRenderer_BuildTargetShader(m_Real, entry, source, compileFlags, type, ref ret, mem); + + if (!success) + ret = ResourceId.Null; + + errors = CustomMarshal.TemplatedArrayToUniString(mem, true); + + CustomMarshal.Free(mem); + + return ret; + } + + public bool ReplaceResource(ResourceId from, ResourceId to) + { return ReplayRenderer_ReplaceResource(m_Real, from, to); } + public bool RemoveReplacement(ResourceId id) + { return ReplayRenderer_RemoveReplacement(m_Real, id); } + public bool FreeTargetResource(ResourceId id) + { return ReplayRenderer_FreeTargetResource(m_Real, id); } + + public FetchFrameInfo[] GetFrameInfo() + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetFrameInfo(m_Real, mem); + + FetchFrameInfo[] ret = null; + + if (success) + ret = (FetchFrameInfo[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchFrameInfo), true); + + CustomMarshal.Free(mem); + + return ret; + } + + private void PopulateDraws(ref Dictionary map, FetchDrawcall[] draws) + { + if (draws.Length == 0) return; + + foreach (var d in draws) + { + map.Add((Int64)d.drawcallID, d); + PopulateDraws(ref map, d.children); + } + } + + private void FixupDraws(Dictionary map, FetchDrawcall[] draws) + { + if (draws.Length == 0) return; + + foreach (var d in draws) + { + if (d.previousDrawcall != 0 && map.ContainsKey(d.previousDrawcall)) d.previous = map[d.previousDrawcall]; + if (d.nextDrawcall != 0 && map.ContainsKey(d.nextDrawcall)) d.next = map[d.nextDrawcall]; + if (d.parentDrawcall != 0 && map.ContainsKey(d.parentDrawcall)) d.parent = map[d.parentDrawcall]; + + FixupDraws(map, d.children); + } + } + + public FetchDrawcall[] GetDrawcalls(UInt32 frameID, bool includeTimes) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetDrawcalls(m_Real, frameID, includeTimes, mem); + + FetchDrawcall[] ret = null; + + if (success) + { + ret = (FetchDrawcall[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchDrawcall), true); + + // fixup previous/next/parent pointers + var map = new Dictionary(); + PopulateDraws(ref map, ret); + FixupDraws(map, ret); + } + + CustomMarshal.Free(mem); + + return ret; + } + + public FetchTexture[] GetTextures() + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetTextures(m_Real, mem); + + FetchTexture[] ret = null; + + if (success) + ret = (FetchTexture[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchTexture), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public FetchBuffer[] GetBuffers() + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetBuffers(m_Real, mem); + + FetchBuffer[] ret = null; + + if (success) + ret = (FetchBuffer[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchBuffer), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public string[] GetResolve(UInt64[] callstack) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + UInt32 len = (UInt32)callstack.Length; + + bool success = ReplayRenderer_GetResolve(m_Real, callstack, len, mem); + + string[] ret = null; + + if (success) + ret = CustomMarshal.TemplatedArrayToUniStringArray(mem, true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ShaderReflection GetShaderDetails(ResourceId shader) + { + IntPtr mem = ReplayRenderer_GetShaderDetails(m_Real, shader); + + ShaderReflection ret = null; + + if (mem != IntPtr.Zero) + ret = (ShaderReflection)CustomMarshal.PtrToStructure(mem, typeof(ShaderReflection), false); + + return ret; + } + + public ShaderDebugTrace VSGetDebugStates(UInt32 vertid, UInt32 instid, UInt32 idx, UInt32 instOffset, UInt32 vertOffset) + { + IntPtr mem = CustomMarshal.Alloc(typeof(ShaderDebugTrace)); + + bool success = ReplayRenderer_VSGetDebugStates(m_Real, vertid, instid, idx, instOffset, vertOffset, mem); + + ShaderDebugTrace ret = null; + + if (success) + ret = (ShaderDebugTrace)CustomMarshal.PtrToStructure(mem, typeof(ShaderDebugTrace), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ShaderDebugTrace PSGetDebugStates(UInt32 x, UInt32 y) + { + IntPtr mem = CustomMarshal.Alloc(typeof(ShaderDebugTrace)); + + bool success = ReplayRenderer_PSGetDebugStates(m_Real, x, y, mem); + + ShaderDebugTrace ret = null; + + if (success) + ret = (ShaderDebugTrace)CustomMarshal.PtrToStructure(mem, typeof(ShaderDebugTrace), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ShaderDebugTrace CSGetDebugStates(UInt32[] groupid, UInt32[] threadid) + { + IntPtr mem = CustomMarshal.Alloc(typeof(ShaderDebugTrace)); + + bool success = ReplayRenderer_CSGetDebugStates(m_Real, groupid, threadid, mem); + + ShaderDebugTrace ret = null; + + if (success) + ret = (ShaderDebugTrace)CustomMarshal.PtrToStructure(mem, typeof(ShaderDebugTrace), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public EventUsage[] GetUsage(ResourceId id) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetUsage(m_Real, id, mem); + + EventUsage[] ret = null; + + if (success) + ret = (EventUsage[])CustomMarshal.GetTemplatedArray(mem, typeof(EventUsage), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ShaderVariable[] GetCBufferVariableContents(ResourceId shader, UInt32 cbufslot, ResourceId buffer, UInt32 offs) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetCBufferVariableContents(m_Real, shader, cbufslot, buffer, offs, mem); + + ShaderVariable[] ret = null; + + if (success) + ret = (ShaderVariable[])CustomMarshal.GetTemplatedArray(mem, typeof(ShaderVariable), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public bool SaveTexture(ResourceId texID, UInt32 mip, string path) + { return ReplayRenderer_SaveTexture(m_Real, texID, mip, path); } + + public PostVSMeshData GetPostVSData(MeshDataStage stage) + { + IntPtr mem = CustomMarshal.Alloc(typeof(PostVSMeshData)); + + PostVSMeshData ret = null; + + bool success = ReplayRenderer_GetPostVSData(m_Real, stage, mem); + + if (success) + ret = (PostVSMeshData)CustomMarshal.PtrToStructure(mem, typeof(PostVSMeshData), true); + + CustomMarshal.Free(mem); + + return ret; + } + + public bool GetMinMax(ResourceId tex, UInt32 sliceFace, UInt32 mip, out PixelValue minval, out PixelValue maxval) + { + IntPtr mem1 = CustomMarshal.Alloc(typeof(PixelValue)); + IntPtr mem2 = CustomMarshal.Alloc(typeof(PixelValue)); + + bool success = ReplayRenderer_GetMinMax(m_Real, tex, sliceFace, mip, mem1, mem2); + + if (success) + { + minval = (PixelValue)CustomMarshal.PtrToStructure(mem1, typeof(PixelValue), true); + maxval = (PixelValue)CustomMarshal.PtrToStructure(mem2, typeof(PixelValue), true); + } + else + { + minval = null; + maxval = null; + } + + CustomMarshal.Free(mem1); + CustomMarshal.Free(mem2); + + return success; + } + + public bool GetHistogram(ResourceId tex, UInt32 sliceFace, UInt32 mip, float minval, float maxval, + bool Red, bool Green, bool Blue, bool Alpha, + out UInt32[] histogram) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool[] channels = new bool[] { Red, Green, Blue, Alpha }; + + bool success = ReplayRenderer_GetHistogram(m_Real, tex, sliceFace, mip, minval, maxval, channels, mem); + + histogram = null; + + if (success) + histogram = (UInt32[])CustomMarshal.GetTemplatedArray(mem, typeof(UInt32), true); + + CustomMarshal.Free(mem); + + return success; + } + + public byte[] GetBufferData(ResourceId buff, UInt32 offset, UInt32 len) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetBufferData(m_Real, buff, offset, len, mem); + + byte[] ret = null; + + if (success) + ret = (byte[])CustomMarshal.GetTemplatedArray(mem, typeof(byte), true); + + CustomMarshal.Free(mem); + + return ret; + } + }; + + public class RemoteRenderer + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RemoteRenderer_Shutdown(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool RemoteRenderer_LocalProxies(IntPtr real, IntPtr outlist); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool RemoteRenderer_RemoteSupportedReplays(IntPtr real, IntPtr outlist); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern ReplayCreateStatus RemoteRenderer_CreateProxyRenderer(IntPtr real, UInt32 proxyid, string logfile, ref float progress, ref IntPtr rendPtr); + + private IntPtr m_Real = IntPtr.Zero; + + public RemoteRenderer(IntPtr real) { m_Real = real; } + + public void Shutdown() + { + if (m_Real != IntPtr.Zero) + { + RemoteRenderer_Shutdown(m_Real); + m_Real = IntPtr.Zero; + } + } + + public string[] LocalProxies() + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + bool success = RemoteRenderer_LocalProxies(m_Real, mem); + + string[] ret = null; + + if (success) + ret = CustomMarshal.TemplatedArrayToUniStringArray(mem, true); + + CustomMarshal.Free(mem); + + return ret; + } + + public string[] RemoteSupportedReplays() + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + bool success = RemoteRenderer_RemoteSupportedReplays(m_Real, mem); + + string[] ret = null; + + if (success) + ret = CustomMarshal.TemplatedArrayToUniStringArray(mem, true); + + CustomMarshal.Free(mem); + + return ret; + } + + public ReplayRenderer CreateProxyRenderer(int proxyid, string logfile, ref float progress) + { + IntPtr rendPtr = IntPtr.Zero; + + ReplayCreateStatus ret = RemoteRenderer_CreateProxyRenderer(m_Real, (UInt32)proxyid, logfile, ref progress, ref rendPtr); + + if (rendPtr == IntPtr.Zero || ret != ReplayCreateStatus.Success) + { + var e = new System.ApplicationException("Failed to set up local proxy replay with remote connection"); + e.Data.Add("status", ret); + throw e; + } + + return new ReplayRenderer(rendPtr); + } + }; + + public class RemoteAccess + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RemoteAccess_Shutdown(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr RemoteAccess_GetTarget(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr RemoteAccess_GetAPI(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr RemoteAccess_GetBusyClient(IntPtr real); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RemoteAccess_TriggerCapture(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RemoteAccess_QueueCapture(IntPtr real, UInt32 frameNumber); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RemoteAccess_CopyCapture(IntPtr real, UInt32 remoteID, string localpath); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RemoteAccess_ReceiveMessage(IntPtr real, IntPtr outmsg); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 RENDERDOC_EnumerateRemoteConnections(string host, UInt32[] idents); + + private IntPtr m_Real = IntPtr.Zero; + private bool m_Connected; + + public RemoteAccess(IntPtr real) + { + m_Real = real; + + if (real == IntPtr.Zero) + { + m_Connected = false; + Target = ""; + API = ""; + BusyClient = ""; + } + else + { + m_Connected = true; + Target = Marshal.PtrToStringUni(RemoteAccess_GetTarget(m_Real)); + API = Marshal.PtrToStringUni(RemoteAccess_GetAPI(m_Real)); + BusyClient = Marshal.PtrToStringUni(RemoteAccess_GetBusyClient(m_Real)); + } + + CaptureExists = false; + CaptureCopied = false; + InfoUpdated = false; + } + + public static UInt32[] GetRemoteIdents(string host) + { + UInt32 numIdents = RENDERDOC_EnumerateRemoteConnections("", null); + + UInt32[] idents = new UInt32[numIdents]; + + RENDERDOC_EnumerateRemoteConnections(host, idents); + + return idents; + } + + public bool Connected { get { return m_Connected; } } + + public void Shutdown() + { + m_Connected = false; + if (m_Real != IntPtr.Zero) RemoteAccess_Shutdown(m_Real); + m_Real = IntPtr.Zero; + } + + public void TriggerCapture() + { + RemoteAccess_TriggerCapture(m_Real); + } + + public void QueueCapture(UInt32 frameNum) + { + RemoteAccess_QueueCapture(m_Real, frameNum); + } + + public void CopyCapture(UInt32 id, string localpath) + { + RemoteAccess_CopyCapture(m_Real, id, localpath); + } + + public void ReceiveMessage() + { + if (m_Real != IntPtr.Zero) + { + RemoteMessage msg = null; + + { + IntPtr mem = CustomMarshal.Alloc(typeof(RemoteMessage)); + + RemoteAccess_ReceiveMessage(m_Real, mem); + + if (mem != IntPtr.Zero) + msg = (RemoteMessage)CustomMarshal.PtrToStructure(mem, typeof(RemoteMessage), true); + + CustomMarshal.Free(mem); + } + + if (msg.Type == RemoteMessageType.Disconnected) + { + m_Connected = false; + RemoteAccess_Shutdown(m_Real); + m_Real = IntPtr.Zero; + } + else if (msg.Type == RemoteMessageType.NewCapture) + { + CaptureFile.ID = msg.NewCapture.ID; + CaptureFile.timestamp = msg.NewCapture.timestamp; + CaptureFile.localpath = msg.NewCapture.localpath; + CaptureFile.thumbnail = msg.NewCapture.thumbnail; + + CaptureExists = true; + } + else if (msg.Type == RemoteMessageType.CaptureCopied) + { + CaptureFile.ID = msg.NewCapture.ID; + CaptureFile.localpath = msg.NewCapture.localpath; + CaptureCopied = true; + } + else if (msg.Type == RemoteMessageType.RegisterAPI) + { + API = msg.RegisterAPI.APIName; + InfoUpdated = true; + } + } + } + + public string BusyClient; + public string Target; + public string API; + + public bool CaptureExists; + public bool CaptureCopied; + public bool InfoUpdated; + + public struct CaptureInfo + { + public UInt32 ID; + public UInt64 timestamp; + public byte[] thumbnail; + public string localpath; + }; + public CaptureInfo CaptureFile = new CaptureInfo(); + }; +}; diff --git a/renderdocui/Interop/Shader.cs b/renderdocui/Interop/Shader.cs new file mode 100644 index 0000000000..63da63c6a5 --- /dev/null +++ b/renderdocui/Interop/Shader.cs @@ -0,0 +1,407 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace renderdoc +{ + [StructLayout(LayoutKind.Sequential)] + public class ShaderVariable + { + public UInt32 rows, columns; + + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string name; + + public VarType type; + + [StructLayout(LayoutKind.Sequential)] + public struct ValueUnion + { + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 16, FixedType = CustomFixedType.UInt32)] + public UInt32[] uv; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 16, FixedType = CustomFixedType.Float)] + public float[] fv; + + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 16, FixedType = CustomFixedType.Int32)] + public Int32[] iv; + + [CustomMarshalAs(CustomUnmanagedType.Skip)] + private double[] dv_arr; + + public double[] dv + { + get + { + if (dv_arr == null) + { + UInt64[] ds = { 0, 0 }; + ds[0] = uv[1]; + ds[1] = uv[3]; + + ds[0] <<= 32; + ds[1] <<= 32; + + ds[0] |= uv[0]; + ds[1] |= uv[2]; + + dv_arr = new double[2]; + dv_arr[0] = BitConverter.Int64BitsToDouble(unchecked((long)ds[0])); + dv_arr[1] = BitConverter.Int64BitsToDouble(unchecked((long)ds[1])); + } + + return dv_arr; + } + } + }; + + [CustomMarshalAs(CustomUnmanagedType.Union)] + public ValueUnion value; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderVariable[] members; + + public override string ToString() + { + if(members.Length > 0) return String.Format("struct[{0}]", members.Length); + if(rows == 1) return Row(0); + + string ret = ""; + for (int i = 0; i < (int)rows; i++) + { + if(i > 0) ret += ", "; + ret += "{" + Row(i) + "}"; + } + + return "{ " + ret + " }"; + } + + public string RowTypeString() + { + if (members.Length > 0) return "struct"; + + if(rows == 0 && columns == 0) + return "-"; + + if(columns == 1) + return type.Str(); + + return String.Format("{0}{1}", type.Str(), columns); + } + + public string TypeString() + { + if (members.Length > 0) return "struct"; + + if (rows == 1 && columns == 1) return type.Str(); + if (rows == 1) return String.Format("{0}{1}", type.Str(), columns); + else return String.Format("{0}{1}x{2}", type.Str(), rows, columns); + } + + public string RowValuesToString(int cols, double x, double y, double z, double w) + { + if (cols == 1) return Formatter.Format(x); + else if (cols == 2) return Formatter.Format(x) + ", " + Formatter.Format(y); + else if (cols == 3) return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z); + else return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z) + ", " + Formatter.Format(w); + } + + public string RowValuesToString(int cols, float x, float y, float z, float w) + { + if (cols == 1) return Formatter.Format(x); + else if (cols == 2) return Formatter.Format(x) + ", " + Formatter.Format(y); + else if (cols == 3) return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z); + else return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z) + ", " + Formatter.Format(w); + } + + public string RowValuesToString(int cols, UInt32 x, UInt32 y, UInt32 z, UInt32 w) + { + if (cols == 1) return Formatter.Format(x); + else if (cols == 2) return Formatter.Format(x) + ", " + Formatter.Format(y); + else if (cols == 3) return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z); + else return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z) + ", " + Formatter.Format(w); + } + + public string RowValuesToString(int cols, Int32 x, Int32 y, Int32 z, Int32 w) + { + if (cols == 1) return Formatter.Format(x); + else if (cols == 2) return Formatter.Format(x) + ", " + Formatter.Format(y); + else if (cols == 3) return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z); + else return Formatter.Format(x) + ", " + Formatter.Format(y) + ", " + Formatter.Format(z) + ", " + Formatter.Format(w); + } + + public string Row(int row, VarType t) + { + if(t == VarType.Double) + return RowValuesToString((int)columns, value.dv[row*columns+0], value.dv[row*columns+1], value.dv[row*columns+2], value.dv[row*columns+3]); + else if(t == VarType.Int) + return RowValuesToString((int)columns, value.iv[row * columns + 0], value.iv[row * columns + 1], value.iv[row * columns + 2], value.iv[row * columns + 3]); + else if(t == VarType.UInt) + return RowValuesToString((int)columns, value.uv[row * columns + 0], value.uv[row * columns + 1], value.uv[row * columns + 2], value.uv[row * columns + 3]); + else + return RowValuesToString((int)columns, value.fv[row * columns + 0], value.fv[row * columns + 1], value.fv[row * columns + 2], value.fv[row * columns + 3]); + } + + public string Row(int row) + { + return Row(row, type); + } + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderDebugState + { + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderVariable[] registers; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderVariable[] outputs; + + public UInt32 nextInstruction; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderDebugTrace + { + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderVariable[] inputs; + + [StructLayout(LayoutKind.Sequential)] + public struct CBuffer + { + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderVariable[] variables; + }; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public CBuffer[] cbuffers; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderDebugState[] states; + }; + + [StructLayout(LayoutKind.Sequential)] + public class SigParameter + { + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string varName; + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string semanticName; + + public UInt32 semanticIndex; + + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string semanticIdxName; + + public bool needSemanticIndex; + + public UInt32 regIndex; + public SystemAttribute systemValue; + + public FormatComponentType compType; + + public byte regChannelMask; + public byte channelUsedMask; + public UInt32 compCount; + public UInt32 stream; + + public string TypeString + { + get + { + string ret = ""; + + if (compType == FormatComponentType.Float) + ret += "float"; + else if (compType == FormatComponentType.UInt) + ret += "uint"; + else if (compType == FormatComponentType.SInt) + ret += "int"; + else if (compType == FormatComponentType.UNorm) + ret += "unorm float"; + else if (compType == FormatComponentType.SNorm) + ret += "snorm float"; + else if (compType == FormatComponentType.Depth) + ret += "float"; + + if (compCount > 1) + ret += compCount; + + return ret; + } + } + + public string D3D11SemanticString + { + get + { + if (systemValue == SystemAttribute.None) + return semanticIdxName; + + string ret = systemValue.Str(); + + // need to include the index if it's a system value semantic that's numbered + if (systemValue == SystemAttribute.ColourOutput || + systemValue == SystemAttribute.CullDistance || + systemValue == SystemAttribute.ClipDistance) + ret += semanticIndex; + + return ret; + } + } + + public static string GetComponentString(byte mask) + { + string ret = ""; + + if ((mask & 0x1) > 0) ret += "R"; + if ((mask & 0x2) > 0) ret += "G"; + if ((mask & 0x4) > 0) ret += "B"; + if ((mask & 0x8) > 0) ret += "A"; + + return ret; + } + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderVariableType + { + [StructLayout(LayoutKind.Sequential)] + public struct ShaderVarDescriptor + { + public UInt32 rows; + public UInt32 cols; + public UInt32 elements; + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string name; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderVarDescriptor descriptor; + + public string Name { get { return descriptor.name; } } + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderConstant[] members; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderConstant + { + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string name; + + [StructLayout(LayoutKind.Sequential)] + public struct RegSpan + { + public UInt32 vec; + public UInt32 comp; + }; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public RegSpan reg; + + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderVariableType type; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ConstantBlock + { + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string name; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderConstant[] variables; + + public UInt32 bufferAddress; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderResource + { + public bool IsSampler; + public bool IsTexture; + public bool IsSRV; + public bool IsUAV; + + public ShaderResourceType resType; + + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string name; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderVariableType variableType; + public UInt32 variableAddress; + public UInt32 bindPoint; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderDebugChunk + { + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string entryFunc; + + public UInt32 compileFlags; + + public struct DebugFile + { + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string filename; + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string filetext; + }; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public DebugFile[] files; + }; + + [StructLayout(LayoutKind.Sequential)] + public class ShaderReflection + { + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public ShaderDebugChunk DebugInfo; + + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string Disassembly; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public SigParameter[] InputSig; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public SigParameter[] OutputSig; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ConstantBlock[] ConstantBlocks; // sparse - index indicates bind point + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public ShaderResource[] Resources; // non-sparse, since bind points can overlap. + + [StructLayout(LayoutKind.Sequential)] + public struct Interface + { + [CustomMarshalAs(CustomUnmanagedType.AsciiTemplatedString)] + public string Name; + }; + + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public Interface[] Interfaces; + }; +}; \ No newline at end of file diff --git a/renderdocui/Interop/StaticExports.cs b/renderdocui/Interop/StaticExports.cs new file mode 100644 index 0000000000..af5a7acf67 --- /dev/null +++ b/renderdocui/Interop/StaticExports.cs @@ -0,0 +1,190 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace renderdoc +{ + class StaticExports + { + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool RENDERDOC_SupportLocalReplay(string logfile, IntPtr outdriver); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern ReplayCreateStatus RENDERDOC_CreateReplayRenderer(string logfile, ref float progress, ref IntPtr rendPtr); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 RENDERDOC_ExecuteAndInject(string app, string workingDir, string cmdLine, + string logfile, CaptureOptions opts, bool waitForExit); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 RENDERDOC_InjectIntoProcess(UInt32 pid, string logfile, CaptureOptions opts, bool waitForExit); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr RENDERDOC_CreateRemoteAccessConnection(string host, UInt32 ident, string clientName, bool forceConnection); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 RENDERDOC_EnumerateRemoteConnections(string host, UInt32[] idents); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern ReplayCreateStatus RENDERDOC_CreateRemoteReplayConnection(string host, ref IntPtr outrend); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RENDERDOC_SpawnReplayHost(ref bool killReplay); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RENDERDOC_TriggerExceptionHandler(IntPtr exceptionPtrs, bool crashed); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RENDERDOC_LogText(string text); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr RENDERDOC_GetLogFilename(); + + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool RENDERDOC_GetThumbnail(string filename, byte[] outmem, ref UInt32 len); + + public static bool SupportLocalReplay(string logfile, out string driverName) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + bool ret = RENDERDOC_SupportLocalReplay(logfile, mem); + + driverName = CustomMarshal.TemplatedArrayToUniString(mem, true); + + CustomMarshal.Free(mem); + return ret; + } + + public static ReplayRenderer CreateReplayRenderer(string logfile, ref float progress) + { + IntPtr rendPtr = IntPtr.Zero; + + ReplayCreateStatus ret = RENDERDOC_CreateReplayRenderer(logfile, ref progress, ref rendPtr); + + if (rendPtr == IntPtr.Zero || ret != ReplayCreateStatus.Success) + { + var e = new System.ApplicationException("Failed to load log for local replay"); + e.Data.Add("status", ret); + throw e; + } + + return new ReplayRenderer(rendPtr); + } + + public static UInt32 ExecuteAndInject(string app, string workingDir, string cmdLine, string logfile, CaptureOptions opts) + { + return RENDERDOC_ExecuteAndInject(app, workingDir, cmdLine, logfile, opts, false); + } + + public static UInt32 InjectIntoProcess(UInt32 pid, string logfile, CaptureOptions opts) + { + return RENDERDOC_InjectIntoProcess(pid, logfile, opts, false); + } + + public static RemoteAccess CreateRemoteAccessConnection(string host, UInt32 ident, string clientName, bool forceConnection) + { + IntPtr rendPtr = RENDERDOC_CreateRemoteAccessConnection(host, ident, clientName, forceConnection); + + if (rendPtr == IntPtr.Zero) + { + var e = new System.ApplicationException("Failed to load log for local replay"); + e.Data.Add("status", ReplayCreateStatus.UnknownError); + throw e; + } + + return new RemoteAccess(rendPtr); + } + + public static UInt32[] EnumerateRemoteConnections(string host) + { + UInt32 numIdents = RENDERDOC_EnumerateRemoteConnections(host, null); + + if (numIdents == 0) + return null; + + UInt32[] ret = new UInt32[numIdents]; + + RENDERDOC_EnumerateRemoteConnections(host, ret); + + return ret; + } + + public static RemoteRenderer CreateRemoteReplayConnection(string host) + { + IntPtr rendPtr = IntPtr.Zero; + + ReplayCreateStatus ret = RENDERDOC_CreateRemoteReplayConnection(host, ref rendPtr); + + if (rendPtr == IntPtr.Zero || ret != ReplayCreateStatus.Success) + { + var e = new System.ApplicationException("Failed to connect to remote replay host"); + e.Data.Add("status", ret); + throw e; + } + + return new RemoteRenderer(rendPtr); + } + + public static void SpawnReplayHost(ref bool killReplay) + { + RENDERDOC_SpawnReplayHost(ref killReplay); + } + + public static void TriggerExceptionHandler(IntPtr exceptionPtrs, bool crashed) + { + RENDERDOC_TriggerExceptionHandler(exceptionPtrs, crashed); + } + + public static void LogText(string text) + { + RENDERDOC_LogText(text); + } + + public static string GetLogFilename() + { + return Marshal.PtrToStringUni(RENDERDOC_GetLogFilename()); + } + + public static byte[] GetThumbnail(string filename) + { + UInt32 len = 0; + + bool success = RENDERDOC_GetThumbnail(filename, null, ref len); + + if (!success || len == 0) + return null; + + byte[] ret = new byte[len]; + + success = RENDERDOC_GetThumbnail(filename, ret, ref len); + + if (!success || len == 0) + return null; + + return ret; + } + } +} diff --git a/renderdocui/Plugins/PluginHelpers.cs b/renderdocui/Plugins/PluginHelpers.cs new file mode 100644 index 0000000000..cafe13a76f --- /dev/null +++ b/renderdocui/Plugins/PluginHelpers.cs @@ -0,0 +1,93 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; + +namespace renderdocplugin +{ + class PluginHelpers + { + private static Dictionary m_LoadedPlugins = null; + + public static String PluginDirectory + { + get + { + var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + dir = Path.Combine(dir, "plugins"); + + return dir; + } + } + + public static List GetPlugins() + { + if (m_LoadedPlugins != null) + return new List(m_LoadedPlugins.Keys); + + m_LoadedPlugins = new Dictionary(); + + if(!Directory.Exists(PluginDirectory)) + return new List(); + + foreach (string pluginFile in Directory.EnumerateFiles(PluginDirectory, "*.dll")) + { + try + { + Assembly myDllAssembly = Assembly.LoadFile(pluginFile); + + var basename = Path.GetFileNameWithoutExtension(pluginFile); + + m_LoadedPlugins.Add(basename, myDllAssembly); + } + catch (Exception) + { + // silently ignore invalid/bad assemblies. + } + } + + return new List(m_LoadedPlugins.Keys); + } + + public static T GetPluginInterface(string assemblyName) + { + if (!m_LoadedPlugins.ContainsKey(assemblyName)) + return default(T); + + var type = typeof(T); + + var ass = m_LoadedPlugins[assemblyName]; + + Type pluginType = ass.GetType(assemblyName + "." + type.Name); + + return (T)ass.CreateInstance(assemblyName + "." + type.Name); + } + } +} diff --git a/renderdocui/Plugins/ReplayManagerPlugin.cs b/renderdocui/Plugins/ReplayManagerPlugin.cs new file mode 100644 index 0000000000..8abdecb40c --- /dev/null +++ b/renderdocui/Plugins/ReplayManagerPlugin.cs @@ -0,0 +1,38 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System.Collections.Generic; + +namespace renderdocplugin +{ + public interface ReplayManagerPlugin + { + string GetTargetType(); + List GetOnlineTargets(); + bool IsReplayRunning(string target); + void RunReplay(string target); + void CloseReplay(); + } +} diff --git a/renderdocui/Properties/AssemblyInfo.cs b/renderdocui/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..bea394d4b7 --- /dev/null +++ b/renderdocui/Properties/AssemblyInfo.cs @@ -0,0 +1,64 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Crytek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RenderDoc")] +[assembly: AssemblyDescription("RenderDoc UI replay app + launcher - http://renderdoc.org/")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Crytek")] +[assembly: AssemblyProduct("RenderDoc UI")] +[assembly: AssemblyCopyright("Copyright © 2014 Crytek")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c3444b4d-32e9-4a50-845f-c59e25d5524b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.20.0.0")] +[assembly: AssemblyFileVersion("0.20.0.0")] + +// this can be replaced with the git hash of the commit being built from e.g. in a script +[assembly: AssemblyInformationalVersion("NO_GIT_COMMIT_HASH_DEFINED")] \ No newline at end of file diff --git a/renderdocui/Properties/Resources.Designer.cs b/renderdocui/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..59a16dc500 --- /dev/null +++ b/renderdocui/Properties/Resources.Designer.cs @@ -0,0 +1,583 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18408 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace renderdocui.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("renderdocui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap accept { + get { + object obj = ResourceManager.GetObject("accept", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap action { + get { + object obj = ResourceManager.GetObject("action", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap action_hover { + get { + object obj = ResourceManager.GetObject("action_hover", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap add { + get { + object obj = ResourceManager.GetObject("add", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_in { + get { + object obj = ResourceManager.GetObject("arrow_in", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_join { + get { + object obj = ResourceManager.GetObject("arrow_join", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_undo { + get { + object obj = ResourceManager.GetObject("arrow_undo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap chart_curve { + get { + object obj = ResourceManager.GetObject("chart_curve", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap cog { + get { + object obj = ResourceManager.GetObject("cog", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap color_wheel { + get { + object obj = ResourceManager.GetObject("color_wheel", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap connect { + get { + object obj = ResourceManager.GetObject("connect", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap cross { + get { + object obj = ResourceManager.GetObject("cross", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap crosshatch { + get { + object obj = ResourceManager.GetObject("crosshatch", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap delete { + get { + object obj = ResourceManager.GetObject("delete", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap disconnect { + get { + object obj = ResourceManager.GetObject("disconnect", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap find { + get { + object obj = ResourceManager.GetObject("find", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap fit_window { + get { + object obj = ResourceManager.GetObject("fit_window", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap flag_green { + get { + object obj = ResourceManager.GetObject("flag_green", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap hourglass { + get { + object obj = ResourceManager.GetObject("hourglass", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon icon { + get { + object obj = ResourceManager.GetObject("icon", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap information { + get { + object obj = ResourceManager.GetObject("information", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap logo { + get { + object obj = ResourceManager.GetObject("logo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap new_window { + get { + object obj = ResourceManager.GetObject("new_window", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap page_white_database { + get { + object obj = ResourceManager.GetObject("page_white_database", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap page_white_delete { + get { + object obj = ResourceManager.GetObject("page_white_delete", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap page_white_edit { + get { + object obj = ResourceManager.GetObject("page_white_edit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap page_white_link { + get { + object obj = ResourceManager.GetObject("page_white_link", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap plugin_add { + get { + object obj = ResourceManager.GetObject("plugin_add", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap red_x_16 { + get { + object obj = ResourceManager.GetObject("red_x_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap runback { + get { + object obj = ResourceManager.GetObject("runback", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap runcursor { + get { + object obj = ResourceManager.GetObject("runcursor", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap runfwd { + get { + object obj = ResourceManager.GetObject("runfwd", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap save { + get { + object obj = ResourceManager.GetObject("save", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap stepnext { + get { + object obj = ResourceManager.GetObject("stepnext", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap stepprev { + get { + object obj = ResourceManager.GetObject("stepprev", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tick { + get { + object obj = ResourceManager.GetObject("tick", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap time { + get { + object obj = ResourceManager.GetObject("time", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap timeline_marker { + get { + object obj = ResourceManager.GetObject("timeline_marker", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_linelist { + get { + object obj = ResourceManager.GetObject("topo_linelist", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_linelist_adj { + get { + object obj = ResourceManager.GetObject("topo_linelist_adj", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_linestrip { + get { + object obj = ResourceManager.GetObject("topo_linestrip", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_linestrip_adj { + get { + object obj = ResourceManager.GetObject("topo_linestrip_adj", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_patch { + get { + object obj = ResourceManager.GetObject("topo_patch", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_pointlist { + get { + object obj = ResourceManager.GetObject("topo_pointlist", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_trilist { + get { + object obj = ResourceManager.GetObject("topo_trilist", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_trilist_adj { + get { + object obj = ResourceManager.GetObject("topo_trilist_adj", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_tristrip { + get { + object obj = ResourceManager.GetObject("topo_tristrip", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap topo_tristrip_adj { + get { + object obj = ResourceManager.GetObject("topo_tristrip_adj", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap wand { + get { + object obj = ResourceManager.GetObject("wand", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap wireframe_mesh { + get { + object obj = ResourceManager.GetObject("wireframe_mesh", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap wrench { + get { + object obj = ResourceManager.GetObject("wrench", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap zoom { + get { + object obj = ResourceManager.GetObject("zoom", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/renderdocui/Properties/Resources.resx b/renderdocui/Properties/Resources.resx new file mode 100644 index 0000000000..4995398766 --- /dev/null +++ b/renderdocui/Properties/Resources.resx @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\topologies\topo_linestrip.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\new_window.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\flag_green.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\stepnext.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\information.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\accept.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\runback.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_white_database.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_linelist.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\find.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\rightarrow_gray_16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\zoom.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_trilist_adj.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\cross.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\red_x_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\wand.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_trilist.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\stepprev.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_linestrip_adj.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\tick.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\color_wheel.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\fit_window.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_tristrip_adj.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\time.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_white_delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\hourglass.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_pointlist.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\save.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\runfwd.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_tristrip.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_linelist_adj.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\runcursor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_white_edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\topologies\topo_patch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\plugin_add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_join.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\crosshatch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\cog.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_white_link.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_undo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\rightarrow_green_16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\wrench.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\chart_curve.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\timeline_marker.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\connect.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\disconnect.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\wireframe_mesh.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/renderdocui/Properties/Settings.Designer.cs b/renderdocui/Properties/Settings.Designer.cs new file mode 100644 index 0000000000..474ffb43a2 --- /dev/null +++ b/renderdocui/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18408 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace renderdocui.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/renderdocui/Properties/Settings.settings b/renderdocui/Properties/Settings.settings new file mode 100644 index 0000000000..8e615f25fd --- /dev/null +++ b/renderdocui/Properties/Settings.settings @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/renderdocui/Resources/128.png b/renderdocui/Resources/128.png new file mode 100644 index 0000000000..bd3f5cbb56 Binary files /dev/null and b/renderdocui/Resources/128.png differ diff --git a/renderdocui/Resources/RightArrow_Gray_16x16.png b/renderdocui/Resources/RightArrow_Gray_16x16.png new file mode 100644 index 0000000000..566ff84160 Binary files /dev/null and b/renderdocui/Resources/RightArrow_Gray_16x16.png differ diff --git a/renderdocui/Resources/RightArrow_Green_16x16.png b/renderdocui/Resources/RightArrow_Green_16x16.png new file mode 100644 index 0000000000..b244731cbe Binary files /dev/null and b/renderdocui/Resources/RightArrow_Green_16x16.png differ diff --git a/renderdocui/Resources/accept.png b/renderdocui/Resources/accept.png new file mode 100644 index 0000000000..89c8129a49 Binary files /dev/null and b/renderdocui/Resources/accept.png differ diff --git a/renderdocui/Resources/add.png b/renderdocui/Resources/add.png new file mode 100644 index 0000000000..6332fefea4 Binary files /dev/null and b/renderdocui/Resources/add.png differ diff --git a/renderdocui/Resources/arrow_in.png b/renderdocui/Resources/arrow_in.png new file mode 100644 index 0000000000..745c65134d Binary files /dev/null and b/renderdocui/Resources/arrow_in.png differ diff --git a/renderdocui/Resources/arrow_join.png b/renderdocui/Resources/arrow_join.png new file mode 100644 index 0000000000..a128413d88 Binary files /dev/null and b/renderdocui/Resources/arrow_join.png differ diff --git a/renderdocui/Resources/arrow_undo.png b/renderdocui/Resources/arrow_undo.png new file mode 100644 index 0000000000..6972c5e594 Binary files /dev/null and b/renderdocui/Resources/arrow_undo.png differ diff --git a/renderdocui/Resources/chart_curve.png b/renderdocui/Resources/chart_curve.png new file mode 100644 index 0000000000..01e933a619 Binary files /dev/null and b/renderdocui/Resources/chart_curve.png differ diff --git a/renderdocui/Resources/cog.png b/renderdocui/Resources/cog.png new file mode 100644 index 0000000000..67de2c6ccb Binary files /dev/null and b/renderdocui/Resources/cog.png differ diff --git a/renderdocui/Resources/cog_go.png b/renderdocui/Resources/cog_go.png new file mode 100644 index 0000000000..3262767cda Binary files /dev/null and b/renderdocui/Resources/cog_go.png differ diff --git a/renderdocui/Resources/color_wheel.png b/renderdocui/Resources/color_wheel.png new file mode 100644 index 0000000000..809fb00e5a Binary files /dev/null and b/renderdocui/Resources/color_wheel.png differ diff --git a/renderdocui/Resources/connect.png b/renderdocui/Resources/connect.png new file mode 100644 index 0000000000..024138eb33 Binary files /dev/null and b/renderdocui/Resources/connect.png differ diff --git a/renderdocui/Resources/cross.png b/renderdocui/Resources/cross.png new file mode 100644 index 0000000000..1514d51a3c Binary files /dev/null and b/renderdocui/Resources/cross.png differ diff --git a/renderdocui/Resources/crosshatch.png b/renderdocui/Resources/crosshatch.png new file mode 100644 index 0000000000..09275f9c09 Binary files /dev/null and b/renderdocui/Resources/crosshatch.png differ diff --git a/renderdocui/Resources/delete.png b/renderdocui/Resources/delete.png new file mode 100644 index 0000000000..08f249365a Binary files /dev/null and b/renderdocui/Resources/delete.png differ diff --git a/renderdocui/Resources/disconnect.png b/renderdocui/Resources/disconnect.png new file mode 100644 index 0000000000..b335cb11c4 Binary files /dev/null and b/renderdocui/Resources/disconnect.png differ diff --git a/renderdocui/Resources/find.png b/renderdocui/Resources/find.png new file mode 100644 index 0000000000..1547479646 Binary files /dev/null and b/renderdocui/Resources/find.png differ diff --git a/renderdocui/Resources/fit_window.png b/renderdocui/Resources/fit_window.png new file mode 100644 index 0000000000..2e9bc42bec Binary files /dev/null and b/renderdocui/Resources/fit_window.png differ diff --git a/renderdocui/Resources/flag_green.png b/renderdocui/Resources/flag_green.png new file mode 100644 index 0000000000..e4bc611f87 Binary files /dev/null and b/renderdocui/Resources/flag_green.png differ diff --git a/renderdocui/Resources/hlsl.xml b/renderdocui/Resources/hlsl.xml new file mode 100644 index 0000000000..ffc82c6cd2 --- /dev/null +++ b/renderdocui/Resources/hlsl.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + register packoffset static const + + break continue discard do for if else switch while case default return + + abort abs acos all AllMemoryBarrier AllMemoryBarrierWithGroupSync any asdouble asfloat asin asint asuint atan + atan2 ceil clamp clip cos cosh countbits cross D3DCOLORtoUBYTE4 ddx ddx_coarse ddx_fine ddy ddy_coarse ddy_fine + degrees determinant DeviceMemoryBarrier DeviceMemoryBarrierWithGroupSync distance dot dst errorf + EvaluateAttributeAtCentroid EvaluateAttributeAtSample EvaluateAttributeSnapped exp exp2 f16tof32 f32tof16 + faceforward firstbithigh firstbitlow floor fma fmod frac frexp fwidth GetRenderTargetSampleCount GetRenderTargetSamplePosition + GroupMemoryBarrier GroupMemoryBarrierWithGroupSync InterlockedAdd InterlockedAnd InterlockedCompareExchange + InterlockedCompareStore InterlockedExchange InterlockedMax InterlockedMin InterlockedOr InterlockedXor isfinite + isinf isnan ldexp length lerp lit log log10 log2 mad max min modf msad4 mul noise normalize pow printf + Process2DQuadTessFactorsAvg Process2DQuadTessFactorsMax Process2DQuadTessFactorsMin ProcessIsolineTessFactors + ProcessQuadTessFactorsAvg ProcessQuadTessFactorsMax ProcessQuadTessFactorsMin ProcessTriTessFactorsAvg + ProcessTriTessFactorsMax ProcessTriTessFactorsMin radians rcp reflect refract reversebits round rsqrt saturate + sign sin sincos sinh smoothstep sqrt step tan tanh tex1D tex1Dbias tex1Dgrad tex1Dlod tex1Dproj + tex2D tex2Dbias tex2Dgrad tex2Dlod tex2Dproj tex3D tex3Dbias tex3Dgrad tex3Dlod tex3Dproj texCUBE texCUBEbias + texCUBEgrad texCUBElod texCUBEproj transpose trunc + + BINORMAL BINORMAL0 BINORMAL1 BINORMAL2 BINORMAL3 BINORMAL4 BINORMAL5 BINORMAL6 BINORMAL7 + BLENDINDICES BLENDINDICES0 BLENDINDICES1 BLENDINDICES2 BLENDINDICES3 BLENDINDICES4 BLENDINDICES5 BLENDINDICES6 BLENDINDICES7 + BLENDWEIGHT BLENDWEIGHT0 BLENDWEIGHT1 BLENDWEIGHT2 BLENDWEIGHT3 BLENDWEIGHT4 BLENDWEIGHT5 BLENDWEIGHT6 BLENDWEIGHT7 + COLOR COLOR0 COLOR1 COLOR2 COLOR3 COLOR4 COLOR5 COLOR6 COLOR7 + NORMAL NORMAL0 NORMAL1 NORMAL2 NORMAL3 NORMAL4 NORMAL5 NORMAL6 NORMAL7 + POSITION POSITION0 POSITION1 POSITION2 POSITION3 POSITION4 POSITION5 POSITION6 POSITION7 + POSITIONT + PSIZE PSIZE0 PSIZE1 PSIZE2 PSIZE3 PSIZE4 PSIZE5 PSIZE6 PSIZE7 + TANGENT TANGENT0 TANGENT1 TANGENT2 TANGENT3 TANGENT4 TANGENT5 TANGENT6 TANGENT7 + TEXCOORD TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 + TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 + + SV_Coverage SV_Depth SV_DispatchThreadID SV_DomainLocation SV_GroupID SV_GroupIndex SV_GroupThreadID SV_GSInstanceID SV_InsideTessFactor SV_IsFrontFace SV_OutputControlPointID SV_POSITION SV_Position SV_RenderTargetArrayIndex SV_SampleIndex SV_TessFactor SV_ViewportArrayIndex SV_InstanceID SV_PrimitiveID SV_VertexID SV_TargetID + SV_TARGET SV_Target SV_Target0 SV_Target1 SV_Target2 SV_Target3 SV_Target4 SV_Target5 SV_Target6 SV_Target7 + SV_ClipDistance0 SV_ClipDistance1 SV_ClipDistance2 SV_ClipDistance3 SV_ClipDistance4 SV_ClipDistance5 SV_ClipDistance6 SV_ClipDistance7 + SV_CullDistance0 SV_CullDistance1 SV_CullDistance2 SV_CullDistance3 SV_CullDistance4 SV_CullDistance5 SV_CullDistance6 SV_CullDistance7 + + + bool bool1 bool2 bool3 bool4 + bool1x1 bool1x2 bool1x3 bool1x4 + bool2x1 bool2x2 bool2x3 bool2x4 + bool3x1 bool3x2 bool3x3 bool3x4 + bool4x1 bool4x2 bool4x3 bool4x4 + + int int1 int2 int3 int4 + int1x1 int1x2 int1x3 int1x4 + int2x1 int2x2 int2x3 int2x4 + int3x1 int3x2 int3x3 int3x4 + int4x1 int4x2 int4x3 int4x4 + + uint uint1 uint2 uint3 uint4 + uint1x1 uint1x2 uint1x3 uint1x4 + uint2x1 uint2x2 uint2x3 uint2x4 + uint3x1 uint3x2 uint3x3 uint3x4 + uint4x1 uint4x2 uint4x3 uint4x4 + + UINT UINT2 UINT3 UINT4 + + dword dword1 dword2 dword3 dword4 + dword1x1 dword1x2 dword1x3 dword1x4 + dword2x1 dword2x2 dword2x3 dword2x4 + dword3x1 dword3x2 dword3x3 dword3x4 + dword4x1 dword4x2 dword4x3 dword4x4 + + half half1 half2 half3 half4 + half1x1 half1x2 half1x3 half1x4 + half2x1 half2x2 half2x3 half2x4 + half3x1 half3x2 half3x3 half3x4 + half4x1 half4x2 half4x3 half4x4 + + float float1 float2 float3 float4 + float1x1 float1x2 float1x3 float1x4 + float2x1 float2x2 float2x3 float2x4 + float3x1 float3x2 float3x3 float3x4 + float4x1 float4x2 float4x3 float4x4 + + double double1 double2 double3 double4 + double1x1 double1x2 double1x3 double1x4 + double2x1 double2x2 double2x3 double2x4 + double3x1 double3x2 double3x3 double3x4 + double4x1 double4x2 double4x3 double4x4 + + snorm unorm string void cbuffer struct + + Buffer AppendStructuredBfufer ByteAddressBuffer ConsumeStructuredBuffer StructuredBuffer + RWBuffer RWByteAddressBuffer RWStructuredBuffer RWTexture1D RWTexture1DArray RWTexture2D RWTexture2DArray RWTexture3D + + InputPatch OutputPatch + + linear centroid nointerpolation noperspective sample + + sampler sampler1D sampler2D sampler3D samplerCUBE SamplerComparisonState SamplerState sampler_state + AddressU AddressV AddressW BorderColor Filter MaxAnisotropy MaxLOD MinLOD MipLODBias ComparisonFunc ComparisonFilter + + texture Texture1D Texture1DArray Texture2D Texture2DArray Texture2DMS Texture2DMSArray Texture3D TextureCube + + + + +