Merge and fix the bug!!!

This commit is contained in:
samcake 2016-11-16 19:12:56 -08:00
commit 9031e65aa5
34 changed files with 852 additions and 310 deletions

View file

@ -17,6 +17,30 @@
class MenuItemProperties;
/**jsdoc
* The `Menu` provides access to the menu that is shown at the top of the window
* shown on a user's desktop and the right click menu that is accessible
* in both Desktop and HMD mode.
*
* <h3>Groupings</h3>
* A `grouping` is a way to group a set of menus and/or menu items together
* so that they can all be set visible or invisible as a group. There are
* 2 available groups: "Advanced" and "Developer"
* These groupings can be toggled in the "Settings" menu.
*
* @namespace Menu
*/
/**
* CURRENTLY NOT WORKING:
*
* <h3>Action groups</h3>
* When 1+ menu items are checkable and in the same action group, only 1 can be
* selected at any one time. If another item in the action group is selected, the
* previous will be deselected. This feature provides the ability to create
* "radio-button"-like menus.
*/
class MenuScriptingInterface : public QObject {
Q_OBJECT
MenuScriptingInterface() { };
@ -28,33 +52,142 @@ private slots:
void menuItemTriggered();
public slots:
/**jsdoc
* Add a new top-level menu.
* @function Menu.addMenu
* @param {string} menuName Name that will be shown in the menu.
* @param {string} grouping Name of the grouping to add this menu to.
*/
void addMenu(const QString& menuName, const QString& grouping = QString());
/**jsdoc
* Remove a top-level menu.
* @function Menu.removeMenu
* @param {string} menuName Name of the menu to remove.
*/
void removeMenu(const QString& menuName);
/**jsdoc
* Check whether a top-level menu exists.
* @function Menu.menuExists
* @param {string} menuName Name of the menu to check for existence.
* @return {bool} `true` if the menu exists, otherwise `false`.
*/
bool menuExists(const QString& menuName);
/**jsdoc
* Add a separator with an unclickable label below it.
* The line will be placed at the bottom of the menu.
* @function Menu.addSeparator
* @param {string} menuName Name of the menu to add a separator to.
* @param {string} separatorName Name of the separator that will be shown (but unclickable) below the separator line.
*/
void addSeparator(const QString& menuName, const QString& separatorName);
/**jsdoc
* Remove a separator and its label from a menu.
* @function Menu.removeSeparator
* @param {string} menuName Name of the menu to remove a separator from.
* @param {string} separatorName Name of the separator to remove.
*/
void removeSeparator(const QString& menuName, const QString& separatorName);
/**jsdoc
* Add a new menu item to a menu.
* @function Menu.addMenuItem
* @param {Menu.MenuItemProperties} properties
*/
void addMenuItem(const MenuItemProperties& properties);
/**jsdoc
* Add a new menu item to a menu.
* @function Menu.addMenuItem
* @param {string} menuName Name of the menu to add a menu item to.
* @param {string} menuItem Name of the menu item. This is what will be displayed in the menu.
* @param {string} shortcutKey A shortcut key that can be used to trigger the menu item.
*/
void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey);
/**jsdoc
* Add a new menu item to a menu.
* @function Menu.addMenuItem
* @param {string} menuName Name of the menu to add a menu item to.
* @param {string} menuItem Name of the menu item. This is what will be displayed in the menu.
*/
void addMenuItem(const QString& menuName, const QString& menuitem);
/**jsdoc
* Remove a menu item from a menu.
* @function Menu.removeMenuItem
* @param {string} menuName Name of the menu to remove a menu item from.
* @param {string} menuItem Name of the menu item to remove.
*/
void removeMenuItem(const QString& menuName, const QString& menuitem);
/**jsdoc
* Check if a menu item exists.
* @function Menu.menuItemExists
* @param {string} menuName Name of the menu that the menu item is in.
* @param {string} menuItem Name of the menu item to check for existence of.
* @return {bool} `true` if the menu item exists, otherwise `false`.
*/
bool menuItemExists(const QString& menuName, const QString& menuitem);
/**
* Not working, will not document until fixed
*/
void addActionGroup(const QString& groupName, const QStringList& actionList,
const QString& selected = QString());
void removeActionGroup(const QString& groupName);
/**jsdoc
* Check whether a checkable menu item is checked.
* @function Menu.isOptionChecked
* @param {string} menuOption The name of the menu item.
* @return `true` if the option is checked, otherwise false.
*/
bool isOptionChecked(const QString& menuOption);
/**jsdoc
* Set a checkable menu item as checked or unchecked.
* @function Menu.setIsOptionChecked
* @param {string} menuOption The name of the menu item to modify.
* @param {bool} isChecked If `true`, the menu item will be checked, otherwise it will not be checked.
*/
void setIsOptionChecked(const QString& menuOption, bool isChecked);
/**jsdoc
* Toggle the status of a checkable menu item. If it is checked, it will be unchecked.
* If it is unchecked, it will be checked.
* @function Menu.setIsOptionChecked
* @param {string} menuOption The name of the menu item to toggle.
*/
void triggerOption(const QString& menuOption);
/**jsdoc
* Check whether a menu is enabled. If a menu is disabled it will be greyed out
* and unselectable.
* Menus are enabled by default.
* @function Menu.isMenuEnabled
* @param {string} menuName The name of the menu to check.
* @return {bool} `true` if the menu is enabled, otherwise false.
*/
bool isMenuEnabled(const QString& menuName);
/**jsdoc
* Set a menu to be enabled or disabled.
* @function Menu.setMenuEnabled
* @param {string} menuName The name of the menu to modify.
* @param {bool} isEnabled Whether the menu will be enabled or not.
*/
void setMenuEnabled(const QString& menuName, bool isEnabled);
signals:
/**jsdoc
* This is a signal that is emitted when a menu item is clicked.
* @function Menu.menuItemEvent
* @param {string} menuItem Name of the menu item that was triggered.
*/
void menuItemEvent(const QString& menuItem);
};

View file

@ -39,6 +39,14 @@ Q_DECLARE_METATYPE(OverlayPropertyResult);
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value);
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value);
/**jsdoc
* @typedef Overlays.RayToOverlayIntersectionResult
* @property {bool} intersects True if the PickRay intersected with a 3D overlay.
* @property {Overlays.OverlayID} overlayID The ID of the overlay that was intersected with.
* @property {float} distance The distance from the PickRay origin to the intersection point.
* @property {Vec3} surfaceNormal The normal of the surface that was intersected with.
* @property {Vec3} intersection The point at which the PickRay intersected with the overlay.
*/
class RayToOverlayIntersectionResult {
public:
RayToOverlayIntersectionResult();
@ -57,6 +65,16 @@ Q_DECLARE_METATYPE(RayToOverlayIntersectionResult);
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value);
void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value);
/**jsdoc
* @typedef {int} Overlays.OverlayID
*/
/**jsdoc
*
* Overlays namespace...
* @namespace Overlays
*/
class Overlays : public QObject {
Q_OBJECT
@ -72,57 +90,137 @@ public:
Overlay::Pointer getOverlay(unsigned int id) const;
OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
void cleanupAllOverlays();
public slots:
/// adds an overlay with the specific properties
unsigned int addOverlay(const QString& type, const QVariant& properties);
/// adds an overlay that's already been created
unsigned int addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
unsigned int addOverlay(Overlay::Pointer overlay);
/// clones an existing overlay
void cleanupAllOverlays();
public slots:
/**jsdoc
* Add an overlays to the scene. The properties specified will depend
* on the type of overlay that is being created.
*
* @function Overlays.addOverlay
* @param {string} type The type of the overlay to add.
* @param {Overlays.OverlayProperties} The properties of the overlay that you want to add.
* @return {Overlays.OverlayID} The ID of the newly created overlay.
*/
unsigned int addOverlay(const QString& type, const QVariant& properties);
/**jsdoc
* Create a clone of an existing overlay.
*
* @function Overlays.cloneOverlay
* @param {Overlays.OverlayID} overlayID The ID of the overlay to clone.
* @return {Overlays.OverlayID} The ID of the new overlay.
*/
unsigned int cloneOverlay(unsigned int id);
/// edits an overlay updating only the included properties, will return the identified OverlayID in case of
/// successful edit, if the input id is for an unknown overlay this function will have no effect
/**jsdoc
* Edit an overlay's properties.
*
* @function Overlays.editOverlay
* @param {Overlays.OverlayID} overlayID The ID of the overlay to edit.
* @return {bool} `true` if the overlay was found and edited, otherwise false.
*/
bool editOverlay(unsigned int id, const QVariant& properties);
/// edits an overlay updating only the included properties, will return the identified OverlayID in case of
/// successful edit, if the input id is for an unknown overlay this function will have no effect
bool editOverlays(const QVariant& propertiesById);
/// deletes an overlay
/**jsdoc
* Delete an overlay.
*
* @function Overlays.deleteOverlay
* @param {Overlays.OverlayID} overlayID The ID of the overlay to delete.
*/
void deleteOverlay(unsigned int id);
/// get the string type of the overlay used in addOverlay
/**jsdoc
* Get the type of an overlay.
*
* @function Overlays.getOverlayType
* @param {Overlays.OverlayID} overlayID The ID of the overlay to get the type of.
* @return {string} The type of the overlay if found, otherwise the empty string.
*/
QString getOverlayType(unsigned int overlayId) const;
/**jsdoc
* Get the ID of the overlay at a particular point on the HUD/screen.
*
* @function Overlays.getOverlayAtPoint
* @param {Vec2} point The point to check for an overlay.
* @return {Overlays.OverlayID} The ID of the overlay at the point specified.
* If no overlay is found, `0` will be returned.
*/
unsigned int getOverlayAtPoint(const glm::vec2& point);
/**jsdoc
* Get the value of a an overlay's property.
*
* @function Overlays.getProperty
* @param {Overlays.OverlayID} The ID of the overlay to get the property of.
* @param {string} The name of the property to get the value of.
* @return {Object} The value of the property. If the overlay or the property could
* not be found, `undefined` will be returned.
*/
OverlayPropertyResult getProperty(unsigned int id, const QString& property);
/*jsdoc
* Find the closest 3D overlay hit by a pick ray.
*
* @function Overlays.findRayIntersection
* @param {PickRay} The PickRay to use for finding overlays.
* @return {Overlays.RayToOverlayIntersectionResult} The result of the ray cast.
*/
RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray);
/**jsdoc
* Check whether an overlay's assets have been loaded. For example, if the
* overlay is an "image" overlay, this will indicate whether the its image
* has loaded.
* @function Overlays.isLoaded
* @param {Overlays.OverlayID} The ID of the overlay to check.
* @return {bool} `true` if the overlay's assets have been loaded, otherwise `false`.
*/
bool isLoaded(unsigned int id);
/**jsdoc
* Calculates the size of the given text in the specified overlay if it is a text overlay.
* If it is a 2D text overlay, the size will be in pixels.
* If it is a 3D text overlay, the size will be in meters.
*
* @function Overlays.textSize
* @param {Overlays.OverlayID} The ID of the overlay to measure.
* @param {string} The string to measure.
* @return {Vec2} The size of the text.
*/
QSizeF textSize(unsigned int id, const QString& text) const;
/**jsdoc
* Get the width of the virtual 2D HUD.
*
* @function Overlays.width
* @return {float} The width of the 2D HUD.
*/
float width() const;
/**jsdoc
* Get the height of the virtual 2D HUD.
*
* @function Overlays.height
* @return {float} The height of the 2D HUD.
*/
float height() const;
/// return true if there is an overlay with that id else false
bool isAddedOverlay(unsigned int id);
unsigned int getParentPanel(unsigned int childId) const;
void setParentPanel(unsigned int childId, unsigned int panelId);
/// returns the top most 2D overlay at the screen point, or 0 if not overlay at that point
unsigned int getOverlayAtPoint(const glm::vec2& point);
/// returns the value of specified property, or null if there is no such property
OverlayPropertyResult getProperty(unsigned int id, const QString& property);
/// returns details about the closest 3D Overlay hit by the pick ray
RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray);
/// returns whether the overlay's assets are loaded or not
bool isLoaded(unsigned int id);
/// returns the size of the given text in the specified overlay if it is a text overlay: in pixels if it is a 2D text
/// overlay; in meters if it is a 3D text overlay
QSizeF textSize(unsigned int id, const QString& text) const;
// Return the size of the virtual screen
float width() const;
float height() const;
/// adds a panel that has already been created
unsigned int addPanel(OverlayPanel::Pointer panel);
@ -138,13 +236,16 @@ public slots:
/// deletes a panel and all child overlays
void deletePanel(unsigned int panelId);
/// return true if there is an overlay with that id else false
bool isAddedOverlay(unsigned int id);
/// return true if there is a panel with that id else false
bool isAddedPanel(unsigned int id) { return _panels.contains(id); }
signals:
/**jsdoc
* Emitted when an overlay is deleted
*
* @function Overlays.overlayDeleted
* @param {OverlayID} The ID of the overlay that was deleted.
*/
void overlayDeleted(unsigned int id);
void panelDeleted(unsigned int id);

View file

@ -438,6 +438,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign
return;
}
unhookChildAvatar(entityID);
emit deletingEntity(entityID);
// NOTE: callers must lock the tree before using this method
@ -447,6 +448,17 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign
_isDirty = true;
}
void EntityTree::unhookChildAvatar(const EntityItemID entityID) {
EntityItemPointer entity = findEntityByEntityItemID(entityID);
entity->forEachDescendant([&](SpatiallyNestablePointer child) {
if (child->getNestableType() == NestableType::Avatar) {
child->setParentID(nullptr);
}
});
}
void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool ignoreWarnings) {
// NOTE: callers must lock the tree before using this method
DeleteEntityOperator theOperator(getThisPointer());
@ -476,6 +488,7 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool i
}
// tell our delete operator about this entityID
unhookChildAvatar(entityID);
theOperator.addEntityIDToDeleteList(entityID);
emit deletingEntity(entityID);
}

View file

@ -121,6 +121,8 @@ public:
// use this method if you have a pointer to the entity (avoid an extra entity lookup)
bool updateEntity(EntityItemPointer entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
// check if the avatar is a child of this entity, If so set the avatar parentID to null
void unhookChildAvatar(const EntityItemID entityID);
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true);
void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = true);

View file

@ -83,9 +83,7 @@ public:
const Vec4i& region, QImage& destImage) final override;
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
static const int MAX_NUM_INPUT_BUFFERS = 16;
// this is the maximum numeber of available input buffers
size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); }
// this is the maximum per shader stage on the low end apple
@ -147,6 +145,10 @@ public:
virtual void do_startNamedCall(const Batch& batch, size_t paramOffset) final;
virtual void do_stopNamedCall(const Batch& batch, size_t paramOffset) final;
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
// The drawcall Info attribute channel is reserved and is the upper bound for the number of availables Input buffers
static const int MAX_NUM_INPUT_BUFFERS = Stream::DRAW_CALL_INFO;
virtual void do_pushProfileRange(const Batch& batch, size_t paramOffset) final;
virtual void do_popProfileRange(const Batch& batch, size_t paramOffset) final;
@ -235,18 +237,21 @@ protected:
virtual void initInput() final;
virtual void killInput() final;
virtual void syncInputStateCache() final;
virtual void resetInputStage() final;
virtual void updateInput();
virtual void resetInputStage();
virtual void updateInput() = 0;
struct InputStageState {
bool _invalidFormat { true };
Stream::FormatPointer _format;
std::string _formatKey;
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
ActivationCache _attributeActivation { 0 };
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
BuffersState _invalidBuffers { 0 };
BuffersState _invalidBuffers{ 0 };
BuffersState _attribBindingBuffers{ 0 };
Buffers _buffers;
Offsets _bufferOffsets;
@ -266,7 +271,11 @@ protected:
GLuint _defaultVAO { 0 };
InputStageState() :
_buffers(_invalidBuffers.size()),
_invalidFormat(true),
_format(0),
_formatKey(),
_attributeActivation(0),
_buffers(_invalidBuffers.size(), BufferPointer(0)),
_bufferOffsets(_invalidBuffers.size(), 0),
_bufferStrides(_invalidBuffers.size(), 0),
_bufferVBOs(_invalidBuffers.size(), 0) {}
@ -276,8 +285,8 @@ protected:
void killTransform();
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncTransformStateCache();
void updateTransform(const Batch& batch);
void resetTransformStage();
virtual void updateTransform(const Batch& batch) = 0;
virtual void resetTransformStage();
// Allows for correction of the camera pose to account for changes
// between the time when a was recorded and the time(s) when it is
@ -325,6 +334,8 @@ protected:
bool _invalidProj { false };
bool _invalidViewport { false };
bool _enabledDrawcallInfoBuffer{ false };
using Pair = std::pair<size_t, size_t>;
using List = std::list<Pair>;
List _cameraOffsets;
@ -399,8 +410,8 @@ protected:
void resetQueryStage();
struct QueryStageState {
};
uint32_t _rangeQueryDepth { 0 };
} _queryStage;
void resetStages();

View file

