mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge pull request #7481 from samcake/lemon
Monitoring Tool for rendering engine
This commit is contained in:
commit
b26533bc14
18 changed files with 788 additions and 82 deletions
186
examples/utilities/tools/render/PlotPerf.qml
Normal file
186
examples/utilities/tools/render/PlotPerf.qml
Normal file
|
@ -0,0 +1,186 @@
|
|||
//
|
||||
// PlotPerf.qml
|
||||
// examples/utilities/tools/render
|
||||
//
|
||||
// Created by Sam Gateau on 3//2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: parent.width
|
||||
height: 100
|
||||
property string title
|
||||
property var config
|
||||
property string parameters
|
||||
|
||||
// THis is my hack to get the name of the first property and assign it to a trigger var in order to get
|
||||
// a signal called whenever the value changed
|
||||
property var trigger: config[parameters.split(":")[3].split("-")[0]]
|
||||
|
||||
property var inputs: parameters.split(":")
|
||||
property var valueScale: +inputs[0]
|
||||
property var valueUnit: inputs[1]
|
||||
property var valueNumDigits: inputs[2]
|
||||
property var input_VALUE_OFFSET: 3
|
||||
property var valueMax : 1
|
||||
|
||||
property var _values : new Array()
|
||||
property var tick : 0
|
||||
|
||||
function createValues() {
|
||||
if (inputs.length > input_VALUE_OFFSET) {
|
||||
for (var i = input_VALUE_OFFSET; i < inputs.length; i++) {
|
||||
var varProps = inputs[i].split("-")
|
||||
_values.push( {
|
||||
value: varProps[0],
|
||||
valueMax: 1,
|
||||
numSamplesConstantMax: 0,
|
||||
valueHistory: new Array(),
|
||||
label: varProps[1],
|
||||
color: varProps[2],
|
||||
scale: (varProps.length > 3 ? varProps[3] : 1),
|
||||
unit: (varProps.length > 4 ? varProps[4] : valueUnit)
|
||||
})
|
||||
}
|
||||
}
|
||||
print("in creator" + JSON.stringify(_values));
|
||||
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
createValues();
|
||||
print(JSON.stringify(_values));
|
||||
|
||||
}
|
||||
|
||||
function pullFreshValues() {
|
||||
//print("pullFreshValues");
|
||||
var VALUE_HISTORY_SIZE = 100;
|
||||
var UPDATE_CANVAS_RATE = 20;
|
||||
tick++;
|
||||
|
||||
|
||||
var currentValueMax = 0
|
||||
for (var i = 0; i < _values.length; i++) {
|
||||
|
||||
var currentVal = config[_values[i].value] * _values[i].scale;
|
||||
_values[i].valueHistory.push(currentVal)
|
||||
_values[i].numSamplesConstantMax++;
|
||||
|
||||
if (_values[i].valueHistory.length > VALUE_HISTORY_SIZE) {
|
||||
var lostValue = _values[i].valueHistory.shift();
|
||||
if (lostValue >= _values[i].valueMax) {
|
||||
_values[i].valueMax *= 0.99
|
||||
_values[i].numSamplesConstantMax = 0
|
||||
}
|
||||
}
|
||||
|
||||
if (_values[i].valueMax < currentVal) {
|
||||
_values[i].valueMax = currentVal;
|
||||
_values[i].numSamplesConstantMax = 0
|
||||
}
|
||||
|
||||
if (_values[i].numSamplesConstantMax > VALUE_HISTORY_SIZE) {
|
||||
_values[i].numSamplesConstantMax = 0
|
||||
_values[i].valueMax *= 0.95 // lower slowly the current max if no new above max since a while
|
||||
}
|
||||
|
||||
if (currentValueMax < _values[i].valueMax) {
|
||||
currentValueMax = _values[i].valueMax
|
||||
}
|
||||
}
|
||||
|
||||
if ((valueMax < currentValueMax) || (tick % VALUE_HISTORY_SIZE == 0)) {
|
||||
valueMax = currentValueMax;
|
||||
}
|
||||
|
||||
if (tick % UPDATE_CANVAS_RATE == 0) {
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
}
|
||||
onTriggerChanged: pullFreshValues()
|
||||
|
||||
Canvas {
|
||||
id: mycanvas
|
||||
anchors.fill:parent
|
||||
onPaint: {
|
||||
var lineHeight = 12;
|
||||
|
||||
function displayValue(val, unit) {
|
||||
return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + unit
|
||||
}
|
||||
|
||||
function pixelFromVal(val, valScale) {
|
||||
return lineHeight + (height - lineHeight) * (1 - (0.9) * val / valueMax);
|
||||
}
|
||||
function valueFromPixel(pixY) {
|
||||
return ((pixY - lineHeight) / (height - lineHeight) - 1) * valueMax / (-0.9);
|
||||
}
|
||||
function plotValueHistory(ctx, valHistory, color) {
|
||||
var widthStep= width / (valHistory.length - 1);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle= color; // Green path
|
||||
ctx.lineWidth="2";
|
||||
ctx.moveTo(0, pixelFromVal(valHistory[0]));
|
||||
|
||||
for (var i = 1; i < valHistory.length; i++) {
|
||||
ctx.lineTo(i * widthStep, pixelFromVal(valHistory[i]));
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
function displayValueLegend(ctx, val, num) {
|
||||
ctx.fillStyle = val.color;
|
||||
var bestValue = val.valueHistory[val.valueHistory.length -1];
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5);
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5);
|
||||
}
|
||||
|
||||
function displayTitle(ctx, text, maxVal) {
|
||||
ctx.fillStyle = "grey";
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText(displayValue(valueFromPixel(lineHeight), root.valueUnit), width, lineHeight);
|
||||
|
||||
ctx.fillStyle = "white";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(text, 0, lineHeight);
|
||||
}
|
||||
function displayBackground(ctx) {
|
||||
ctx.fillStyle = Qt.rgba(0, 0, 0, 0.6);
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
ctx.strokeStyle= "grey";
|
||||
ctx.lineWidth="2";
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, lineHeight + 1);
|
||||
ctx.lineTo(width, lineHeight + 1);
|
||||
ctx.moveTo(0, height);
|
||||
ctx.lineTo(width, height);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
var ctx = getContext("2d");
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.font="12px Verdana";
|
||||
|
||||
displayBackground(ctx);
|
||||
|
||||
for (var i = 0; i < _values.length; i++) {
|
||||
plotValueHistory(ctx, _values[i].valueHistory, _values[i].color)
|
||||
displayValueLegend(ctx, _values[i], i)
|
||||
}
|
||||
|
||||
displayTitle(ctx, title, valueMax)
|
||||
}
|
||||
}
|
||||
}
|
21
examples/utilities/tools/render/renderStats.js
Normal file
21
examples/utilities/tools/render/renderStats.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// renderStats.js
|
||||
// examples/utilities/tools/render
|
||||
//
|
||||
// Sam Gateau, created on 3/22/2016.
|
||||
// Copyright 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
|
||||
//
|
||||
|
||||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('stats.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Render Stats',
|
||||
source: qml,
|
||||
width: 300,
|
||||
height: 200
|
||||
});
|
||||
window.setPosition(500, 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
69
examples/utilities/tools/render/stats.qml
Normal file
69
examples/utilities/tools/render/stats.qml
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// stats.qml
|
||||
// examples/utilities/tools/render
|
||||
//
|
||||
// Created by Zach Pomerantz on 2/8/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
|
||||
Item {
|
||||
id: statsUI
|
||||
anchors.fill:parent
|
||||
|
||||
Column {
|
||||
id: stats
|
||||
spacing: 8
|
||||
anchors.fill:parent
|
||||
|
||||
property var config: Render.getConfig("Stats")
|
||||
|
||||
function evalEvenHeight() {
|
||||
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
|
||||
return (height - spacing * (children.length - 1)) / children.length
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Num Buffers"
|
||||
config: stats.config
|
||||
height: parent.evalEvenHeight()
|
||||
parameters: "1::0:bufferCPUCount-CPU-#00B4EF:bufferGPUCount-GPU-#1AC567"
|
||||
}
|
||||
PlotPerf {
|
||||
title: "gpu::Buffer Memory"
|
||||
config: stats.config
|
||||
height: parent.evalEvenHeight()
|
||||
parameters: "1048576:Mb:1:bufferCPUMemoryUsage-CPU-#00B4EF:bufferGPUMemoryUsage-GPU-#1AC567"
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Num Textures"
|
||||
config: stats.config
|
||||
height: parent.evalEvenHeight()
|
||||
parameters: "1::0:textureCPUCount-CPU-#00B4EF:textureGPUCount-GPU-#1AC567:frameTextureCount-Frame-#E2334D"
|
||||
}
|
||||
PlotPerf {
|
||||
title: "gpu::Texture Memory"
|
||||
config: stats.config
|
||||
height: parent.evalEvenHeight()
|
||||
parameters: "1048576:Mb:1:textureCPUMemoryUsage-CPU-#00B4EF:textureGPUMemoryUsage-GPU-#1AC567"
|
||||
}
|
||||
PlotPerf {
|
||||
title: "Drawcalls"
|
||||
config: stats.config
|
||||
height: parent.evalEvenHeight()
|
||||
parameters: "1::0:frameDrawcallCount-frame-#E2334D:frameDrawcallRate-rate-#1AC567-0.001-K/s"
|
||||
}
|
||||
PlotPerf {
|
||||
title: "Triangles"
|
||||
config: stats.config
|
||||
height: parent.evalEvenHeight()
|
||||
parameters: "1000:K:0:frameTriangleCount-frame-#E2334D:frameTriangleRate-rate-#1AC567-0.001-MT/s"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,6 +74,11 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons
|
|||
_backend->downloadFramebuffer(srcFramebuffer, region, destImage);
|
||||
}
|
||||
|
||||
|
||||
void Context::getStats(ContextStats& stats) const {
|
||||
_backend->getStats(stats);
|
||||
}
|
||||
|
||||
const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const {
|
||||
_projectionInverse = glm::inverse(_projection);
|
||||
|
||||
|
@ -102,3 +107,68 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Counters for Buffer and Texture usage in GPU/Context
|
||||
std::atomic<uint32_t> Context::_bufferGPUCount{ 0 };
|
||||
std::atomic<Buffer::Size> Context::_bufferGPUMemoryUsage{ 0 };
|
||||
|
||||
std::atomic<uint32_t> Context::_textureGPUCount{ 0 };
|
||||
std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 };
|
||||
|
||||
void Context::incrementBufferGPUCount() {
|
||||
_bufferGPUCount++;
|
||||
}
|
||||
void Context::decrementBufferGPUCount() {
|
||||
_bufferGPUCount--;
|
||||
}
|
||||
void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||
if (prevObjectSize == newObjectSize) {
|
||||
return;
|
||||
}
|
||||
if (newObjectSize > prevObjectSize) {
|
||||
_bufferGPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize);
|
||||
} else {
|
||||
_bufferGPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::incrementTextureGPUCount() {
|
||||
_textureGPUCount++;
|
||||
}
|
||||
void Context::decrementTextureGPUCount() {
|
||||
_textureGPUCount--;
|
||||
}
|
||||
void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||
if (prevObjectSize == newObjectSize) {
|
||||
return;
|
||||
}
|
||||
if (newObjectSize > prevObjectSize) {
|
||||
_textureGPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize);
|
||||
} else {
|
||||
_textureGPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Context::getBufferGPUCount() {
|
||||
return _bufferGPUCount.load();
|
||||
}
|
||||
|
||||
Context::Size Context::getBufferGPUMemoryUsage() {
|
||||
return _bufferGPUMemoryUsage.load();
|
||||
}
|
||||
|
||||
uint32_t Context::getTextureGPUCount() {
|
||||
return _textureGPUCount.load();
|
||||
}
|
||||
|
||||
Context::Size Context::getTextureGPUMemoryUsage() {
|
||||
return _textureGPUMemoryUsage.load();
|
||||
}
|
||||
|
||||
void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); }
|
||||
void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); }
|
||||
void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
||||
void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount(); }
|
||||
void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); }
|
||||
void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
||||
|
||||
|
|
|
@ -27,6 +27,21 @@ class QImage;
|
|||
|
||||
namespace gpu {
|
||||
|
||||
struct ContextStats {
|
||||
public:
|
||||
int _ISNumFormatChanges = 0;
|
||||
int _ISNumInputBufferChanges = 0;
|
||||
int _ISNumIndexBufferChanges = 0;
|
||||
|
||||
int _RSNumTextureBounded = 0;
|
||||
|
||||
int _DSNumDrawcalls = 0;
|
||||
int _DSNumTriangles = 0;
|
||||
|
||||
ContextStats() {}
|
||||
ContextStats(const ContextStats& stats) = default;
|
||||
};
|
||||
|
||||
struct StereoState {
|
||||
bool _enable{ false };
|
||||
bool _skybox{ false };
|
||||
|
@ -100,13 +115,27 @@ public:
|
|||
return reinterpret_cast<T*>(object.gpuObject.getGPUObject());
|
||||
}
|
||||
|
||||
void getStats(ContextStats& stats) const { stats = _stats; }
|
||||
|
||||
|
||||
|
||||
// These should only be accessed by Backend implementation to repport the buffer and texture allocations,
|
||||
// they are NOT public calls
|
||||
static void incrementBufferGPUCount();
|
||||
static void decrementBufferGPUCount();
|
||||
static void updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
||||
static void incrementTextureGPUCount();
|
||||
static void decrementTextureGPUCount();
|
||||
static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
||||
|
||||
protected:
|
||||
StereoState _stereo;
|
||||
ContextStats _stats;
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
using Size = Resource::Size;
|
||||
typedef Backend* (*CreateBackend)();
|
||||
typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings);
|
||||
|
||||
|
@ -125,6 +154,7 @@ public:
|
|||
~Context();
|
||||
|
||||
void render(Batch& batch);
|
||||
|
||||
void enableStereo(bool enable = true);
|
||||
bool isStereo();
|
||||
void setStereoProjections(const mat4 eyeProjections[2]);
|
||||
|
@ -137,6 +167,16 @@ public:
|
|||
// It s here for convenience to easily capture a snapshot
|
||||
void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage);
|
||||
|
||||
// Repporting stats of the context
|
||||
void getStats(ContextStats& stats) const;
|
||||
|
||||
|
||||
static uint32_t getBufferGPUCount();
|
||||
static Size getBufferGPUMemoryUsage();
|
||||
|
||||
static uint32_t getTextureGPUCount();
|
||||
static Size getTextureGPUMemoryUsage();
|
||||
|
||||
protected:
|
||||
Context(const Context& context);
|
||||
|
||||
|
@ -153,6 +193,23 @@ protected:
|
|||
static std::once_flag _initialized;
|
||||
|
||||
friend class Shader;
|
||||
|
||||
// These should only be accessed by the Backend, they are NOT public calls
|
||||
static void incrementBufferGPUCount();
|
||||
static void decrementBufferGPUCount();
|
||||
static void updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||
static void incrementTextureGPUCount();
|
||||
static void decrementTextureGPUCount();
|
||||
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||
|
||||
// Buffer and Texture Counters
|
||||
static std::atomic<uint32_t> _bufferGPUCount;
|
||||
static std::atomic<Size> _bufferGPUMemoryUsage;
|
||||
|
||||
static std::atomic<uint32_t> _textureGPUCount;
|
||||
static std::atomic<Size> _textureGPUMemoryUsage;
|
||||
|
||||
friend class Backend;
|
||||
};
|
||||
typedef std::shared_ptr<Context> ContextPointer;
|
||||
|
||||
|
|
|
@ -324,7 +324,10 @@ void GLBackend::do_draw(Batch& batch, size_t paramOffset) {
|
|||
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
||||
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
||||
glDrawArrays(mode, startVertex, numVertices);
|
||||
(void) CHECK_GL_ERROR();
|
||||
_stats._DSNumTriangles += numVertices / 3;
|
||||
_stats._DSNumDrawcalls++;
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) {
|
||||
|
@ -339,6 +342,9 @@ void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) {
|
|||
GLvoid* indexBufferByteOffset = reinterpret_cast<GLvoid*>(startIndex * typeByteSize + _input._indexBufferOffset);
|
||||
|
||||
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
|
||||
_stats._DSNumTriangles += numIndices / 3;
|
||||
_stats._DSNumDrawcalls++;
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
@ -350,6 +356,9 @@ void GLBackend::do_drawInstanced(Batch& batch, size_t paramOffset) {
|
|||
uint32 startVertex = batch._params[paramOffset + 1]._uint;
|
||||
|
||||
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
|
||||
_stats._DSNumTriangles += (numInstances * numVertices) / 3;
|
||||
_stats._DSNumDrawcalls += numInstances;
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
@ -372,6 +381,9 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
|
|||
glDrawElementsInstanced(mode, numIndices, glType, indexBufferByteOffset, numInstances);
|
||||
Q_UNUSED(startInstance);
|
||||
#endif
|
||||
_stats._DSNumTriangles += (numInstances * numIndices) / 3;
|
||||
_stats._DSNumDrawcalls += numInstances;
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
@ -382,6 +394,7 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) {
|
|||
GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
|
||||
glMultiDrawArraysIndirect(mode, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
|
||||
_stats._DSNumDrawcalls += commandCount;
|
||||
#else
|
||||
// FIXME implement the slow path
|
||||
#endif
|
||||
|
@ -396,6 +409,8 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) {
|
|||
GLenum indexType = _elementTypeToGLType[_input._indexBufferType];
|
||||
|
||||
glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
|
||||
_stats._DSNumDrawcalls += commandCount;
|
||||
|
||||
#else
|
||||
// FIXME implement the slow path
|
||||
#endif
|
||||
|
|
|
@ -67,6 +67,8 @@ public:
|
|||
|
||||
GLBuffer();
|
||||
~GLBuffer();
|
||||
|
||||
void setSize(GLuint size);
|
||||
};
|
||||
static GLBuffer* syncGPUObject(const Buffer& buffer);
|
||||
static GLuint getBufferID(const Buffer& buffer);
|
||||
|
@ -77,10 +79,15 @@ public:
|
|||
Stamp _contentStamp;
|
||||
GLuint _texture;
|
||||
GLenum _target;
|
||||
GLuint _size;
|
||||
|
||||
GLTexture();
|
||||
~GLTexture();
|
||||
|
||||
void setSize(GLuint size);
|
||||
GLuint size() const { return _size; }
|
||||
|
||||
private:
|
||||
GLuint _size;
|
||||
};
|
||||
static GLTexture* syncGPUObject(const Texture& texture);
|
||||
static GLuint getTextureID(const TexturePointer& texture, bool sync = true);
|
||||
|
@ -230,26 +237,11 @@ public:
|
|||
void do_setStateBlend(State::BlendFunction blendFunction);
|
||||
|
||||
void do_setStateColorWriteMask(uint32 mask);
|
||||
|
||||
// Repporting stats of the context
|
||||
class Stats {
|
||||
public:
|
||||
int _ISNumFormatChanges = 0;
|
||||
int _ISNumInputBufferChanges = 0;
|
||||
int _ISNumIndexBufferChanges = 0;
|
||||
|
||||
Stats() {}
|
||||
Stats(const Stats& stats) = default;
|
||||
};
|
||||
|
||||
void getStats(Stats& stats) const { stats = _stats; }
|
||||
|
||||
|
||||
protected:
|
||||
void renderPassTransfer(Batch& batch);
|
||||
void renderPassDraw(Batch& batch);
|
||||
|
||||
Stats _stats;
|
||||
|
||||
// Draw Stage
|
||||
void do_draw(Batch& batch, size_t paramOffset);
|
||||
void do_drawIndexed(Batch& batch, size_t paramOffset);
|
||||
|
|
|
@ -16,12 +16,21 @@ GLBackend::GLBuffer::GLBuffer() :
|
|||
_stamp(0),
|
||||
_buffer(0),
|
||||
_size(0)
|
||||
{}
|
||||
{
|
||||
Backend::incrementBufferGPUCount();
|
||||
}
|
||||
|
||||
GLBackend::GLBuffer::~GLBuffer() {
|
||||
if (_buffer != 0) {
|
||||
glDeleteBuffers(1, &_buffer);
|
||||
}
|
||||
Backend::updateBufferGPUMemoryUsage(_size, 0);
|
||||
Backend::decrementBufferGPUCount();
|
||||
}
|
||||
|
||||
void GLBackend::GLBuffer::setSize(GLuint size) {
|
||||
Backend::updateBufferGPUMemoryUsage(_size, size);
|
||||
_size = size;
|
||||
}
|
||||
|
||||
GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) {
|
||||
|
@ -46,7 +55,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) {
|
|||
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
object->_stamp = buffer.getSysmem().getStamp();
|
||||
object->_size = (GLuint)buffer.getSysmem().getSize();
|
||||
object->setSize((GLuint)buffer.getSysmem().getSize());
|
||||
//}
|
||||
(void) CHECK_GL_ERROR();
|
||||
|
||||
|
|
|
@ -251,6 +251,9 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
|
||||
// One more True texture bound
|
||||
_stats._RSNumTextureBounded++;
|
||||
|
||||
// Always make sure the GLObject is in sync
|
||||
GLTexture* object = GLBackend::syncGPUObject(*resourceTexture);
|
||||
if (object) {
|
||||
|
|
|
@ -19,12 +19,21 @@ GLBackend::GLTexture::GLTexture() :
|
|||
_texture(0),
|
||||
_target(GL_TEXTURE_2D),
|
||||
_size(0)
|
||||
{}
|
||||
{
|
||||
Backend::incrementTextureGPUCount();
|
||||
}
|
||||
|
||||
GLBackend::GLTexture::~GLTexture() {
|
||||
if (_texture != 0) {
|
||||
glDeleteTextures(1, &_texture);
|
||||
}
|
||||
Backend::updateTextureGPUMemoryUsage(_size, 0);
|
||||
Backend::decrementTextureGPUCount();
|
||||
}
|
||||
|
||||
void GLBackend::GLTexture::setSize(GLuint size) {
|
||||
Backend::updateTextureGPUMemoryUsage(_size, size);
|
||||
_size = size;
|
||||
}
|
||||
|
||||
class GLTexelFormat {
|
||||
|
@ -427,8 +436,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
if (needUpdate) {
|
||||
if (texture.isStoredMipFaceAvailable(0)) {
|
||||
Texture::PixelsPointer mip = texture.accessStoredMipFace(0);
|
||||
const GLvoid* bytes = mip->_sysmem.read<Byte>();
|
||||
Element srcFormat = mip->_format;
|
||||
const GLvoid* bytes = mip->readData();
|
||||
Element srcFormat = mip->getFormat();
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
|
@ -458,8 +467,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
if (texture.isStoredMipFaceAvailable(0)) {
|
||||
Texture::PixelsPointer mip = texture.accessStoredMipFace(0);
|
||||
|
||||
bytes = mip->_sysmem.read<Byte>();
|
||||
srcFormat = mip->_format;
|
||||
bytes = mip->readData();
|
||||
srcFormat = mip->getFormat();
|
||||
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
}
|
||||
|
@ -483,7 +492,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
|
||||
object->_storageStamp = texture.getStamp();
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
object->_size = (GLuint)texture.getSize();
|
||||
object->setSize((GLuint)texture.getSize());
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, boundTex);
|
||||
|
@ -507,11 +516,11 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
for (int f = 0; f < NUM_FACES; f++) {
|
||||
if (texture.isStoredMipFaceAvailable(0, f)) {
|
||||
Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f);
|
||||
Element srcFormat = mipFace->_format;
|
||||
Element srcFormat = mipFace->getFormat();
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0,
|
||||
texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->_sysmem.read<Byte>()));
|
||||
texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData()));
|
||||
|
||||
// At this point the mip pixels have been loaded, we can notify
|
||||
texture.notifyMipFaceGPULoaded(0, f);
|
||||
|
@ -536,11 +545,11 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
for (int f = 0; f < NUM_FACES; f++) {
|
||||
if (texture.isStoredMipFaceAvailable(0, f)) {
|
||||
Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f);
|
||||
Element srcFormat = mipFace->_format;
|
||||
Element srcFormat = mipFace->getFormat();
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0,
|
||||
texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->_sysmem.read<Byte>()));
|
||||
texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData()));
|
||||
|
||||
// At this point the mip pixels have been loaded, we can notify
|
||||
texture.notifyMipFaceGPULoaded(0, f);
|
||||
|
@ -561,7 +570,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
|
||||
object->_storageStamp = texture.getStamp();
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
object->_size = (GLuint)texture.getSize();
|
||||
object->setSize((GLuint)texture.getSize());
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, boundTex);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Context.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
class AllocationDebugger {
|
||||
|
@ -232,19 +234,55 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::atomic<uint32_t> Buffer::_bufferCPUCount{ 0 };
|
||||
std::atomic<Buffer::Size> Buffer::_bufferCPUMemoryUsage{ 0 };
|
||||
|
||||
void Buffer::updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||
if (prevObjectSize == newObjectSize) {
|
||||
return;
|
||||
}
|
||||
if (prevObjectSize > newObjectSize) {
|
||||
_bufferCPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize);
|
||||
} else {
|
||||
_bufferCPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Buffer::getBufferCPUCount() {
|
||||
return _bufferCPUCount.load();
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::getBufferCPUMemoryUsage() {
|
||||
return _bufferCPUMemoryUsage.load();
|
||||
}
|
||||
|
||||
uint32_t Buffer::getBufferGPUCount() {
|
||||
return Context::getBufferGPUCount();
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::getBufferGPUMemoryUsage() {
|
||||
return Context::getBufferGPUMemoryUsage();
|
||||
}
|
||||
|
||||
Buffer::Buffer() :
|
||||
Resource(),
|
||||
_sysmem(new Sysmem()) {
|
||||
_bufferCPUCount++;
|
||||
|
||||
}
|
||||
|
||||
Buffer::Buffer(Size size, const Byte* bytes) :
|
||||
Resource(),
|
||||
_sysmem(new Sysmem(size, bytes)) {
|
||||
_bufferCPUCount++;
|
||||
Buffer::updateBufferCPUMemoryUsage(0, _sysmem->getSize());
|
||||
}
|
||||
|
||||
Buffer::Buffer(const Buffer& buf) :
|
||||
Resource(),
|
||||
_sysmem(new Sysmem(buf.getSysmem())) {
|
||||
_bufferCPUCount++;
|
||||
Buffer::updateBufferCPUMemoryUsage(0, _sysmem->getSize());
|
||||
}
|
||||
|
||||
Buffer& Buffer::operator=(const Buffer& buf) {
|
||||
|
@ -253,18 +291,27 @@ Buffer& Buffer::operator=(const Buffer& buf) {
|
|||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
_bufferCPUCount--;
|
||||
|
||||
if (_sysmem) {
|
||||
Buffer::updateBufferCPUMemoryUsage(_sysmem->getSize(), 0);
|
||||
delete _sysmem;
|
||||
_sysmem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::resize(Size size) {
|
||||
return editSysmem().resize(size);
|
||||
auto prevSize = editSysmem().getSize();
|
||||
auto newSize = editSysmem().resize(size);
|
||||
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize);
|
||||
return newSize;
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::setData(Size size, const Byte* data) {
|
||||
return editSysmem().setData(size, data);
|
||||
auto prevSize = editSysmem().getSize();
|
||||
auto newSize = editSysmem().setData(size, data);
|
||||
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize);
|
||||
return newSize;
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) {
|
||||
|
@ -272,6 +319,9 @@ Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) {
|
|||
}
|
||||
|
||||
Buffer::Size Buffer::append(Size size, const Byte* data) {
|
||||
return editSysmem().append( size, data);
|
||||
auto prevSize = editSysmem().getSize();
|
||||
auto newSize = editSysmem().append( size, data);
|
||||
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize);
|
||||
return newSize;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "Format.h"
|
||||
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
#include <memory>
|
||||
#ifdef _DEBUG
|
||||
|
@ -109,7 +110,15 @@ protected:
|
|||
};
|
||||
|
||||
class Buffer : public Resource {
|
||||
static std::atomic<uint32_t> _bufferCPUCount;
|
||||
static std::atomic<Size> _bufferCPUMemoryUsage;
|
||||
static void updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||
|
||||
public:
|
||||
static uint32_t getBufferCPUCount();
|
||||
static Size getBufferCPUMemoryUsage();
|
||||
static uint32_t getBufferGPUCount();
|
||||
static Size getBufferGPUMemoryUsage();
|
||||
|
||||
Buffer();
|
||||
Buffer(Size size, const Byte* bytes);
|
||||
|
|
|
@ -12,20 +12,77 @@
|
|||
#include "Texture.h"
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
#include <QDebug>
|
||||
#include "GPULogging.h"
|
||||
#include "Context.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
|
||||
std::atomic<uint32_t> Texture::_textureCPUCount{ 0 };
|
||||
std::atomic<Texture::Size> Texture::_textureCPUMemoryUsage{ 0 };
|
||||
|
||||
void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||
if (prevObjectSize == newObjectSize) {
|
||||
return;
|
||||
}
|
||||
if (prevObjectSize > newObjectSize) {
|
||||
_textureCPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize);
|
||||
} else {
|
||||
_textureCPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Texture::getTextureCPUCount() {
|
||||
return _textureCPUCount.load();
|
||||
}
|
||||
|
||||
Texture::Size Texture::getTextureCPUMemoryUsage() {
|
||||
return _textureCPUMemoryUsage.load();
|
||||
}
|
||||
|
||||
uint32_t Texture::getTextureGPUCount() {
|
||||
return Context::getTextureGPUCount();
|
||||
}
|
||||
|
||||
Texture::Size Texture::getTextureGPUMemoryUsage() {
|
||||
return Context::getTextureGPUMemoryUsage();
|
||||
|
||||
}
|
||||
|
||||
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6};
|
||||
|
||||
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
|
||||
_sysmem(size, bytes),
|
||||
_format(format),
|
||||
_sysmem(size, bytes),
|
||||
_isGPULoaded(false) {
|
||||
Texture::updateTextureCPUMemoryUsage(0, _sysmem.getSize());
|
||||
}
|
||||
|
||||
Texture::Pixels::~Pixels() {
|
||||
Texture::updateTextureCPUMemoryUsage(_sysmem.getSize(), 0);
|
||||
}
|
||||
|
||||
Texture::Size Texture::Pixels::resize(Size pSize) {
|
||||
auto prevSize = _sysmem.getSize();
|
||||
auto newSize = _sysmem.resize(pSize);
|
||||
Texture::updateTextureCPUMemoryUsage(prevSize, newSize);
|
||||
return newSize;
|
||||
}
|
||||
|
||||
Texture::Size Texture::Pixels::setData(const Element& format, Size size, const Byte* bytes ) {
|
||||
_format = format;
|
||||
auto prevSize = _sysmem.getSize();
|
||||
auto newSize = _sysmem.setData(size, bytes);
|
||||
Texture::updateTextureCPUMemoryUsage(prevSize, newSize);
|
||||
_isGPULoaded = false;
|
||||
return newSize;
|
||||
}
|
||||
|
||||
void Texture::Pixels::notifyGPULoaded() {
|
||||
_isGPULoaded = true;
|
||||
auto prevSize = _sysmem.getSize();
|
||||
auto newSize = _sysmem.resize(0);
|
||||
Texture::updateTextureCPUMemoryUsage(prevSize, newSize);
|
||||
}
|
||||
|
||||
void Texture::Storage::assignTexture(Texture* texture) {
|
||||
|
@ -59,15 +116,15 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa
|
|||
|
||||
void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const {
|
||||
PixelsPointer mipFace = getMipFace(level, face);
|
||||
if (mipFace && (_type != TEX_CUBE)) {
|
||||
mipFace->_isGPULoaded = true;
|
||||
mipFace->_sysmem.resize(0);
|
||||
// Free the mips
|
||||
if (mipFace) {
|
||||
mipFace->notifyGPULoaded();
|
||||
}
|
||||
}
|
||||
|
||||
bool Texture::Storage::isMipAvailable(uint16 level, uint8 face) const {
|
||||
PixelsPointer mipFace = getMipFace(level, face);
|
||||
return (mipFace && mipFace->_sysmem.getSize());
|
||||
return (mipFace && mipFace->getSize());
|
||||
}
|
||||
|
||||
bool Texture::Storage::allocateMip(uint16 level) {
|
||||
|
@ -103,9 +160,7 @@ bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size s
|
|||
auto faceBytes = bytes;
|
||||
Size allocated = 0;
|
||||
for (auto& face : mip) {
|
||||
face->_format = format;
|
||||
allocated += face->_sysmem.setData(sizePerFace, faceBytes);
|
||||
face->_isGPULoaded = false;
|
||||
allocated += face->setData(format, sizePerFace, faceBytes);
|
||||
faceBytes += sizePerFace;
|
||||
}
|
||||
|
||||
|
@ -122,9 +177,7 @@ bool Texture::Storage::assignMipFaceData(uint16 level, const Element& format, Si
|
|||
Size allocated = 0;
|
||||
if (face < mip.size()) {
|
||||
auto mipFace = mip[face];
|
||||
mipFace->_format = format;
|
||||
allocated += mipFace->_sysmem.setData(size, bytes);
|
||||
mipFace->_isGPULoaded = false;
|
||||
allocated += mipFace->setData(format, size, bytes);
|
||||
bumpStamp();
|
||||
}
|
||||
|
||||
|
@ -171,10 +224,12 @@ Texture* Texture::createFromStorage(Storage* storage) {
|
|||
Texture::Texture():
|
||||
Resource()
|
||||
{
|
||||
_textureCPUCount++;
|
||||
}
|
||||
|
||||
Texture::~Texture()
|
||||
{
|
||||
_textureCPUCount--;
|
||||
}
|
||||
|
||||
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) {
|
||||
|
@ -292,7 +347,7 @@ bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, co
|
|||
}
|
||||
}
|
||||
|
||||
// THen check that the mem buffer passed make sense with its format
|
||||
// THen check that the mem texture passed make sense with its format
|
||||
Size expectedSize = evalStoredMipSize(level, format);
|
||||
if (size == expectedSize) {
|
||||
_storage->assignMipData(level, format, size, bytes);
|
||||
|
@ -323,7 +378,7 @@ bool Texture::assignStoredMipFace(uint16 level, const Element& format, Size size
|
|||
}
|
||||
}
|
||||
|
||||
// THen check that the mem buffer passed make sense with its format
|
||||
// THen check that the mem texture passed make sense with its format
|
||||
Size expectedSize = evalStoredMipFaceSize(level, format);
|
||||
if (size == expectedSize) {
|
||||
_storage->assignMipFaceData(level, format, size, bytes, face);
|
||||
|
@ -364,7 +419,7 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) {
|
|||
|
||||
uint16 Texture::getStoredMipWidth(uint16 level) const {
|
||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||
if (mipFace && mipFace->_sysmem.getSize()) {
|
||||
if (mipFace && mipFace->getSize()) {
|
||||
return evalMipWidth(level);
|
||||
}
|
||||
return 0;
|
||||
|
@ -372,7 +427,7 @@ uint16 Texture::getStoredMipWidth(uint16 level) const {
|
|||
|
||||
uint16 Texture::getStoredMipHeight(uint16 level) const {
|
||||
PixelsPointer mip = accessStoredMipFace(level);
|
||||
if (mip && mip->_sysmem.getSize()) {
|
||||
if (mip && mip->getSize()) {
|
||||
return evalMipHeight(level);
|
||||
}
|
||||
return 0;
|
||||
|
@ -380,7 +435,7 @@ uint16 Texture::getStoredMipHeight(uint16 level) const {
|
|||
|
||||
uint16 Texture::getStoredMipDepth(uint16 level) const {
|
||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||
if (mipFace && mipFace->_sysmem.getSize()) {
|
||||
if (mipFace && mipFace->getSize()) {
|
||||
return evalMipDepth(level);
|
||||
}
|
||||
return 0;
|
||||
|
@ -388,7 +443,7 @@ uint16 Texture::getStoredMipDepth(uint16 level) const {
|
|||
|
||||
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||
if (mipFace && mipFace->_sysmem.getSize()) {
|
||||
if (mipFace && mipFace->getSize()) {
|
||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
|
||||
}
|
||||
return 0;
|
||||
|
@ -396,7 +451,7 @@ uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
|||
|
||||
uint32 Texture::getStoredMipSize(uint16 level) const {
|
||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||
if (mipFace && mipFace->_sysmem.getSize()) {
|
||||
if (mipFace && mipFace->getSize()) {
|
||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
|
||||
}
|
||||
return 0;
|
||||
|
@ -642,8 +697,8 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
// for each face of cube texture
|
||||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
|
||||
auto numComponents = cubeTexture.accessStoredMipFace(0,face)->_format.getScalarCount();
|
||||
auto data = cubeTexture.accessStoredMipFace(0,face)->_sysmem.readData();
|
||||
auto numComponents = cubeTexture.accessStoredMipFace(0,face)->getFormat().getScalarCount();
|
||||
auto data = cubeTexture.accessStoredMipFace(0,face)->readData();
|
||||
if (data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -138,7 +138,14 @@ protected:
|
|||
};
|
||||
|
||||
class Texture : public Resource {
|
||||
static std::atomic<uint32_t> _textureCPUCount;
|
||||
static std::atomic<Size> _textureCPUMemoryUsage;
|
||||
static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||
public:
|
||||
static uint32_t getTextureCPUCount();
|
||||
static Size getTextureCPUMemoryUsage();
|
||||
static uint32_t getTextureGPUCount();
|
||||
static Size getTextureGPUMemoryUsage();
|
||||
|
||||
class Usage {
|
||||
public:
|
||||
|
@ -194,9 +201,21 @@ public:
|
|||
Pixels(const Element& format, Size size, const Byte* bytes);
|
||||
~Pixels();
|
||||
|
||||
Sysmem _sysmem;
|
||||
const Byte* readData() const { return _sysmem.readData(); }
|
||||
Size getSize() const { return _sysmem.getSize(); }
|
||||
Size resize(Size pSize);
|
||||
Size setData(const Element& format, Size size, const Byte* bytes );
|
||||
|
||||
const Element& getFormat() const { return _format; }
|
||||
|
||||
void notifyGPULoaded();
|
||||
|
||||
protected:
|
||||
Element _format;
|
||||
Sysmem _sysmem;
|
||||
bool _isGPULoaded;
|
||||
|
||||
friend class Texture;
|
||||
};
|
||||
typedef std::shared_ptr< Pixels > PixelsPointer;
|
||||
|
||||
|
@ -448,7 +467,7 @@ typedef std::shared_ptr<Texture> TexturePointer;
|
|||
typedef std::vector< TexturePointer > Textures;
|
||||
|
||||
|
||||
// TODO: For now TextureView works with Buffer as a place holder for the Texture.
|
||||
// TODO: For now TextureView works with Texture as a place holder for the Texture.
|
||||
// The overall logic should be about the same except that the Texture will be a real GL Texture under the hood
|
||||
class TextureView {
|
||||
public:
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "EngineStats.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
Engine::Engine() :
|
||||
_sceneContext(std::make_shared<SceneContext>()),
|
||||
_renderContext(std::make_shared<RenderContext>()) {
|
||||
addJob<EngineStats>("Stats");
|
||||
}
|
||||
|
||||
void Engine::load() {
|
||||
|
@ -57,4 +59,6 @@ void Engine::run() {
|
|||
for (auto job : _jobs) {
|
||||
job.run(_sceneContext, _renderContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -16,37 +16,37 @@
|
|||
|
||||
#include "Context.h"
|
||||
#include "Task.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
// The render engine holds all render tasks, and is itself a render task.
|
||||
// State flows through tasks to jobs via the render and scene contexts -
|
||||
// the engine should not be known from its jobs.
|
||||
class Engine : public Task {
|
||||
public:
|
||||
Engine();
|
||||
~Engine() = default;
|
||||
// The render engine holds all render tasks, and is itself a render task.
|
||||
// State flows through tasks to jobs via the render and scene contexts -
|
||||
// the engine should not be known from its jobs.
|
||||
class Engine : public Task {
|
||||
public:
|
||||
|
||||
// Load any persisted settings, and set up the presets
|
||||
// This should be run after adding all jobs, and before building ui
|
||||
void load();
|
||||
Engine();
|
||||
~Engine() = default;
|
||||
|
||||
// Register the scene
|
||||
void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; }
|
||||
// Load any persisted settings, and set up the presets
|
||||
// This should be run after adding all jobs, and before building ui
|
||||
void load();
|
||||
|
||||
// Push a RenderContext
|
||||
void setRenderContext(const RenderContext& renderContext) { (*_renderContext) = renderContext; }
|
||||
RenderContextPointer getRenderContext() const { return _renderContext; }
|
||||
// Register the scene
|
||||
void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; }
|
||||
|
||||
// Render a frame
|
||||
// A frame must have a scene registered and a context set to render
|
||||
void run();
|
||||
// Push a RenderContext
|
||||
void setRenderContext(const RenderContext& renderContext) { (*_renderContext) = renderContext; }
|
||||
RenderContextPointer getRenderContext() const { return _renderContext; }
|
||||
|
||||
protected:
|
||||
SceneContextPointer _sceneContext;
|
||||
RenderContextPointer _renderContext;
|
||||
};
|
||||
using EnginePointer = std::shared_ptr<Engine>;
|
||||
// Render a frame
|
||||
// A frame must have a scene registered and a context set to render
|
||||
void run();
|
||||
|
||||
protected:
|
||||
SceneContextPointer _sceneContext;
|
||||
RenderContextPointer _renderContext;
|
||||
};
|
||||
using EnginePointer = std::shared_ptr<Engine>;
|
||||
|
||||
}
|
||||
|
||||
|
|
49
libraries/render/src/render/EngineStats.cpp
Normal file
49
libraries/render/src/render/EngineStats.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// EngineStats.cpp
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Sam Gateau on 3/27/16.
|
||||
// Copyright 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 "EngineStats.h"
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
using namespace render;
|
||||
|
||||
void EngineStats::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
// Tick time
|
||||
|
||||
quint64 msecsElapsed = _frameTimer.restart();
|
||||
double frequency = 1000.0 / msecsElapsed;
|
||||
|
||||
// Update the stats
|
||||
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
|
||||
|
||||
config->bufferCPUCount = gpu::Buffer::getBufferCPUCount();
|
||||
config->bufferGPUCount = gpu::Buffer::getBufferGPUCount();
|
||||
config->bufferCPUMemoryUsage = gpu::Buffer::getBufferCPUMemoryUsage();
|
||||
config->bufferGPUMemoryUsage = gpu::Buffer::getBufferGPUMemoryUsage();
|
||||
|
||||
config->textureCPUCount = gpu::Texture::getTextureCPUCount();
|
||||
config->textureGPUCount = gpu::Texture::getTextureGPUCount();
|
||||
config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage();
|
||||
config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage();
|
||||
|
||||
gpu::ContextStats gpuStats(_gpuStats);
|
||||
renderContext->args->_context->getStats(_gpuStats);
|
||||
|
||||
config->frameDrawcallCount = _gpuStats._DSNumDrawcalls - gpuStats._DSNumDrawcalls;
|
||||
config->frameDrawcallRate = config->frameDrawcallCount * frequency;
|
||||
|
||||
config->frameTriangleCount = _gpuStats._DSNumTriangles - gpuStats._DSNumTriangles;
|
||||
config->frameTriangleRate = config->frameTriangleCount * frequency;
|
||||
|
||||
config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded;
|
||||
config->frameTextureRate = config->frameTextureCount * frequency;
|
||||
|
||||
config->emitDirty();
|
||||
}
|
89
libraries/render/src/render/EngineStats.h
Normal file
89
libraries/render/src/render/EngineStats.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
//
|
||||
// EngineStats.h
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Sam Gateau on 3/27/16.
|
||||
// Copyright 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_render_EngineStats_h
|
||||
#define hifi_render_EngineStats_h
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
// A simple job collecting global stats on the Engine / Scene / GPU
|
||||
class EngineStatsConfig : public Job::Config{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(quint32 bufferCPUCount MEMBER bufferCPUCount NOTIFY dirty)
|
||||
Q_PROPERTY(quint32 bufferGPUCount MEMBER bufferGPUCount NOTIFY dirty)
|
||||
Q_PROPERTY(qint64 bufferCPUMemoryUsage MEMBER bufferCPUMemoryUsage NOTIFY dirty)
|
||||
Q_PROPERTY(qint64 bufferGPUMemoryUsage MEMBER bufferGPUMemoryUsage NOTIFY dirty)
|
||||
|
||||
Q_PROPERTY(quint32 textureCPUCount MEMBER textureCPUCount NOTIFY dirty)
|
||||
Q_PROPERTY(quint32 textureGPUCount MEMBER textureGPUCount NOTIFY dirty)
|
||||
Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty)
|
||||
Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty)
|
||||
|
||||
Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty)
|
||||
Q_PROPERTY(quint32 frameDrawcallRate MEMBER frameDrawcallRate NOTIFY dirty)
|
||||
|
||||
Q_PROPERTY(quint32 frameTriangleCount MEMBER frameTriangleCount NOTIFY dirty)
|
||||
Q_PROPERTY(quint32 frameTriangleRate MEMBER frameTriangleRate NOTIFY dirty)
|
||||
|
||||
Q_PROPERTY(quint32 frameTextureCount MEMBER frameTextureCount NOTIFY dirty)
|
||||
Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty)
|
||||
|
||||
|
||||
public:
|
||||
EngineStatsConfig() : Job::Config(true) {}
|
||||
|
||||
quint32 bufferCPUCount{ 0 };
|
||||
quint32 bufferGPUCount{ 0 };
|
||||
qint64 bufferCPUMemoryUsage{ 0 };
|
||||
qint64 bufferGPUMemoryUsage{ 0 };
|
||||
|
||||
quint32 textureCPUCount{ 0 };
|
||||
quint32 textureGPUCount{ 0 };
|
||||
qint64 textureCPUMemoryUsage{ 0 };
|
||||
qint64 textureGPUMemoryUsage{ 0 };
|
||||
|
||||
quint32 frameDrawcallCount{ 0 };
|
||||
quint32 frameDrawcallRate{ 0 };
|
||||
|
||||
quint32 frameTriangleCount{ 0 };
|
||||
quint32 frameTriangleRate{ 0 };
|
||||
|
||||
quint32 frameTextureCount{ 0 };
|
||||
quint32 frameTextureRate{ 0 };
|
||||
|
||||
void emitDirty() { emit dirty(); }
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class EngineStats {
|
||||
gpu::ContextStats _gpuStats;
|
||||
QElapsedTimer _frameTimer;
|
||||
public:
|
||||
using Config = EngineStatsConfig;
|
||||
using JobModel = Job::Model<EngineStats, Config>;
|
||||
|
||||
EngineStats() { _frameTimer.start(); }
|
||||
|
||||
void configure(const Config& configuration) {}
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue