creating a Vulkan Instance in version 1.3.224 doesn't work and results in an Error VK_ERROR_INCOMPATIBLE_DRIVER on Apple M1 - visual-studio-code

Hello I am new to Vulkan and c++.
I am following a tutorial on Vulkan for Visual-Studio and stuck at creating a Vulkan Instance. Through a lot of googling I found out that the error -9 (VK_ERROR_INCOMPATIBLE_DRIVER) is based on the Vulkan Version 1.3, me using MacOS and how it implements the MoltenVk or must be included or something else like that.
There it got too complicated for me.
I have tried to search through the documentations and now I don't really even understand what MoltenVk is or how I even tried to include Vulkan with cmake in my project.
I may found a solution on [here] and on stackoverflow (Why does vkCreateInstance return "VK_ERROR_INCOMPATIBLE_DRIVER" on MacOS despite vulkan supported GPU and up to date driver?) but I am not able to implement/understand it. Maybe somebody can explain it or tell me how to implement it?.
The Site said I should put something like that in
std::vector<const char*>
extNames.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
extNames.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
VkInstanceCreateInfo inst_info = {};
ins_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
inst_info.enabledExtensionCount = static_cast<uint32_t>(extNames.size());
inst_info.ppEnabledExtensionNames = extNames.data();
I have tried it that way and with some deviations in the vk_device.cpp file without any success.
My Project basically looks like this:
Project
--.vscode
--bin
->Project.exe
--build
--CMakeFiles
--libs
--SDL
--src
--Vk_base
->vk_base.h
->vk_device.cpp
->main.cpp
->CMakeList.txt
vk_base.h:
#include <vulkan/vulkan.h>
struct VulkanContext {
VkInstance instance;
};
VulkanContext* initVulkan();
vk_device.cpp:
#include "vk_base.h"
#include <iostream>
bool initVulkanInstance(VulkanContext* context) {
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Vulkan App";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_VERSION_1_0;
VkInstanceCreateInfo createInfo = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
createInfo.pApplicationInfo = &appInfo;
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; // MAC OS SPECIFIC
//createInfo.enabledExtensionCount = static_cast<uint32_t>(extNames.size()); // MAC OS SPECIFIC
//createInfo.ppEnabledExtensionNames = extNames.data(); // MAC OS SPECIFIC
VkResult creation_result = vkCreateInstance(&createInfo, 0, &context->instance);
std::cout << creation_result << std::endl;
return true;
}
VulkanContext* initVulkan() {
VulkanContext* context = new VulkanContext();
if (initVulkanInstance(context) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
return context;
}
main.cpp
#include <iostream>
#include <SDL.h>
#include "vk_base/vk_base.h"
bool handleMessage() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
return false;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE) {
return false;
}
break;
}
}
}
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *_window;
_window = SDL_CreateWindow("Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 700, 500, SDL_WINDOW_RESIZABLE);
SDL_Event e;
bool quit = false;
while (!quit) {
while(SDL_PollEvent(&e) != 0){
if(e.type == SDL_QUIT){
quit = true;
}
}
}
VulkanContext* context = initVulkan();
SDL_DestroyWindow(_window);
SDL_Quit();
return 0;
}
and my Cmakefile to create the Project in the build folder with the command : cmake ../ -GXcode ( I have tried it with -GXcode and without)
CMakeLists.txt:
#project name
project(Project)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
set(SOURCE_FILES src/main.cpp src/vk_base/vk_device.cpp)
#find SDL2
add_subdirectory(libs/SDL)
#find Vulkan
find_package(Vulkan REQUIRED)
#vulkan executebl
add_executable(Project ${SOURCE_FILES})
target_include_directories(Project PUBLIC libs/SDL/include)
target_link_libraries(Project PUBLIC SDL2-static)
target_link_libraries(Project PUBLIC Vulkan::Vulkan)
target_link_libraries(Project PUBLIC ${Vulkan_LIBRARIES})
Thank you for reading and sry for my bad english:)
if there are misspellings in it, it is probably not the cause of the problem and just a typo from me on this thread :p