@ -10,16 +10,26 @@
//
#include "GLBackend.h"
#include "GLShared.h"
#include "GLInputFormat.h"
using namespace gpu;
using namespace gpu::gl;
void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
if (format != _input._format) {
_input._format = format;
_input._invalidFormat = true;
if (format) {
auto inputFormat = GLInputFormat::sync((*format));
assert(inputFormat);
if (_input._formatKey != inputFormat->key) {
_input._formatKey = inputFormat->key;
_input._invalidFormat = true;
}
} else {
_input._formatKey.clear();
_input._invalidFormat = true;
}
}
}
@ -93,16 +103,9 @@ void GLBackend::resetInputStage() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
(void) CHECK_GL_ERROR();
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
glDisableVertexAttribArray(i);
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
// Reset vertex buffer and format
_input._format.reset();
_input._formatKey.clear();
_input._invalidFormat = false;
_input._attributeActivation.reset();
@ -114,6 +117,7 @@ void GLBackend::resetInputStage() {
}
_input._invalidBuffers.reset();
// THe vertex array binding MUST be reset in the specific Backend versions as they use different techniques
}
void GLBackend::do_setIndexBuffer(const Batch& batch, size_t paramOffset) {
@ -151,183 +155,3 @@ void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) {
(void)CHECK_GL_ERROR();
}
// Core 41 doesn't expose the features to really separate the vertex format from the vertex buffers binding
// Core 43 does :)
// FIXME crashing problem with glVertexBindingDivisor / glVertexAttribFormat
// Once resolved, break this up into the GL 4.1 and 4.5 backends
#if 1 || (GPU_INPUT_PROFILE == GPU_CORE_41)
#define NO_SUPPORT_VERTEX_ATTRIB_FORMAT
#else
#define SUPPORT_VERTEX_ATTRIB_FORMAT
#endif
void GLBackend::updateInput() {
#if defined(SUPPORT_VERTEX_ATTRIB_FORMAT)
if (_input._invalidFormat) {
InputStageState::ActivationCache newActivation;
// Assign the vertex format required
if (_input._format) {
for (auto& it : _input._format->getAttributes()) {
const Stream::Attribute& attrib = (it).second;
GLuint slot = attrib._slot;
GLuint count = attrib._element.getLocationScalarCount();
uint8_t locationCount = attrib._element.getLocationCount();
GLenum type = _elementTypeToGL41Type[attrib._element.getType()];
GLuint offset = attrib._offset;;
GLboolean isNormalized = attrib._element.isNormalized();
GLenum perLocationSize = attrib._element.getLocationSize();
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
newActivation.set(slot + locNum);
glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize);
glVertexAttribBinding(slot + locNum, attrib._channel);
}
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexBindingDivisor(attrib._channel, attrib._frequency * (isStereo() ? 2 : 1));
#else
glVertexBindingDivisor(attrib._channel, attrib._frequency);
#endif
}
(void)CHECK_GL_ERROR();
}
// Manage Activation what was and what is expected now
for (size_t i = 0; i < newActivation.size(); i++) {
bool newState = newActivation[i];
if (newState != _input._attributeActivation[i]) {
if (newState) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
_input._attributeActivation.flip(i);
}
}
(void)CHECK_GL_ERROR();
_input._invalidFormat = false;
_stats._ISNumFormatChanges++;
}
if (_input._invalidBuffers.any()) {
int numBuffers = _input._buffers.size();
auto buffer = _input._buffers.data();
auto vbo = _input._bufferVBOs.data();
auto offset = _input._bufferOffsets.data();
auto stride = _input._bufferStrides.data();
for (int bufferNum = 0; bufferNum < numBuffers; bufferNum++) {
if (_input._invalidBuffers.test(bufferNum)) {
glBindVertexBuffer(bufferNum, (*vbo), (*offset), (*stride));
}
buffer++;
vbo++;
offset++;
stride++;
}
_input._invalidBuffers.reset();
(void)CHECK_GL_ERROR();
}
#else
if (_input._invalidFormat || _input._invalidBuffers.any()) {
if (_input._invalidFormat) {
InputStageState::ActivationCache newActivation;
_stats._ISNumFormatChanges++;
// Check expected activation
if (_input._format) {
for (auto& it : _input._format->getAttributes()) {
const Stream::Attribute& attrib = (it).second;
uint8_t locationCount = attrib._element.getLocationCount();
for (int i = 0; i < locationCount; ++i) {
newActivation.set(attrib._slot + i);
}
}
}
// Manage Activation what was and what is expected now
for (unsigned int i = 0; i < newActivation.size(); i++) {
bool newState = newActivation[i];
if (newState != _input._attributeActivation[i]) {
if (newState) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
(void)CHECK_GL_ERROR();
_input._attributeActivation.flip(i);
}
}
}
// now we need to bind the buffers and assign the attrib pointers
if (_input._format) {
const Buffers& buffers = _input._buffers;
const Offsets& offsets = _input._bufferOffsets;
const Offsets& strides = _input._bufferStrides;
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
auto& inputChannels = _input._format->getChannels();
_stats._ISNumInputBufferChanges++;
GLuint boundVBO = 0;
for (auto& channelIt : inputChannels) {
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
if ((channelIt).first < buffers.size()) {
int bufferNum = (channelIt).first;
if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) {
// GLuint vbo = gpu::GL41Backend::getBufferID((*buffers[bufferNum]));
GLuint vbo = _input._bufferVBOs[bufferNum];
if (boundVBO != vbo) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
(void)CHECK_GL_ERROR();
boundVBO = vbo;
}
_input._invalidBuffers[bufferNum] = false;
for (unsigned int i = 0; i < channel._slots.size(); i++) {
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
GLuint slot = attrib._slot;
GLuint count = attrib._element.getLocationScalarCount();
uint8_t locationCount = attrib._element.getLocationCount();
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
// GLenum perLocationStride = strides[bufferNum];
GLenum perLocationStride = attrib._element.getLocationSize();
GLuint stride = (GLuint)strides[bufferNum];
GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]);
GLboolean isNormalized = attrib._element.isNormalized();
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride,
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1));
#else
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency);
#endif
}
// TODO: Support properly the IAttrib version
(void)CHECK_GL_ERROR();
}
}
}
}
}
// everything format related should be in sync now
_input._invalidFormat = false;
}
#endif
}

View file

@ -16,8 +16,10 @@ using namespace gpu::gl;
// Eventually, we want to test with TIME_ELAPSED instead of TIMESTAMP
#ifdef Q_OS_MAC
const uint32_t MAX_RANGE_QUERY_DEPTH = 1;
static bool timeElapsed = true;
#else
const uint32_t MAX_RANGE_QUERY_DEPTH = 10000;
static bool timeElapsed = false;
#endif
@ -27,12 +29,17 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
if (glquery) {
PROFILE_RANGE_BEGIN(glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00);
glquery->_batchElapsedTime = usecTimestampNow() * 1000;
++_queryStage._rangeQueryDepth;
glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime);
if (timeElapsed) {
glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo);
if (_queryStage._rangeQueryDepth <= MAX_RANGE_QUERY_DEPTH) {
glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo);
}
} else {
glQueryCounter(glquery->_beginqo, GL_TIMESTAMP);
}
glquery->_rangeQueryDepth = _queryStage._rangeQueryDepth;
(void)CHECK_GL_ERROR();
}
}
@ -42,12 +49,16 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
if (timeElapsed) {
glEndQuery(GL_TIME_ELAPSED);
if (_queryStage._rangeQueryDepth <= MAX_RANGE_QUERY_DEPTH) {
glEndQuery(GL_TIME_ELAPSED);
}
} else {
glQueryCounter(glquery->_endqo, GL_TIMESTAMP);
}
GLint64 now = usecTimestampNow() * 1000;
--_queryStage._rangeQueryDepth;
GLint64 now;
glGetInteger64v(GL_TIMESTAMP, &now);
glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
PROFILE_RANGE_END(glquery->_profileRangeId);
@ -59,20 +70,24 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
if (glquery->_result == GL_TRUE) {
if (timeElapsed) {
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &glquery->_result);
} else {
GLuint64 start, end;
glGetQueryObjectui64v(glquery->_beginqo, GL_QUERY_RESULT, &start);
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &end);
glquery->_result = end - start;
}
if (glquery) {
if (glquery->_rangeQueryDepth > MAX_RANGE_QUERY_DEPTH) {
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
} else {
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
if (glquery->_result == GL_TRUE) {
if (timeElapsed) {
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &glquery->_result);
} else {
GLuint64 start, end;
glGetQueryObjectui64v(glquery->_beginqo, GL_QUERY_RESULT, &start);
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &end);
glquery->_result = end - start;
}
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
}
(void)CHECK_GL_ERROR();
}
(void)CHECK_GL_ERROR();
}
}

View file

