OpenGL debug extension with glObjectLabel - debugging

I just starting to use the debug extension in my project but the glObjectLabel generates an error when used with GL_BUFFER.
Graphic card is a nVidia Quadro 600 with 340.82 drivers
This simple test is built with MSVC 2010 in 32bit :
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
void GLAPIENTRY ogl_cb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
using namespace std;
cout << "message: "<< message << endl;
}
int main()
{
using namespace std;
if (!glfwInit())
{
cerr << "Error initializing GLFW" << endl;
return 1;
}
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
GLFWwindow *window = glfwCreateWindow(1, 1, "", NULL, NULL);
glfwMakeContextCurrent(window);
GLint glew_result = glewInit();
if (GLEW_OK != glew_result)
{
cerr << "Error initializing GLEW : " << (const char*)glewGetErrorString(glew_result) << endl;
return 2;
}
cout << "VENDOR : " << glGetString(GL_VENDOR) << endl;
cout << "RENDERER : " << glGetString(GL_RENDERER) << endl;
cout << "VERSION : " << glGetString(GL_VERSION) << endl;
cout << "GLSL VERSION : " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
glDebugMessageCallback(ogl_cb, NULL);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
GLuint progid = glCreateProgram();
glObjectLabel(GL_PROGRAM, progid, -1, "My program");
GLuint bufid;
glGenBuffers(1, &bufid);
glObjectLabel(GL_BUFFER, bufid, -1, "My buffer");
char prog_name[100];
GLsizei prog_name_len = 0;
glGetObjectLabel(GL_PROGRAM, progid, 100, &prog_name_len, prog_name);
cout << "Program name " << prog_name_len << " : " << (prog_name_len ? prog_name : "NULL") << endl;
char buf_name[100];
GLsizei buf_name_len = 0;
glGetObjectLabel(GL_BUFFER, bufid, 100, &buf_name_len, buf_name);
cout << "Buffer name " << buf_name_len << " : " << (buf_name_len ? buf_name : "NULL") << endl;
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
And the output on machine :
VENDOR : NVIDIA Corporation
RENDERER : Quadro 600/PCIe/SSE2
VERSION : 4.5.0 NVIDIA 340.82
GLSL VERSION : 4.50 NVIDIA
message: GL_INVALID_VALUE error generated. ObjectLabel: unknown buffer object <name>
Program name 10 : My program
message: GL_INVALID_VALUE error generated. GetObjectLabel: unknown buffer object <name>
Buffer name 0 : NULL
Everything is OK with the program, but not the buffer...
Looking at samples from www.g-truc.net, and other on the net, I just can't seem what I do wrong...
Any clue on what is going on here ?

Object you assign label to must already be created. glGenBuffers only reserves names, without creating anything. glCreateProgram, on the contrary, generates one new name and creates program object.
Binding buffer object at least once would be enough.

Related

Q: Boost Program Options using std::filesystem::path as option fails when the given path contains spaces

I have a windows command line program using Boost.Program_Options. One option uses a std::filesystem::path variable.
namespace fs = std::filesystem;
namespace po = boost::program_options;
fs::path optionsFile;
po::options_description desc( "Options" );
desc.add_options()
("help,h", "Help screen")
("options,o", po::value<fs::path>( &optionsFile ), "file with options");
calling the program with -o c:\temp\options.txt or with -o "c:\temp\options.txt" works fine, but calling the program with -o "c:\temp\options 1.txt" fails with this error:
error: the argument( 'c:\temp\options 1.txt' ) for option '--options' is invalid
The content of argv in this case is:
argv[0] = Exepath
argv[1] = -o
argv[2] = c:\temp\options 1.txt
This is the full code:
#include <boost/program_options.hpp>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
namespace po = boost::program_options;
int wmain( int argc, wchar_t * argv[] )
{
try
{
fs::path optionsFile;
po::options_description desc( "Options" );
desc.add_options()
("help,h", "Help screen")
("options,o", po::value<fs::path>( &optionsFile ), "File containing the command and the arguments");
po::wcommand_line_parser parser{ argc, argv };
parser.options( desc ).allow_unregistered().style(
po::command_line_style::default_style |
po::command_line_style::allow_slash_for_short );
po::wparsed_options parsed_options = parser.run();
po::variables_map vm;
store( parsed_options, vm );
notify( vm );
if( vm.count( "help" ) )
{
std::cout << desc << '\n';
return 0;
}
std::cout << "optionsFile = " << optionsFile << "\n";
}
catch( const std::exception & e )
{
std::cerr << "error: " << e.what() << "\n";
return 1;
}
return 0;
}
How can I handle paths containing whitespace correctly? Is that even possible using std::filesystem::path or do I have to use std::wstring?
Indeed I could reproduce this. Replacing fs::path with std::string fixed it.
Here's a side-by-side reproducer:
Live On Coliru
#include <boost/program_options.hpp>
#include <filesystem>
#include <iostream>
namespace po = boost::program_options;
template <typename Path> static constexpr auto Type = "[unknown]";
template <> constexpr auto Type<std::string> = "std::string";
template <> constexpr auto Type<std::filesystem::path> = "fs::path";
template <typename Path>
bool do_test(int argc, char const* argv[]) try {
Path optionsFile;
po::options_description desc("Options");
desc.add_options() //
("help,h", "Help screen") //
("options,o", po::value<Path>(&optionsFile),
"File containing the command and the arguments");
po::command_line_parser parser{argc, argv};
parser.options(desc).allow_unregistered().style(
po::command_line_style::default_style |
po::command_line_style::allow_slash_for_short);
auto parsed_options = parser.run();
po::variables_map vm;
store(parsed_options, vm);
notify(vm);
if (vm.count("help")) {
std::cout << desc << '\n';
return true;
}
std::cout << "Using " << Type<Path> << "\toptionsFile = " << optionsFile << "\n";
return true;
} catch (const std::exception& e) {
std::cout << "Using " << Type<Path> << "\terror: " << e.what() << "\n";
return false;
}
int main() {
for (auto args : {
std::vector{"Exepath", "-o", "c:\\temp\\options1.txt"},
std::vector{"Exepath", "-o", "c:\\temp\\options 1.txt"},
})
{
std::cout << "\n -- Input: ";
for (auto& arg : args) {
std::cout << " " << std::quoted(arg);
}
std::cout << "\n";
int argc = args.size();
args.push_back(nullptr);
do_test<std::string>(argc, args.data());
do_test<std::filesystem::path>(argc, args.data());
}
}
Prints
-- Input: "Exepath" "-o" "c:\\temp\\options1.txt"
Using std::string optionsFile = c:\temp\options1.txt
Using fs::path optionsFile = "c:\\temp\\options1.txt"
-- Input: "Exepath" "-o" "c:\\temp\\options 1.txt"
Using std::string optionsFile = c:\temp\options 1.txt
Using fs::path error: the argument ('c:\temp\options 1.txt') for option '--options' is invalid
The reason most likely is that extraction from the command line argument defaults to using operator>> on a stringstream¹. If that has skipws set (as all C++ istreams do by default), then whitespace stops the "parse" and the argument is rejected because it is not fully consumed.
However, modifying the code to include a validate overload that fires for paths, adding std::noskipws didn't help!
template <class CharT>
void validate(boost::any& v, std::vector<std::basic_string<CharT>> const& s,
std::filesystem::path* p, int)
{
assert(s.size() == 1);
std::basic_stringstream<CharT> ss;
for (auto& el : s)
ss << el;
path converted;
ss >> std::noskipws >> converted;
if (!ss.eof())
throw std::runtime_error("Invalid path format");
v = std::move(converted);
}
Apparently, operator>> for fs::path doesn't obey noskipws. A look at the docs confirms:
Performs stream input or output on the path p. std::quoted is used so that spaces do not cause truncation when later read by stream input operator.
This gives us the workaround:
Workaround
template <class CharT>
void validate(boost::any& v, std::vector<std::basic_string<CharT>> const& s,
std::filesystem::path* p, int)
{
assert(s.size() == 1);
std::basic_stringstream<CharT> ss;
for (auto& el : s)
ss << std::quoted(el);
path converted;
ss >> std::noskipws >> converted;
if (ss.peek(); !ss.eof())
throw std::runtime_error("excess path characters");
v = std::move(converted);
}
Here we balance the std::quoted quoting/escaping as required.
Live Demo
Proof Of Concept:
Live On Coliru
#include <boost/program_options.hpp>
#include <filesystem>
#include <iostream>
namespace std::filesystem {
template <class CharT>
void validate(boost::any& v, std::vector<std::basic_string<CharT>> const& s,
std::filesystem::path* p, int)
{
assert(s.size() == 1);
std::basic_stringstream<CharT> ss;
for (auto& el : s)
ss << std::quoted(el);
path converted;
ss >> std::noskipws >> converted;
if (ss.peek(); !ss.eof())
throw std::runtime_error("excess path characters");
v = std::move(converted);
}
}
namespace po = boost::program_options;
template <typename Path> static constexpr auto Type = "[unknown]";
template <> constexpr auto Type<std::string> = "std::string";
template <> constexpr auto Type<std::filesystem::path> = "fs::path";
template <typename Path>
bool do_test(int argc, char const* argv[]) try {
Path optionsFile;
po::options_description desc("Options");
desc.add_options() //
("help,h", "Help screen") //
("options,o", po::value<Path>(&optionsFile),
"File containing the command and the arguments");
po::command_line_parser parser{argc, argv};
parser.options(desc).allow_unregistered().style(
po::command_line_style::default_style |
po::command_line_style::allow_slash_for_short);
auto parsed_options = parser.run();
po::variables_map vm;
store(parsed_options, vm);
notify(vm);
if (vm.count("help")) {
std::cout << desc << '\n';
return true;
}
std::cout << "Using " << Type<Path> << "\toptionsFile = " << optionsFile << "\n";
return true;
} catch (const std::exception& e) {
std::cout << "Using " << Type<Path> << "\terror: " << e.what() << "\n";
return false;
}
int main() {
for (auto args : {
std::vector{"Exepath", "-o", "c:\\temp\\options1.txt"},
std::vector{"Exepath", "-o", "c:\\temp\\options 1.txt"},
})
{
std::cout << "\n -- Input: ";
for (auto& arg : args) {
std::cout << " " << std::quoted(arg);
}
std::cout << "\n";
int argc = args.size();
args.push_back(nullptr);
do_test<std::string>(argc, args.data());
do_test<std::filesystem::path>(argc, args.data());
}
}
Now prints
-- Input: "Exepath" "-o" "c:\\temp\\options1.txt"
Using std::string optionsFile = c:\temp\options1.txt
Using fs::path optionsFile = "c:\\temp\\options1.txt"
-- Input: "Exepath" "-o" "c:\\temp\\options 1.txt"
Using std::string optionsFile = c:\temp\options 1.txt
Using fs::path optionsFile = "c:\\temp\\options 1.txt"
¹ this actually happens inside boost::lexical_cast which comes from Boost Conversion

Can't get segmentation fault exit code from boost child process

I am trying to get the exit code of a child process (using boost::process and boost::asio) when that child process is killed due to a segmentation violation or divide be zero or any other kill signal. The exit code and error code always return with 0 and success.
I am running this on CentOS 7 using g++ 4.8.5 and boost 1.66
If I run the same code with a child process that simply returns a non-zero exit code it successfully returns that exit code.
#include <iostream>
#include <boost/process.hpp>
#include <boost/asio/io_service.hpp>
namespace bp = boost::process;
using namespace std;
int main (int argc, char** argv)
{
string exe = "./crashes";
vector<string> data;
boost::asio::io_service ios;
int exit_code;
error_code ec;
future<string> ostr;
bp::child c(exe,
(bp::std_out & bp::std_err) > ostr,
ios,
bp::on_exit=[&exit_code, &ec](int exit, const error_code& ecin)
{exit_code = exit; ec = ecin;});
ios.run();
cout << "Exit Code = " << exit_code << endl;
cout << "Error Code = " << ec.message() << endl;
cout << "child stdin & stderr:\n";
cout << ostr.get() << endl;
return exit_code;
}
and the crashes code
int main (int argc, char** argv)
{
int* y = 0;
int c = *y;
}
The results show a 0 exit code and Success error_code
Exit Code = 0
Error Code = Success
child stdin & stderr:
running the crashes executable alone returns an exit code of 139
bash-4.2$ ./crashes
Segmentation fault (core dumped)
bash-4.2$ echo $?
139
The details of process termination and exit codes are platform dependent.
Boost process papers over the differences in the default interface: your on_exit handler is called with the result of boost::process::detail::posix::eval_exit_status() of the exit status, which means:
inline int eval_exit_status(int code)
{
if (WIFEXITED(code))
{
return WEXITSTATUS(code);
}
else if (WIFSIGNALED(code))
{
return WTERMSIG(code);
}
else
{
return code;
}
}
So, you get "exit-code 11" meaning segfault... If you want to actually know, you can look at native_exit_code()
bp::on_exit = [&result, &c](int /*ignored*/, const std::error_code &ec) {
auto exit_status = c.native_exit_code();
result.exit_code = boost::make_optional(WIFEXITED(exit_status), WEXITSTATUS(exit_status));
result.signal = boost::make_optional(WIFSIGNALED(exit_status), WTERMSIG(exit_status));
result.ec = ec;
}
Now this assumes some changes to the result variables. Full listing:
Listing
#include <boost/asio/io_service.hpp>
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
int main(int argc, char**) {
std::string exe = argc>1? "./ltua" : "./crashes";
boost::asio::io_service ios;
struct {
boost::optional<int> exit_code;
boost::optional<int> signal;
std::error_code ec{};
} result;
std::future<std::string> ostr;
bp::group g;
bp::child c(exe, g, (bp::std_out & bp::std_err) > ostr, ios,
bp::on_exit = [&result, &c](int /*ignored*/, const std::error_code &ec) {
auto exit_status = c.native_exit_code();
result.exit_code = boost::make_optional(WIFEXITED(exit_status), WEXITSTATUS(exit_status));
result.signal = boost::make_optional(WIFSIGNALED(exit_status), WTERMSIG(exit_status));
result.ec = ec;
});
//g.wait();
ios.run();
if (result.exit_code) {
std::cout << "Exited with " << *result.exit_code << std::endl;
}
if (result.signal) {
std::cout << "Signaled with sginal #" << *result.signal << ", aka " << ::strsignal(*result.signal) << std::endl;
}
std::cout << "Error Code = " << result.ec.message() << std::endl;
std::cout << "child stdin & stderr:\n";
std::cout << ostr.get() << std::endl;
return result.exit_code? *result.exit_code : 255;
}
Output
When run with ltua.cpp:
#include <iostream>
int main() {
std::cout << "so long" << std::end;
std::cerr << "and thanks" << std::end;
std::cout << "for all" << std::end;
std::cerr << "the fish" << std::end;
return 42;
}
Prints
Exited with 42
Error Code = Success
child stdin & stderr:
so long
and thanks
for all
the fish
And with crashes.cpp:
int main() {
int *y = 0;
int c = *y;
}
Prints
Signaled with sginal #11, aka Segmentation fault
Error Code = Success
child stdin & stderr:

Get HDD size programatically on MacOS using C++

I am building an application and I need to get the HDD size:
I am working on Mac OS. I have tried this:
#include <sys/param.h>
#include <sys/mount.h>
float MonitoringWorker::getHDDSize()
{
struct statfs statf;
statfs(".", &statf);
std::cout << "statf.f_bsize = " << statf.f_bsize << std::endl;
std::cout << "statf.f_blocks = " << statf.f_blocks << std::endl;
std::cout << "statf.f_bavail = " << statf.f_bavail << std::endl;
std::cout << "statf.f_bfree = "<< statf.f_bfree << std::endl;
std::cout << "GB = "<< ((statf.f_bsize * statf.f_blocks) / kBytesInGB)<< std::endl;
return 0;
}
I am seeing that the result in GB is 465. However checking System Information tells me that I have 500GB
What am I doing wrong? Is this best way to get those numbers?
Note: I am using C++ on Mac OS, can't use Objective-C
Thanks in advance

Long path name in SetCurrentDirectoryW

Using this msdn reference I created a small use case.
#include <iostream>
#include <windows.h>
int main()
{
const std::wstring dir_path = L"\\\\?\\c:\\temp\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory";
if (!CreateDirectoryW(dir_path.c_str(), NULL))
{
std::cout << " Error occurred while creation of directory!!! " << GetLastError() << std::endl;
}
else
{
std::cout << "Lenth is " << dir_path.length() << std::endl;
if (dir_path.length() > 255)
{
if (!SetCurrentDirectoryW(buf.c_str()))
{
std::cout << " Error occurred!!! " << GetLastError() << std::endl;
}
else
{
std::cout << " Successful!!!" << std::endl;
}
}
}
return 0;
}
However, I get the output as
Error occurred while creation of directory!!! 3
Error code 3 points me to
ERROR_PATH_NOT_FOUND
3 (0x3)
The system cannot find the path specified.
Are there any other way to use long path names in CreateDirectoryW or SetCurrentDirectoryW APIs that I am unaware of ?
PS:I am using VS 2015 Update 3 compiler on Windows 7.
You have to create each directory on the path one by one. So the parent directory to the directory you pass must exist before you call CreateDirectory.
This information can be found by reading the documentation. It specifically calls out that error code and says:
One or more intermediate directories do not exist; this function will only create the final directory in the path.

losing files when using ReadDirectoryChangesW

I'm using ReadDirectoryChangesW to monitor a directory.
Here's my simple code
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <cwctype>
using namespace std;
wstring getname(FILE_NOTIFY_INFORMATION *tmp)
{
wstring s = L"";
for (int i = 0;i < tmp->FileNameLength / 2;i++)
s += tmp->FileName[i];
return s;
}
void _tmain(int argc, TCHAR *argv[])
{
HANDLE hDir;
char notify[1024];
DWORD cbBytes,i;
char AnsiChar[3];
wchar_t UnicodeChar[2];
LPTSTR path;
FILE_NOTIFY_INFORMATION *pnotify=(FILE_NOTIFY_INFORMATION *)notify;
FILE_NOTIFY_INFORMATION *tmp ;
// GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));
wcout.imbue(locale("chs"));
path = argv[1];
hDir = CreateFile( path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED, NULL);
wcout << L"===CreateFile complete===" << endl;
if (hDir == INVALID_HANDLE_VALUE)
{
wcout << L"invalid handle value" << endl;
return;
}
FILE_NOTIFY_INFORMATION buffer[1024];
FILE_NOTIFY_INFORMATION *pbuffer;
while (TRUE)
{
wcout << L"waiting..." << endl;
if(ReadDirectoryChangesW(hDir, &buffer, sizeof(buffer),
TRUE, FILE_NOTIFY_CHANGE_FILE_NAME| FILE_NOTIFY_CHANGE_LAST_WRITE,
&cbBytes, NULL, NULL))
{
pbuffer = buffer;
do{
tmp = pbuffer;
switch(tmp->Action)
{
case FILE_ACTION_ADDED:
wcout << L"Directory/File added - " << getname(tmp) << endl;
break;
case FILE_ACTION_REMOVED:
wcout << L"Directory/File removed - " << getname(tmp) << endl;
break;
case FILE_ACTION_MODIFIED:
wcout << L"Directory/File modfied - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_OLD_NAME:
wcout << L"Directory/File old name - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
wcout << L"Directory/File new name - " << getname(tmp) << endl;
break;
default:
wcout << L"unknown action\n" << endl;
break;
}
pbuffer += pbuffer->NextEntryOffset;
}while(pbuffer->NextEntryOffset);
} else
{
wcout << "readChangesW failed now return" << endl;
return;
}
}
}
It looks fine, however, when I'm adding or deleting a large number of files in my directory, it will not report some of the changes, how can I fix this?
Try making your buffer bigger.
From the documentation for the ReadDirectoryChangesW function:
When you first call ReadDirectoryChangesW, the system allocates a buffer to store change information. This buffer is associated with the directory handle until it is closed and its size does not change during its lifetime. Directory changes that occur between calls to this function are added to the buffer and then returned with the next call. If the buffer overflows, the entire contents of the buffer are discarded and the lpBytesReturned parameter contains zero.
The buffer size that the system allocates is based on the size of the buffer you pass in. If you pass in a bigger size the system will allocate a bigger buffer to store changes that occur while you are processing the previous lot of changes, which means there's less chance of the buffer overflowing and those changes being lost.

Resources