if you are not comfortable with C++, steer away from Vulkan. One will teach you exactly the wrong lessons about the other. Vulkan is low-level API, and shows you how you should not be programming C++ in 98 % of the time.
Apple does not support Vulkan. They have their own API Metal. MoltenVK is a library that attempts to translate Vulkan function calls to Metal calls.
This API translation does not match 1:1, so the MoltenVK wrapper is not a conformant Vulkan implementation. You need to waive that it is not conformant, and that you know of and will avoid triggering the limitations:
https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VK_KHR_portability_subset
https://github.com/KhronosGroup/MoltenVK/blob/master/Docs/MoltenVK_Runtime_UserGuide.md#known-moltenvk-limitations
You waive the Vulkan conformance by adding VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit to the Instance creation:
#ifdef __APPLE__
createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif //__APPLE__
VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR is part of a Vulkan extension, so that extension needs to be enabled before using the bit, per standard Vulkan rules:
#ifdef __APPLE__
extNames.push_back( VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME );
#endif //__APPLE__
createInfo.enabledExtensionCount = static_cast<uint32_t>(extNames.size());
createInfo.ppEnabledExtensionNames = extNames.data();

Related

Linux, spidev: why it shouldn't be directly in devicetree?

I want to define a SPI device with usermode access, as explained for example in http://linux-sunxi.org/SPIdev
Following these examples, I added in the devicetree this :
&ecspi1 {
.... other stuff ...
mydev#0 {
compatible = "spidev";
spi-max-frequency = <5000000>;
reg = <2>; /*chipselect*/
};
};
The platform is i.MX6. ecspi1 seems to be their SPI controller.
Then I indeed get /dev/spi0.2 and /sys/class/spidev/spidev0.2
But in kernel trace there's a WARNING saying this:
spidev spi0.2: buggy DT: spidev listed directly in DT
So how else the spidev should be described? What is the right syntax?
spidev: why it shouldn't be directly in devicetree?
The Device Tree should describe the board's hardware, but
spidev does not describe/identify any hardware.
Mark Brown wrote:
Since spidev is a detail of how Linux controls a device rather than a
description of the hardware in the system we should never have a node
described as "spidev" in DT, any SPI device could be a spidev so this
is just not a useful description.
The rationale and workaround for this kernel patch is https://patchwork.kernel.org/patch/6113191/
So how else the spidev should be described? What is the right syntax?
Instead of explicit use of spidev in your Device Tree source, you instead need to identify the actual device that you're controlling, e.g.
mydev#0 {
- compatible = "spidev";
+ compatible = "my_spi_device";
spi-max-frequency = <5000000>;
Then (as Geert Uytterhoeven explains), modify drivers/spi/spidev.c in the kernel source code by adding the compatible value for your device to the spidev_dt_ids[] array
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
+ { .compatible = "my_spi_device" },
{},
}
An alternate solution, which involves a quick-n-dirty change to just the Device Tree, is suggested by this article.
Simply replace the "spidev" compatible string with a proper string that already does exist:
mydev#0 {
- compatible = "spidev";
+ compatible = "rohm,dh2228fv"; /* actually spidev for my_spi_dev */
spi-max-frequency = <5000000>;
Since "rohm,dh2228fv" is already in the spidev_dt_ids[] list, no edit to drivers/spi/spidev.c is needed.
To avoid this issue just use linux,spidev instead of spidev:
&spi0 {
mydev#0 {
compatible = "linux,spidev";
};
};

international chars in tcl/tk can't be handle

I use tcl shellicon command to extract icons, as it mentioned on wiki page below, there are some international character problems in it, then I write some code to test but it doesn't work, could anyone to help me correct it.
/*
* testdll.c
* gcc compile: gcc testdll.c -ltclstub86 -ltkstub86 -IC:\Users\L\tcc\include -IC:\Users\L\tcl\include -LC:\Users\L\tcl\lib -LC:\Users\L\tcc\lib -DUSE_TCL_STUBS -DUSE_TK_STUBS -shared -o testdll.dll
*/
#include <windows.h>
#include <tcl.h>
#include <stdlib.h>
int TestdllCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]) {
char * path;
Tcl_DString ds;
if (objc > 2) {
Tcl_SetResult(interp, "Usage: testdll ?path?",NULL);
return TCL_ERROR;
}
if (objc == 2) {
path = Tcl_GetString(objv[objc-1]);
path = Tcl_TranslateFileName(interp, path, &ds);
if (path != TCL_OK) {
return TCL_ERROR;
}
}
Tcl_AppendResult(interp, ds, NULL);
return TCL_OK;
}
int DLLEXPORT Testdll_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "testdll", TestdllCmd, NULL, NULL);
Tcl_PkgProvide(interp, "testdll", "1.0");
return TCL_OK;
}
I compile it with:
gcc compile: gcc testdll.c -ltclstub86 -ltkstub86 -IC:\Users\USERNAME\tcc\include -IC:\Users\USERNAME\tcl\include -LC:\Users\USERNAME\tcl\lib -LC:\Users\USERNAME\tcc\lib -DUSE_TCL_STUBS -DUSE_TK_STUBS -shared -o testdll.dll
windows cmd shell run: tclsh testdll.tcl
load testdll
puts [testdll C:/Users/L/桌面]
the output is:
// This line isn't in the output, just to show the first line of output is a *EMPTY LINE*
while executing
"testdll 'C:/Users/L/桌面'"
invoked from within
"puts [testdll 'C:/Users/L/桌面']"
(file "testdll.tcl" line 2)
In fact, I want to print a line, whose content is "C:/Users/L/桌面"
I write this dll to debug how to replace Tcl_GetString,Tcl_TranslateFileName with Tcl_FSGetNormalizedPath, Tcl_FSGetNativePath, I wonder if it's clear?
Thank you!
Remove this:
if (path != TCL_OK) {
return TCL_ERROR;
}
You are comparing a char * to an int.
The manual page for Tcl_TranslateFileName says:
However, with the advent of the newer Tcl_FSGetNormalizedPath
and Tcl_FSGetNativePath, there is no longer any need to use this
procedure.
You should probably switch to more modern API call.