@ -85,6 +85,9 @@ void GLBackend::syncTransformStateCache() {
Mat4 modelView;
auto modelViewInv = glm::inverse(modelView);
_transform._view.evalFromRawMatrix(modelViewInv);
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO);
_transform._enabledDrawcallInfoBuffer = false;
}
void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const StereoState& stereo) {
@ -162,29 +165,7 @@ void GLBackend::TransformStageState::bindCurrentCamera(int eye) const {
}
}
void GLBackend::updateTransform(const Batch& batch) {
_transform.update(_commandIndex, _stereo);
auto& drawCallInfoBuffer = batch.getDrawCallInfoBuffer();
if (batch._currentNamedCall.empty()) {
auto& drawCallInfo = drawCallInfoBuffer[_currentDraw];
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is disabled
glVertexAttribI2i(gpu::Stream::DRAW_CALL_INFO, drawCallInfo.index, drawCallInfo.unused);
} else {
glEnableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is enabled
glBindBuffer(GL_ARRAY_BUFFER, _transform._drawCallInfoBuffer);
glVertexAttribIPointer(gpu::Stream::DRAW_CALL_INFO, 2, GL_UNSIGNED_SHORT, 0,
_transform._drawCallInfoOffsets[batch._currentNamedCall]);
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, (isStereo() ? 2 : 1));
#else
glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, 1);
#endif
}
(void)CHECK_GL_ERROR();
}
void GLBackend::resetTransformStage() {
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO);
_transform._enabledDrawcallInfoBuffer = false;
}

View file

@ -0,0 +1,33 @@
//
// Created by Sam Gateau on 2016/07/21
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLInputFormat.h"
#include "GLBackend.h"
using namespace gpu;
using namespace gpu::gl;
GLInputFormat::GLInputFormat() {
}
GLInputFormat:: ~GLInputFormat() {
}
GLInputFormat* GLInputFormat::sync(const Stream::Format& inputFormat) {
GLInputFormat* object = Backend::getGPUObject<GLInputFormat>(inputFormat);
if (!object) {
object = new GLInputFormat();
object->key = inputFormat.getKey();
Backend::setGPUObject(inputFormat, object);
}
return object;
}

View file

@ -0,0 +1,29 @@
//
// Created by Sam Gateau on 2016/07/21
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLInputFormat_h
#define hifi_gpu_gl_GLInputFormat_h
#include "GLShared.h"
namespace gpu {
namespace gl {
class GLInputFormat : public GPUObject {
public:
static GLInputFormat* sync(const Stream::Format& inputFormat);
GLInputFormat();
~GLInputFormat();
std::string key;
};
}
}
#endif

View file

@ -50,6 +50,7 @@ public:
GLuint64 _result { (GLuint64)-1 };
GLuint64 _batchElapsedTime { (GLuint64) 0 };
uint64_t _profileRangeId { 0 };
uint32_t _rangeQueryDepth { 0 };
protected:
GLQuery(const std::weak_ptr<GLBackend>& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {}

View file

@ -77,13 +77,13 @@ protected:
void do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) override;
// Input Stage
void resetInputStage() override;
void updateInput() override;
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void transferTransformState(const Batch& batch) const override;
void initTransform() override;
void updateTransform(const Batch& batch);
void resetTransformStage();
void updateTransform(const Batch& batch) override;
// Output stage
void do_blit(const Batch& batch, size_t paramOffset) override;

View file

@ -13,7 +13,111 @@
using namespace gpu;
using namespace gpu::gl41;
void GL41Backend::updateInput() {
Parent::updateInput();
void GL41Backend::resetInputStage() {
Parent::resetInputStage();
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
glDisableVertexAttribArray(i);
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
}
void GL41Backend::updateInput() {
if (_input._invalidFormat || _input._invalidBuffers.any()) {
if (_input._invalidFormat) {
InputStageState::ActivationCache newActivation;
_stats._ISNumFormatChanges++;
// Check expected activation
if (_input._format) {
for (auto& it : _input._format->getAttributes()) {
const Stream::Attribute& attrib = (it).second;
uint8_t locationCount = attrib._element.getLocationCount();
for (int i = 0; i < locationCount; ++i) {
newActivation.set(attrib._slot + i);
}
}
}
// Manage Activation what was and what is expected now
for (unsigned int i = 0; i < newActivation.size(); i++) {
bool newState = newActivation[i];
if (newState != _input._attributeActivation[i]) {
if (newState) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
(void)CHECK_GL_ERROR();
_input._attributeActivation.flip(i);
}
}
}
// now we need to bind the buffers and assign the attrib pointers
if (_input._format) {
const Buffers& buffers = _input._buffers;
const Offsets& offsets = _input._bufferOffsets;
const Offsets& strides = _input._bufferStrides;
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
auto& inputChannels = _input._format->getChannels();
_stats._ISNumInputBufferChanges++;
GLuint boundVBO = 0;
for (auto& channelIt : inputChannels) {
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
if ((channelIt).first < buffers.size()) {
int bufferNum = (channelIt).first;
if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) {
// GLuint vbo = gpu::GL41Backend::getBufferID((*buffers[bufferNum]));
GLuint vbo = _input._bufferVBOs[bufferNum];
if (boundVBO != vbo) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
(void)CHECK_GL_ERROR();
boundVBO = vbo;
}
_input._invalidBuffers[bufferNum] = false;
for (unsigned int i = 0; i < channel._slots.size(); i++) {
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
GLuint slot = attrib._slot;
GLuint count = attrib._element.getLocationScalarCount();
uint8_t locationCount = attrib._element.getLocationCount();
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
// GLenum perLocationStride = strides[bufferNum];
GLenum perLocationStride = attrib._element.getLocationSize();
GLuint stride = (GLuint)strides[bufferNum];
GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]);
GLboolean isNormalized = attrib._element.isNormalized();
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride,
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1));
#else
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency);
#endif
}
// TODO: Support properly the IAttrib version
(void)CHECK_GL_ERROR();
}
}
}
}
}
// everything format related should be in sync now
_input._invalidFormat = false;
}
}

View file

@ -79,3 +79,32 @@ void GL41Backend::transferTransformState(const Batch& batch) const {
// Make sure the current Camera offset is unknown before render Draw
_transform._currentCameraOffset = INVALID_OFFSET;
}
void GL41Backend::updateTransform(const Batch& batch) {
_transform.update(_commandIndex, _stereo);
auto& drawCallInfoBuffer = batch.getDrawCallInfoBuffer();
if (batch._currentNamedCall.empty()) {
auto& drawCallInfo = drawCallInfoBuffer[_currentDraw];
if (_transform._enabledDrawcallInfoBuffer) {
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is disabled
_transform._enabledDrawcallInfoBuffer = false;
}
glVertexAttribI2i(gpu::Stream::DRAW_CALL_INFO, drawCallInfo.index, drawCallInfo.unused);
} else {
if (!_transform._enabledDrawcallInfoBuffer) {
glEnableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is enabled
glBindBuffer(GL_ARRAY_BUFFER, _transform._drawCallInfoBuffer);
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, (isStereo() ? 2 : 1));
#else
glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, 1);
#endif
_transform._enabledDrawcallInfoBuffer = true;
}
glVertexAttribIPointer(gpu::Stream::DRAW_CALL_INFO, 2, GL_UNSIGNED_SHORT, 0, _transform._drawCallInfoOffsets[batch._currentNamedCall]);
}
(void)CHECK_GL_ERROR();
}

View file

@ -130,13 +130,13 @@ protected:
void do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) override;
// Input Stage
void resetInputStage() override;
void updateInput() override;
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void transferTransformState(const Batch& batch) const override;
void initTransform() override;
void updateTransform(const Batch& batch);
void resetTransformStage();
void updateTransform(const Batch& batch) override;
// Output stage
void do_blit(const Batch& batch, size_t paramOffset) override;

View file

@ -9,10 +9,112 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GL45Backend.h"
#include "../gl/GLShared.h"
using namespace gpu;
using namespace gpu::gl45;
void GL45Backend::updateInput() {
Parent::updateInput();
void GL45Backend::resetInputStage() {
Parent::resetInputStage();
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
glDisableVertexAttribArray(i);
}
for (uint32_t i = 0; i < _input._attribBindingBuffers.size(); i++) {
glBindVertexBuffer(i, 0, 0, 0);
}
}
void GL45Backend::updateInput() {
if (_input._invalidFormat) {
InputStageState::ActivationCache newActivation;
// Assign the vertex format required
if (_input._format) {
_input._attribBindingBuffers.reset();
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
auto& inputChannels = _input._format->getChannels();
for (auto& channelIt : inputChannels) {
auto bufferChannelNum = (channelIt).first;
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
_input._attribBindingBuffers.set(bufferChannelNum);
GLuint frequency = 0;
for (unsigned int i = 0; i < channel._slots.size(); i++) {
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
GLuint slot = attrib._slot;
GLuint count = attrib._element.getLocationScalarCount();
uint8_t locationCount = attrib._element.getLocationCount();
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
GLuint offset = (GLuint)attrib._offset;;
GLboolean isNormalized = attrib._element.isNormalized();
GLenum perLocationSize = attrib._element.getLocationSize();
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
GLuint attriNum = (GLuint)(slot + locNum);
newActivation.set(attriNum);
if (!_input._attributeActivation[attriNum]) {
_input._attributeActivation.set(attriNum);
glEnableVertexAttribArray(attriNum);
}
glVertexAttribFormat(attriNum, count, type, isNormalized, offset + locNum * perLocationSize);
// TODO: Support properly the IAttrib version
glVertexAttribBinding(attriNum, attrib._channel);
}
if (i == 0) {
frequency = attrib._frequency;
} else {
assert(frequency == attrib._frequency);
}
(void)CHECK_GL_ERROR();
}
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexBindingDivisor(bufferChannelNum, frequency * (isStereo() ? 2 : 1));
#else
glVertexBindingDivisor(bufferChannelNum, frequency);
#endif
}
// Manage Activation what was and what is expected now
// This should only disable VertexAttribs since the one in use have been disabled above
for (GLuint i = 0; i < (GLuint)newActivation.size(); i++) {
bool newState = newActivation[i];
if (newState != _input._attributeActivation[i]) {
if (newState) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
_input._attributeActivation.flip(i);
}
}
(void)CHECK_GL_ERROR();
}
_input._invalidFormat = false;
_stats._ISNumFormatChanges++;
}
if (_input._invalidBuffers.any()) {
auto vbo = _input._bufferVBOs.data();
auto offset = _input._bufferOffsets.data();
auto stride = _input._bufferStrides.data();
for (GLuint buffer = 0; buffer < _input._buffers.size(); buffer++, vbo++, offset++, stride++) {
if (_input._invalidBuffers.test(buffer)) {
glBindVertexBuffer(buffer, (*vbo), (*offset), (GLsizei)(*stride));
}
}
_input._invalidBuffers.reset();
(void)CHECK_GL_ERROR();
}
}

View file

@ -66,3 +66,36 @@ void GL45Backend::transferTransformState(const Batch& batch) const {
// Make sure the current Camera offset is unknown before render Draw
_transform._currentCameraOffset = INVALID_OFFSET;
}
void GL45Backend::updateTransform(const Batch& batch) {
_transform.update(_commandIndex, _stereo);
auto& drawCallInfoBuffer = batch.getDrawCallInfoBuffer();
if (batch._currentNamedCall.empty()) {
auto& drawCallInfo = drawCallInfoBuffer[_currentDraw];
if (_transform._enabledDrawcallInfoBuffer) {
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is disabled
_transform._enabledDrawcallInfoBuffer = false;
}
glVertexAttribI2i(gpu::Stream::DRAW_CALL_INFO, drawCallInfo.index, drawCallInfo.unused);
} else {
if (!_transform._enabledDrawcallInfoBuffer) {
glEnableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is enabled
glVertexAttribIFormat(gpu::Stream::DRAW_CALL_INFO, 2, GL_UNSIGNED_SHORT, 0);
glVertexAttribBinding(gpu::Stream::DRAW_CALL_INFO, gpu::Stream::DRAW_CALL_INFO);
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexBindingDivisor(gpu::Stream::DRAW_CALL_INFO, (isStereo() ? 2 : 1));
#else
glVertexBindingDivisor(gpu::Stream::DRAW_CALL_INFO, 1);
#endif
_transform._enabledDrawcallInfoBuffer = true;
}
// NOTE: A stride of zero in BindVertexBuffer signifies that all elements are sourced from the same location,
// so we must provide a stride.
// This is in contrast to VertexAttrib*Pointer, where a zero signifies tightly-packed elements.
glBindVertexBuffer(gpu::Stream::DRAW_CALL_INFO, _transform._drawCallInfoBuffer, (GLintptr)_transform._drawCallInfoOffsets[batch._currentNamedCall], 2 * sizeof(GLushort));
}
(void)CHECK_GL_ERROR();
}

View file