How to add a built-in module to a C-Python API after Py_Initialize?

I have a module defined in my C code like so:
static struct PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
"the_module_name", /* m_name */
module_documentation, /* m_doc */
//....
};
and a function to initialize it:
PyMODINIT_FUNC init_the_module(void)
{
PyObject *mod, *submodule;
PyObject *sys_modules = PyThreadState_GET()->interp->modules;
mod = PyModule_Create(&module_def);
PyModule_AddObject(mod, "some_submodule", (submodule = init_the_submodule()));
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
Py_INCREF(submodule);
// more submodules..
return mod;
}
The application that I am embedding python into is quite big and I can not change the workflow much. At this point Py_Initialize has already been called, so I can not call PyImport_ExtendInittabor PyImport_AppendInittab .
How can I create and add the module to the system modules?
Maybe I can manipulate the modules dictionary directly? Like so:
PyObject *modules, *the_module;
modules = PyImport_GetModuleDict();
PyDict_SetItemString(modules, "the_module_name", init_the_module());
the_module = PyDict_GetItemString(modules, "the_module_name"); //this is getting something back
std::cout << PyDict_Size(the_module) << std::endl; // this prints -1
The easiest way to handle this is to statically initialize your statically-linked modules by directly calling initspam() after the call to Py_Initialize() or PyMac_Initialize():
int main(int argc, char **argv)
{
/* Pass argv[0] to the Python interpreter */
Py_SetProgramName(argv[0]);
/* Initialize the Python interpreter. Required. */
Py_Initialize();
/* Add a static module */
initspam();
An example may be found in the file Demo/embed/demo.c in the Python source distribution.

XSD Validation on iOS

I want to validate XML files against an XSD on iOS. The documentations alludes to using NSXMLDocument to do this, but its not available on iOS =(. Are there any light weight alternatives to do this on iOS?
I ended up using the validation facilities in libxml2 since its a library already included in iOS. Following this sample code
#include <libxml/parser.h>
#include <libxml/xmlschemas.h>
int is_valid(const xmlDocPtr doc, const char *schema_filename)
{
xmlDocPtr schema_doc = xmlReadFile(schema_filename, NULL, XML_PARSE_NONET);
if (schema_doc == NULL) {
/* the schema cannot be loaded or is not well-formed */
return -1;
}
xmlSchemaParserCtxtPtr parser_ctxt = xmlSchemaNewDocParserCtxt(schema_doc);
if (parser_ctxt == NULL) {
/* unable to create a parser context for the schema */
xmlFreeDoc(schema_doc);
return -2;
}
xmlSchemaPtr schema = xmlSchemaParse(parser_ctxt);
if (schema == NULL) {
/* the schema itself is not valid */
xmlSchemaFreeParserCtxt(parser_ctxt);
xmlFreeDoc(schema_doc);
return -3;
}
xmlSchemaValidCtxtPtr valid_ctxt = xmlSchemaNewValidCtxt(schema);
if (valid_ctxt == NULL) {
/* unable to create a validation context for the schema */
xmlSchemaFree(schema);
xmlSchemaFreeParserCtxt(parser_ctxt);
xmlFreeDoc(schema_doc);
return -4;
}
int is_valid = (xmlSchemaValidateDoc(valid_ctxt, doc) == 0);
xmlSchemaFreeValidCtxt(valid_ctxt);
xmlSchemaFree(schema);
xmlSchemaFreeParserCtxt(parser_ctxt);
xmlFreeDoc(schema_doc);
/* force the return value to be non-negative on success */
return is_valid ? 1 : 0;
}
It appears that it is not exactly easy to do in Objective C, but there are several ideas listed at this S.O. question: Possible to validate xml against xsd using Objc/iPhone code at runtime
It seems CodeSynthesis supports this here : http://wiki.codesynthesis.com/Using_XSDE_in_iPhone_Applications
I am really just pulling links and ideas from the Stack Overflow question at this point, though.
There is not a general schema validator. Try using XSDE as proposed above. It is very fast and very, very reliable.
Nice tutorial is here: http://amateuritsolutions.blogspot.hu/2012/10/validate-xsd-schema-in-your-ios.html

Reason for segmentation fault, while using drag wxFileDropTarget

I try to do simple drag'n'drop (drag file to text area). I implemented drag'n'drop in 2 ways. Lets mark them V1 and V2.
In both versions drag'n'drop works OK, but in V1 I get segmentation fault when I try to exit the application.
Question:
Maybe somebody could enlighten me why with V1 I get segmentation faul, while no segmentation fault with V2 ?
(I have no real problem using V2, just want to know the reason why segmenation fault occurs)
Short descriptions of the versions:
V1 - There is one class named Notepad. It inherits from wxFrame and wxFileDropTarget, and encapsulates wxTextCtrl and implements OnDropFiles(
V2 - class Notepad ingerits only from wxFrame and encapsulates wxTextCtrl. Drang'n'drop is done by separate class called DRPTARGET, which inherits from wxFileDropTarget and implements OnDropFiles(
Code for ilustration
(I cut out a lot of code here, which was not relevant. I hope I did not cut out too much)
V1:
#include <wx/wx.h>
#include <wx/dir.h>
#include <wx/dnd.h>
class Notepad : public wxFrame , public wxFileDropTarget {
public:
Notepad();
private:
wxTextCtrl* text_area;
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames);
};
bool Notepad::OnDropFiles (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxArrayString &filenames){
return this->text_area->LoadFile(filenames[0]);
}
Notepad::Notepad() : wxFrame(NULL, wxID_ANY, wxT("V1"), wxDefaultPosition, wxSize(650,500)) {
wxBoxSizer *sizerh = new wxBoxSizer(wxHORIZONTAL);
this->text_area = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_MULTILINE);
sizerh->Add(this->text_area,1,wxEXPAND,0);
this->SetSizer(sizerh);
this->text_area->SetDropTarget(this);
}
V2:
#include <wx/wx.h>
#include <wx/dir.h>
#include <wx/dnd.h>
class DRPTARGET : public wxFileDropTarget{
private:
wxTextCtrl* text_area;
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
{
return this->text_area->LoadFile(filenames[0]);
};
public:
DRPTARGET(wxTextCtrl* text_area)
{
this->text_area = text_area;
};
};
class Notepad : public wxFrame , public wxFileDropTarget {
public:
Notepad(); // our default constructor
private:
wxTextCtrl* text_area;
};
Notepad::Notepad() : wxFrame(NULL, wxID_ANY, wxT("V2"), wxDefaultPosition, wxSize(650,500)) {
wxBoxSizer *sizerh = new wxBoxSizer(wxHORIZONTAL);
this->text_area = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_MULTILINE);
sizerh->Add(this->text_area,1,wxEXPAND,0);
this->SetSizer(sizerh);
DRPTARGET* drop_target = new DRPTARGET(this->text_area);
this->text_area->SetDropTarget(drop_target);
}
When a drop target is registered, wxWidgets will be nice and delete the pointer after the it exits the main loop. The problem has to do with the scope of the file drop target object.
V1
this->text_area->SetDropTarget(this);
In this version, "this" refers to the frame. Remember that the window pointers are also managed by wxWidgets; the frame pointer is deleted before the file drop target. When wxWidgets tries to delete the drop target pointer it will attempt to delete a pointer that has already been deleted.
V2
DRPTARGET* drop_target = new DRPTARGET(this->text_area);
this->text_area->SetDropTarget(drop_target);
In this case, the pointer is allocated in the heap; but never deleted. In this case, when wxWidgets attempts to delete it it can do so safely.