@ -13,6 +13,23 @@
#include "GPULogging.h"
using namespace gpu;
void ContextStats::evalDelta(const ContextStats& begin, const ContextStats& end) {
_ISNumFormatChanges = end._ISNumFormatChanges - begin._ISNumFormatChanges;
_ISNumInputBufferChanges = end._ISNumInputBufferChanges - begin._ISNumInputBufferChanges;
_ISNumIndexBufferChanges = end._ISNumIndexBufferChanges - begin._ISNumIndexBufferChanges;
_RSNumTextureBounded = end._RSNumTextureBounded - begin._RSNumTextureBounded;
_RSAmountTextureMemoryBounded = end._RSAmountTextureMemoryBounded - begin._RSAmountTextureMemoryBounded;
_DSNumAPIDrawcalls = end._DSNumAPIDrawcalls - begin._DSNumAPIDrawcalls;
_DSNumDrawcalls = end._DSNumDrawcalls - begin._DSNumDrawcalls;
_DSNumTriangles= end._DSNumTriangles - begin._DSNumTriangles;
_PSNumSetPipelines = end._PSNumSetPipelines - begin._PSNumSetPipelines;
}
Context::CreateBackend Context::_createBackendCallback = nullptr;
Context::MakeProgram Context::_makeProgramCallback = nullptr;
std::once_flag Context::_initialized;
@ -73,6 +90,10 @@ void Context::consumeFrameUpdates(const FramePointer& frame) const {
}
void Context::executeFrame(const FramePointer& frame) const {
// Grab the stats at the around the frame and delta to have a consistent sampling
ContextStats beginStats;
getStats(beginStats);
// FIXME? probably not necessary, but safe
consumeFrameUpdates(frame);
_backend->setStereoState(frame->stereoState);
@ -90,6 +111,10 @@ void Context::executeFrame(const FramePointer& frame) const {
_frameRangeTimer->end(endBatch);
_backend->render(endBatch);
}
ContextStats endStats;
getStats(endStats);
_frameStats.evalDelta(beginStats, endStats);
}
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
@ -135,10 +160,18 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons
_backend->downloadFramebuffer(srcFramebuffer, region, destImage);
}
void Context::resetStats() const {
_backend->resetStats();
}
void Context::getStats(ContextStats& stats) const {
_backend->getStats(stats);
}
void Context::getFrameStats(ContextStats& stats) const {
stats = _frameStats;
}
double Context::getFrameTimerGPUAverage() const {
if (_frameRangeTimer) {
return _frameRangeTimer->getGPUAverage();

View file

@ -45,6 +45,8 @@ public:
ContextStats() {}
ContextStats(const ContextStats& stats) = default;
void evalDelta(const ContextStats& begin, const ContextStats& end);
};
class Backend {
@ -83,6 +85,7 @@ public:
return reinterpret_cast<T*>(object.gpuObject.getGPUObject());
}
void resetStats() const { _stats = ContextStats(); }
void getStats(ContextStats& stats) const { stats = _stats; }
virtual bool isTextureManagementSparseEnabled() const = 0;
@ -123,7 +126,7 @@ protected:
}
friend class Context;
ContextStats _stats;
mutable ContextStats _stats;
StereoState _stereo;
};
@ -201,8 +204,11 @@ public:
void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage);
// Repporting stats of the context
void resetStats() const;
void getStats(ContextStats& stats) const;
// Same as above but grabbed at every end of a frame
void getFrameStats(ContextStats& stats) const;
double getFrameTimerGPUAverage() const;
double getFrameTimerBatchAverage() const;
@ -229,8 +235,8 @@ protected:
RangeTimerPointer _frameRangeTimer;
StereoState _stereo;
double getGPUAverage() const;
double getBatchAverage() const;
// Sampled at the end of every frame, the stats of all the counters
mutable ContextStats _frameStats;
// This function can only be called by "static Shader::makeProgram()"
// makeProgramShader(...) make a program shader ready to be used in a Batch.

View file

@ -12,6 +12,8 @@
#include "Stream.h"
#include <algorithm> //min max and more
#include <sstream>
#include <iomanip>
using namespace gpu;
@ -39,9 +41,21 @@ const ElementArray& getDefaultElements() {
return defaultElements;
}
std::string Stream::Attribute::getKey() const {
std::stringstream skey;
skey << std::hex;
skey << std::setw(8) << std::setfill('0') << (uint32)((((uint32)_slot) << 24) | (((uint32)_channel) << 16) | ((uint32)_element.getRaw()));
skey << _offset;
skey << _frequency;
return skey.str();
}
void Stream::Format::evaluateCache() {
_key.clear();
_channels.clear();
_elementTotalSize = 0;
for(AttributeMap::iterator it = _attributes.begin(); it != _attributes.end(); it++) {
Attribute& attrib = (*it).second;
ChannelInfo& channel = _channels[attrib._channel];
@ -49,6 +63,8 @@ void Stream::Format::evaluateCache() {
channel._stride = std::max(channel._stride, attrib.getSize() + attrib._offset);
channel._netSize += attrib.getSize();
_elementTotalSize += attrib.getSize();
_key += attrib.getKey();
}
}

View file

@ -14,6 +14,7 @@
#include <vector>
#include <map>
#include <array>
#include <string>
#include <assert.h>
@ -73,6 +74,9 @@ public:
// Size of the
uint32 getSize() const { return _element.getSize(); }
// Generate a string key describing the attribute uniquely
std::string getKey() const;
};
// Stream Format is describing how to feed a list of attributes from a bunch of stream buffer channels
@ -106,10 +110,15 @@ public:
bool hasAttribute(Slot slot) const { return (_attributes.find(slot) != _attributes.end()); }
const std::string& getKey() const { return _key; }
const GPUObjectPointer gpuObject{};
protected:
AttributeMap _attributes;
ChannelMap _channels;
uint32 _elementTotalSize { 0 };
std::string _key;
void evaluateCache();
};

View file

@ -35,14 +35,24 @@ layout(std140) uniform transformCameraBuffer {
#ifdef GPU_VERTEX_SHADER
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_CAMERA
#ifdef GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED
layout(location=14) in int _inStereoSide;
#endif
flat out int _stereoSide;
// In stereo drawcall mode Instances are drawn twice (left then right) hence the true InstanceID is the gl_InstanceID / 2
int gpu_InstanceID = gl_InstanceID >> 1;
#else
int gpu_InstanceID = gl_InstanceID;
#endif
#else
int gpu_InstanceID = gl_InstanceID;
#endif
@ -54,6 +64,7 @@ flat in int _stereoSide;
#endif
#endif
TransformCamera getTransformCamera() {
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_CAMERA
@ -211,6 +222,8 @@ TransformObject getTransformObject() {
{ // transformWorldToClipPos
vec4 eyeWAPos = <$worldPos$> - vec4(<$cameraTransform$>._viewInverse[3].xyz, 0.0);
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos;
<$transformStereoClipsSpace($cameraTransform$, $clipPos$)$>
}
<@endfunc@>

View file

@ -179,6 +179,10 @@ void LightClusters::updateFrustum(const ViewFrustum& frustum) {
_frustum = frustum;
_frustumGridBuffer.edit().updateFrustum(frustum);
if (true) {
_frustumGridBuffer.edit().generateGridPlanes(_gridPlanes[0], _gridPlanes[1], _gridPlanes[2]);
}
}
void LightClusters::updateLightStage(const LightStagePointer& lightStage) {

View file

@ -53,12 +53,12 @@ void main(void) {
ivec3 cluster = clusterGrid_getCluster(gl_InstanceID);
ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID);
int numLights = cluster.x + cluster.y;
float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0);
ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID);
ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID);
float boxScale = 0.99;
vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3((1.0 - boxScale) * 0.5 + (1.0 - numLightsScale) * boxScale * 0.5) + numLightsScale * boxScale * pos.xyz);
@ -69,5 +69,5 @@ void main(void) {
TransformCamera cam = getTransformCamera();
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), (numLights >0 ? 0.9 : 0.1));
varColor = vec4(colorWheel(fract(float(gpu_InstanceID) / float(frustumGrid_numClusters()))), (numLights >0 ? 0.9 : 0.1));
}

View file

@ -53,7 +53,7 @@ void main(void) {
);
vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]];
ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID);
ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID);
vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz);
vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0));
@ -62,5 +62,5 @@ void main(void) {
TransformCamera cam = getTransformCamera();
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9);
varColor = vec4(colorWheel(fract(float(gpu_InstanceID) / float(frustumGrid_numClusters()))), 0.9);
}

View file

@ -54,10 +54,10 @@ void main(void) {
vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]];
ivec3 cluster = clusterGrid_getCluster(gl_InstanceID);
ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID);
int numLights = cluster.x + cluster.y;
ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID);
ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID);
float boxScale = 1.0;
@ -69,5 +69,5 @@ void main(void) {
TransformCamera cam = getTransformCamera();
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0));
varColor = vec4(colorWheel(fract(float(gpu_InstanceID) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0));
}

View file

@ -35,21 +35,21 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
config->textureGPUVirtualMemoryUsage = gpu::Texture::getTextureGPUVirtualMemoryUsage();
config->textureGPUTransferCount = gpu::Texture::getTextureGPUTransferCount();
gpu::ContextStats gpuStats(_gpuStats);
renderContext->args->_context->getStats(_gpuStats);
renderContext->args->_context->getFrameStats(_gpuStats);
config->frameAPIDrawcallCount = _gpuStats._DSNumAPIDrawcalls - gpuStats._DSNumAPIDrawcalls;
config->frameDrawcallCount = _gpuStats._DSNumDrawcalls - gpuStats._DSNumDrawcalls;
config->frameAPIDrawcallCount = _gpuStats._DSNumAPIDrawcalls;
config->frameDrawcallCount = _gpuStats._DSNumDrawcalls;
config->frameDrawcallRate = config->frameDrawcallCount * frequency;
config->frameTriangleCount = _gpuStats._DSNumTriangles - gpuStats._DSNumTriangles;
config->frameTriangleCount = _gpuStats._DSNumTriangles;
config->frameTriangleRate = config->frameTriangleCount * frequency;
config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded;
config->frameTextureCount = _gpuStats._RSNumTextureBounded;
config->frameTextureRate = config->frameTextureCount * frequency;
config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded;
config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded;
config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines - gpuStats._PSNumSetPipelines;
config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines;
config->frameSetInputFormatCount = _gpuStats._ISNumFormatChanges;
config->emitDirty();
}

View file

@ -48,6 +48,7 @@ namespace render {
Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty)
Q_PROPERTY(quint32 frameSetPipelineCount MEMBER frameSetPipelineCount NOTIFY dirty)
Q_PROPERTY(quint32 frameSetInputFormatCount MEMBER frameSetInputFormatCount NOTIFY dirty)
public:
@ -78,6 +79,8 @@ namespace render {
quint32 frameSetPipelineCount{ 0 };
quint32 frameSetInputFormatCount{ 0 };
void emitDirty() { emit dirty(); }

View file

@ -28,7 +28,7 @@ MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& m
{
}
MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& menuItemName,
MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& menuItemName,
const KeyEvent& shortcutKeyEvent, bool checkable, bool checked, bool separator) :
menuName(menuName),
menuItemName(menuItemName),
@ -50,13 +50,31 @@ QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuIt
return obj;
}
/**jsdoc
* `MenuItemProperties` is a list of properties that can be passed to Menu.addMenuItem
* to create a new menu item.
*
* If none of position, beforeItem, afterItem, or grouping are specified, the
* menu item will be placed in the last position.
*
* @typedef {Object} Menu.MenuItemProperties
* @property {string} menuName Name of the top-level menu
* @property {string} menuItemName Name of the menu item
* @property {bool} isCheckable Whether the menu item is checkable or not
* @property {bool} isChecked Where the menu item is checked or not
* @property {string} shortcutKey An optional shortcut key to trigger the menu item.
* @property {int} position The position to place the new menu item. `0` is the first menu item.
* @property {string} beforeItem The name of the menu item to place this menu item before.
* @property {string} afterItem The name of the menu item to place this menu item after.
* @property {string} grouping The name of grouping to add this menu item to.
*/
void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemProperties& properties) {
properties.menuName = object.property("menuName").toVariant().toString();
properties.menuItemName = object.property("menuItemName").toVariant().toString();
properties.isCheckable = object.property("isCheckable").toVariant().toBool();
properties.isChecked = object.property("isChecked").toVariant().toBool();
properties.isSeparator = object.property("isSeparator").toVariant().toBool();
// handle the shortcut key options in order...
QScriptValue shortcutKeyValue = object.property("shortcutKey");
if (shortcutKeyValue.isValid()) {

View file

@ -20,6 +20,24 @@
#include "GLMHelpers.h"
/**jsdoc
* A 2-dimensional vector.
*
* @typedef Vec2
* @property {float} x X-coordinate of the vector.
* @property {float} y Y-coordinate of the vector.
*/
/**jsdoc
* A 3-dimensional vector.
*
* @typedef Vec3
* @property {float} x X-coordinate of the vector.
* @property {float} y Y-coordinate of the vector.
* @property {float} z Z-coordinate of the vector.
*/
/// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API
class Vec3 : public QObject {
Q_OBJECT

View file

@ -197,7 +197,7 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
ULONG uNumOfInstances = 0;
CComPtr<IWbemClassObject> spInstance = NULL;
hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance, &uNumOfInstances);
hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance.p, &uNumOfInstances);
while (hr == S_OK && spInstance && uNumOfInstances) {
// Get properties from the object
CComVariant var;

View file

@ -16,6 +16,11 @@
#include "DependencyManager.h"
/**jsdoc
* @namespace Paths
* @readonly
* @property {string} resources The path to the resources directory.
*/
class PathUtils : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY

View file

@ -173,6 +173,11 @@ Item {
prop: "frameSetPipelineCount",
label: "Pipelines",
color: "#E2334D"
},
{
prop: "frameSetInputFormatCount",
label: "Input Formats",
color: "#1AC567"
}
]
}

View file

@ -16,6 +16,7 @@ exports.handlers = {
var dirList = [
'../../interface/src',
'../../interface/src/scripting',
'../../interface/src/ui/overlays',
'../../libraries/script-engine/src',
'../../libraries/networking/src',
'../../libraries/animation/src',