LINUX.ORG.RU

Сообщения KivApple

 

Монитор с USB Type-C: может ли избирательно повредиться разъём

Форум — Linux-hardware

Один из друзей подарил на день рождения вчера 4K монитор с USB Type C, который выполняет сразу 3 функции: монитор, зарядка PD до 90 ватт и USB хаб. Всё благодаря USB Type C.

На двух ноутбуках работает всё, кроме последней функции: происходит ошибка запроса дескриптора USB.

Нюанс в том, что в ходе праздничного застолья так случилось, что монитор один раз дернули за USB Type C провод, а до этого работоспособность USB портов не проверяли.

Вопрос к знатокам шины USB: может ли разъём так повредиться, что будет работать PD и DisplayPort, но не работать USB?

Я вот знаю, что PD вообще не использует линии данных, а только питание, землю и экран кабеля (но при этом важно, чтобы экран не был закорочен с землёй). А про DisplayPort over USB особо не знаю. В моём представлении устройства стартуют в режиме USB, а уже потом договариваются о всяких alt mode типа displayport или thunderbolt. Соответственно, если бы повредились линии USB 2.0, то и картинки на экране не было бы. Это так или не совсем?

Хочется разделить вероятности аппаратных и программных проблем.

P.S.: Кабель используется комплектный.

 , ,

KivApple
()

Хорошие библиотеки для обработки строк на C++

Форум — Development

А есть ли для C++ хорошие библиотеки для обработки строк в функциональном стиле?

Чтобы можно было, например, решить задачу вида «разбить строку по символу переноса строки, удалить завершающие пробелы, отфильтровать непустые строки, вывести» как-то так:

std::string text = ...;
text.split('\n')
    .map([](auto s) { return s.trim(); })
    .filter([](auto s) { return !s.empty(); })
    .for_each([](auto s) { std::cout << s << std::endl; });

Разумеется, это всё ещё должно работать на базе string_view или аналога из библиотеки, чтобы не было лишних копирований и аллокаций. И без создания промежуточных контейнеров.

 ,

KivApple
()

CEssentials

Форум — Development

Я тут запилил небольшую библиотеку для Plain C:

https://github.com/KivApple/CEssentials

Что в себе содержит:

- Утилиты работы с динамическими строками

- Обобщённый вектор (на макросах)

- Обобщённая хеш-таблица (на макросах) с open adressing и quadratic probing

Обобщённые структуры данных реализованы типобезопасным образом (макросы порождают static inline функции под нужный тип данных, соответственно, у компилятора есть информация о типах).

Я открыт к критике как по поводу самого содержимого, так и его упаковки (насколько хорош подход, который выбрал именно я для реализации обобщённого программирования в C).

Библиотека распространяется под лицензией MIT и обладает исчерпывающей документацией.

UPD: Переписал в snake_case стиле, плюс перевёл полностью на макросы вместо порождения макросами кучи специализированных функций, потому что оказалось, что на практике глобальное пространство имён быстро засоряется, а других в plain C не завезли.

UPD2: Написал статью по устройству хеш-таблицы из библиотеки: https://habr.com/ru/post/704724/

 ,

KivApple
()

std::any без аллокаций

Форум — Development

Я тут не нашёл ни в STL, ни в Boost версии any позволяющей избегать аллокаций. Точнее в STL есть small value optimization, но на практике размеры буфера очень малы (на GCC это всего лишь 1 указатель, в MSVC 3 указателя), а возможности задать свой размер нет (например, допустим, мы знаем, что большинство объектов меньше 64 байт).

Так что я сделал свой Any: https://pastebin.com/JMS32LNi

Вроде всё хорошо работает, кроме некоторых конструкторов:

int x = 10;
Any<64> v0 = x; // Ошибка

Any<64> v1 = 10; // Работает
Any<128> v2 = v1; // Ошибка

Собственно, в обоих случаях проблема в том, что вызывается конструктор template<typename T> Any(T &&value) вместо template<typename T> Any(const T &value) для первого случая и template<std::size_t N> Any(const Any<N> &value) для второго.

Как можно исправить вызовы конструкторов?

P. S. Такая же проблема с оператором присваивания - всегда выбирается версия с аргументом T, а версии с Any игнорируются.

 ,

KivApple
()

Структура данных

Форум — Development

Есть множество кубов заданных координатами центров и длиной ребра. Их много и они могут наслаиваться, но зато все координаты и размеры целые. Нужен алгоритм, который по координатам точки (тоже целым) выдаст список всех кубов, в которые она попадает (допустим, у кубов есть идентификаторы или хотя бы номера). При этом нужна также возможность быстро двигать кубы (менять координаты центров, однако, обычно за один шаг сдвиг мал). Запросы на принадлежность точек происходят чаще, чем сдвиги кубов.

Например, у нас есть 1000 кубов, они двигаются раз в секунду (в разное время), а каждую секунду мы проверяем миллион точек.

Какая структура данных лучше всего для этого подходит?

 , ,

KivApple
()

CMake + vcpkg + EMSDK

Форум — Development

Допустим, есть простенький C++ проект:

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

include(FetchContent)
FetchContent_Declare(vcpkg GIT_REPOSITORY https://github.com/microsoft/vcpkg/ GIT_TAG 2022.09.27)
FetchContent_MakeAvailable(vcpkg)
set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake" CACHE FILEPATH "")

project(MyProject)

set(CMAKE_CXX_STANDARD 20)

find_package(spdlog CONFIG REQUIRED)

add_executable(${CMAKE_PROJECT_NAME} main.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE spdlog::spdlog)

vcpkg.json

{
        "name": "main",
        "version-string": "latest",
        "dependencies": [
                "spdlog"
        ]
}

main.cpp

#include <spdlog/spdlog.h>

int main() {
        spdlog::info("Hello world!");
        return 0;
}

Пытаемся его собирать нативно:

$ cmake .. && make && ./MyProject
...
[100%] Built target MyProject
[2022-10-23 14:41:07.376] [info] Hello world!

Всё работает.

Теперь, допустим, мы его хотим собрать под WASM:

$ source "/home/kiv/emsdk/emsdk_env.sh"
...
$ cmake .. -DVCPKG_TARGET_TRIPLET=wasm32-emscripten && make
-- Running vcpkg install
-- Running vcpkg install - done
CMake Error at build-wasm/_deps/vcpkg-src/scripts/buildsystems/vcpkg.cmake:829 (_find_package):
  Could not find a configuration file for package "spdlog" that is compatible
  with requested version "".

  The following configuration files were considered but not accepted:

    /home/kiv/my_project/build-wasm/vcpkg_installed/wasm32-emscripten/share/spdlog/spdlogConfig.cmake, version: 1.10.0 (32bit)

Call Stack (most recent call first):
  CMakeLists.txt:12 (find_package)


-- Configuring incomplete, errors occurred!
See also "/home/kiv/my_project/build-wasm/CMakeFiles/CMakeOutput.log".

Беглый поиск по ошибке даёт наводку, что такое может быть, когда CMake находит несовместимую библиотеку. Например, пытается использовать системную при кросскомпиляции. Что ж, похоже на наш случай.

$ mkdir tmp && cd tmp
$ ar x ../vcpkg_installed/wasm32-emscripten/lib/libspdlog.a
$ file spdlog.cpp.o
spdlog.cpp.o: WebAssembly (wasm) binary module version 0x1 (MVP)

Нет, не наш случай - библиотека скомпилирована под WASM и её должно быть возможно использовать.

Возникает вопрос, как заставить CMake всё же использовать найденную библиотеку.

Пробуем указывать точную версию find_package(spdlog «1.10.0 (32bit)» CONFIG REQUIRED) - получаем ошибку недопустимого аргумента (вероятно, из-за пробела в версии). Если указывать же просто 1.10.0, то получаем старую ошибку и ничего не меняется.

Возникает вопрос, как find_package определяет совместимость библиотеки и как изменить его мнение в данной ситуации.

 , , vcpkg

KivApple
()

C++ modules и системы сборки

Форум — Development

Кто как собирает проекты с использованием C++ modules?

Компиляторы уже давно умеют их, например, в clang даже объявили deprecated опцию -fmodules-ts и поддержка модулей автоматически включается при активации стандарта C++20.

Однако, собирать руками проекты удовольствия мало. Хочется использовать какую-нибудь систему сборки. И вот тут возникает проблема. Самая популярная система сборки в мире C/C++ - CMake - поддерживает модули только для MSVC, что как бы не очень интересно (так как ограничивает одной платформой, к тому же clang/gcc по моим тестам обычно генерируют более оптимальный код, чем MSVC, даже под Windows). Какие есть альтернативы? Можно ли приобщиться к модулям не путём написания вручную Makefile или Bash-скриптов?

 , ,

KivApple
()

Rust и обёртка над блокировкой

Форум — Development

Допустим, у нас есть некая мутабельная структура данных (в данном случае это просто число, но это лишь для простоты примера), которую мы хотим шарить между потоками. При этом мы хотим сделать свою RAII обёртку над блокировкой этой сущности, чтобы предоставить пользователю определённый интерфейс её модификации (а также отслеживать разблокировку и т. п.).

Получается как-то так (лайфтаймы у обёртки от балды, потому что я не знаю как это правильно написать):

use std::sync::{Arc, Mutex, MutexGuard};

pub struct SharedData {
    data: Arc<Mutex<i32>>
}

impl SharedData {
    pub fn new(value: i32) -> Self {
        SharedData {
            data: Arc::new(Mutex::new(value))
        }
    }

    pub fn lock(&self) -> LockedSharedData<'_> {
        LockedSharedData::new(self.data.clone())
    }
}

pub struct LockedSharedData<'a> {
    _data: Arc<Mutex<i32>>,
    guard: MutexGuard<'a, i32>
}

impl<'a> LockedSharedData<'a> {
    fn new(data: Arc<Mutex<i32>>) -> Self {
        LockedSharedData {
            guard: data.lock().unwrap(),
            _data: data
        }
    }

    pub fn get(&self) -> i32 {
        *self.guard
    }

    pub fn inc(&mut self) {
        *self.guard += 1;
    }
}

Оно ожидаемо не компилируется - https://rust.godbolt.org/z/4rEe3fWxK :

error[E0515]: cannot return value referencing function parameter `data`
  --> <source>:26:9
   |
26 | /         LockedSharedData {
27 | |             guard: data.lock().unwrap(),
   | |                    ----------- `data` is borrowed here
28 | |             _data: data
29 | |         }
   | |_________^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `data` because it is borrowed
  --> <source>:28:20
   |
24 |   impl<'a> LockedSharedData<'a> {
   |        -- lifetime `'a` defined here
25 |       fn new(data: Arc<Mutex<i32>>) -> Self {
26 | /         LockedSharedData {
27 | |             guard: data.lock().unwrap(),
   | |                    ----------- borrow of `data` occurs here
28 | |             _data: data
   | |                    ^^^^ move out of `data` occurs here
29 | |         }
   | |_________- returning this value requires that `data` is borrowed for `'a`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0505, E0515.
For more information about an error, try `rustc --explain E0505`.
Compiler returned: 1

Собственно, вопрос как это переписать правильно, чтобы Rust устраивали лайфтаймы, но при этом сохранить инкапсуляцию заблокированного значения в структуру блокировки.

 ,

KivApple
()

Небольшой бенчмарк Rust vs C++

Форум — Talks

Я тут вам покушать принёс.

Rust: https://github.com/KivApple/rust_benchmark

C++: https://github.com/KivApple/cxx_benchmark

Реализован алгоритм построения icosphere. Этот алгоритм запускается 10000 раз и замеряется среднее время исполнения. Алгоритм реализован практически дословно на обоих языках. Для небольшой математики используется glm для C++ и glam для Rust. Также алгоритм использует стандартные контейнеры HashMap и Vec для Rust и std::unordered_map и std::vector для C++.

Результаты (указаны в порядке запуска тестов, каждый тест был запущен два раза, чтобы немного нивелировать влияние изменений частоты и температуры процессора, всякий кешей и т. п):

Rust: 211 us
MSVC: 606 us
GCC: 497 us
Clang: 575 us
Rust: 211 us
MSVC: 598 us
GCC: 496 us
Clang: 587 us

Тестовое железо: Core i7-1165G7, 64 GB RAM, Windows 11 (мне быстрее всего было это запустить на Windows машине, плюс так получилась возможность забенчить ещё и MSVC для полноты картины, так же надо учесть, что в программе нет ни I/O, ни многопоточности, так что едва ли ОС будет влиять на производительность, а если и будет, то опять же оба языка в равных условиях).

Все проекты собраны в Release режиме (cargo build --release, cmake -DCMAKE_BUILD_TYPE=Release) под 64 бита.

Критика бенчмарка принимается (я понимаю, что это один частный use-case, но в рамках него можете указать на какие-то неточности замеров или несоответствия алгоритмов для разных языков). Также можете попробовать запустить на своих машинах со своими компиляторами (код достаточно тривиальный для понимания).

UPD: Версии компиляторов:

> rustc --version
rustc 1.64.0 (a55dd71d5 2022-09-19)
> clang --version
clang version 15.0.2
Target: x86_64-pc-windows-msvc
Thread model: posix
> cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.32.31329 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.
> gcc --version
gcc (GCC) 11.3.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 , , ,

KivApple
()

Rust: преобразования указателя на трейт в конкретный тип

Форум — Development

Хочу хранить мапу с экземплярами реализующими трейт. При этом на месте одного ключа я уверен, что будет всегда лежать экземпляр одной и той же реализации (в данном примере в качестве ключа выступает помимо прочего TypeId). С хранием проблем не возникает, возникает проблема с извлечением элементов.

use std::collections::HashMap;
use std::any::TypeId;
use std::rc::Rc;

trait MyTrait {
    fn new() -> Self where Self: Sized;

    // Тут ещё какие-нибудь методы
}

struct MyStruct {
    items: HashMap<(i32, TypeId), Rc<dyn MyTrait>>
}

impl MyStruct {
    fn get<T: MyTrait + 'static>(&mut self, key: i32) -> Rc<T> {
        if let Some(item) = self.items.get(&(key, TypeId::of::<T>())) {
            item.clone() as Rc<T>
        } else {
            let item = Rc::new(T::new());
            self.items.insert((key, TypeId::of::<T>()), item.clone());
            item
        }
    }
}

Как правильно конвертировать элемент при его извлечении в тип T?

 

KivApple
()

std::unordered_map + emplace + non-movable тип

Форум — Development

Допустим, мы хотим хранить в качестве значений в unordered_map неперемещаемый тип. Например, вот так:

#include <mutex>
#include <unordered_map>

struct MyStruct {
    std::mutex mutex;
    int data = 0;
};

void f(std::unordered_map<int, MyStruct> &map, int key) {
    map.emplace(key, {});
}

Получаем ошибку компиляции: https://godbolt.org/z/vaTc5rxfP

У std::mutex нет ни конструктора копирования, ни конструктора перемещения. Однако, такие типы допустимо хранить в качестве значений в данном типе контейнера, потому что под капотом происходит динамическое выделение памяти и контейнер гарантирует, что единственная операция инвалидирующая ссылки и указатели на элементы - erase. Значит за всё время жизни элемента его никто никуда не переместит.

Проблема в том, как сделать emplace. Если бы у MyStruct был конструктор с аргументами - всё было бы просто. А у MyStruct нет конструктора, либо можно добавить, но по логике программы имеет смысл лишь конструктор без аргументов. Однако передать пустой список аргументов в emplace я не могу.

 

KivApple
()

Посоветуйте структуру данных

Форум — Development

Хочу структуру данных удовлетворяющую следующим условиям:

- Хранит в себе пары ключ-значение. Ключи - числа от 0 до 4095. Значения - uint32_t, но в целом вряд ли принципиально для алгоритма.

- Элементы отсортированы по возрастанию ключа - имея в каком-то виде указатель на элемент можно со сложностью O(1) получить указатель на следующий или на предыдущий (то есть возможна дешёвая итерация в обе стороны, полный обход списка в порядке сортировки и обратном имеет сложность O(N) - просто выполнить O(1) для каждого элемента) в порядке сортировки ключей.

- Существует операция поиска элемента по ключу со сложностью не более O(logN). При этом если элемента с таким ключом нет, должен находиться элемент с максимальным ключом меньше запрошенного. Функция поиска возвращает в каком-то виде указатель на элемент, который позволяет не только узнать его значение, но и выполнять итерирование, а также вставку и удаление элементов перед или после него.

- Операции добавления и удаления элементов - дешёвые, но выполняются значительно реже итерирования. Сложность не более O(logN).

- Эффективность по памяти. Требуется добавлять необходимый минимум служебной информации к элементам (так как сами элементы всего лишь 6 байт). Ну и само собой нельзя взять и выделить память сразу под 4096 возможных элементов, когда в реальности может лежать лишь пара сотен.

- Операции итерирования и поиска элементов не должны приводить к модификации структуры данных, чтобы можно было использовать RW блокировки и несколько потоков могли одновременно читать одну и ту же структуру (невозможность записи без эксклюзивной блокировки это нормально).

- Здорово если бы добавление-удаление элементов не инвалидировало указатели на не затронутые элементы, но это опциональное требование.

Как я понимаю, разумно использовать какой-нибудь std::vector, в который запихнуть элементы с обвязкой, а указатели между элементами (для построения какого-нибудь двоичного дерева) делать в виде 16-битных индексов (ведь максимальное число уникальных ключей всего 4096). Вопрос в том какую структуру данных построить поверх вектора.

 ,

KivApple
()

PF2: Метрики шрифта

Форум — Development

Пытаюсь сделать самодельный рендеринг текста с помощью PF2 шрифтов и OpenGL. В качестве шрифта использую Droid Sans. Для начала рендерю его в «моноширинном» режиме (поддержку переменной ширины глифа добавлю потом) - просто создаю текстуру, где каждому глифу отводится область maxCharWidth * maxCharHeight, а при рендеринге соответственно на каждую плоскость соответствующую очередному символу натягиваю текстуру по нужным координатам. Проблема в том, что глифы в шрифте могут иметь размеры меньше максимальных и их в этом случае надо правильно позиционировать внутри их места, иначе получается вот так (строчные буквы ниже заглавных и попадают не туда):

https://freeimage.host/i/iI0Yxt

Алгоритм помещения очередного глифа в текстуру шрифта выглядит так:

struct PF2CharHeader {
	uint16_t width;
	uint16_t height;
	int16_t xOffset;
	int16_t yOffset;
	int16_t deviceWidth;
};

...

class PF2FontLoader {
	...
	int m_pointSize;
	int m_maxCharWidth;
	int m_maxCharHeight;
	int m_ascent;
	int m_descent;
	...
}

...

void PF2FontLoader::parseCharBitmap(int index, const PF2CharHeader &header) {
	int x0 = (index % m_colCount) * m_maxCharWidth; //+ header.xOffset;
	int y0 = (index / m_colCount) * m_maxCharHeight; //+ header.yOffset;
	auto base = m_deserializer.adapter().currentReadPos();
	for (int y = 0; y < header.height; y++) {
		int j = (y0 + y) * m_textureWidth + x0;
		for (int x = 0; x < header.width; x++) {
			int i = y * header.width + x;
			uint8_t byte = m_data[base + i / 8];
			if ((byte & (1 << (7 - i % 8))) != 0) {
				m_textureData[j + x] = {255, 255, 255, 255};
			}
		}
	}
}

Также у меня есть параметры m_pointSize, m_ascent и m_descent извлеченные из заголовка шрифта (см. полное описание формата - http://grub.gibibit.com/New_font_format).

По идее ими надо как-то воспользоваться, чтобы вычислить baseline и разместить глиф, когда его размер меньше максимального, однако использовать xOffset и yOffset не помогает. Во-первых, у «e» и «H» одинаковый нулевой yOffset (хотя буквы имеют разную высоту глифа), во-вторых, тогда некоторые другие глифы выходят за границы своего места в текстуре.

Также вот параметры шрифта Droid Sans:

PF2 font "assets/fonts/DroidSans-32.pf2"
PF2 font name: Droid Sans Regular 32
PF2 font family: Droid Sans
PF2 font weight: normal
PF2 font slant: normal
PF2 font point size: 32
PF2 font max char width: 36
PF2 font max char height: 36
PF2 font ascent: 34
PF2 font descent: 9
PF2 font character index has 873 Unicode code point(s) (873 unique glyph(s))

 , , ,

KivApple
()

Статически создаваемые объекты

Форум — Development

Собственно, пример:

https://godbolt.org/z/YEPoddsss

Здесь речь идёт от std::initializer_list и о std::tuple.

Функции f и g принимают константную ссылку (на уровене ассемблера то же самое, что и указатель). Сами передаваемые объекты не предполагают динамического выделения памяти. То есть по факту они представляют одинаковый набор байт каждый вызов функции. Значит, с точки зрения самого алгоритма ничто не мешает создать объект в секции констант и передавать просто ссылку на него (ведь ссылка константная, а значит f и g не могут менять объект). Однако нет, каждый вызов f и g объекты конструируются на стеке. Хотя у tuple вообще есть constexpr конструктор.

Почему так? И способен ли современный C++ при каких-то условиях сконструировать временный объект во время компиляции и передавать ссылку на него в секции констант вместо конструирования на стеке? Если нет, то есть ли какие-то причины, почему эту фичу не реализуют?

UPD: Для std::tuple это работает как надо, если объявить аргумент отдельно как static переменную -https://godbolt.org/z/Y9q6Yh3q3. Для std::initializer_list не работает даже в этом случае (просто теперь он инициализируется не на стеке). Возможно ли создать аналог initializer_list (возможность передать в функцию переменное число аргументов с нормальной типобезопасностью и преобразованием типов при необходимости к правильному, а не как у темплейтов), который бы умел в статическое создание?

 ,

KivApple
()

C++: unordered_map с композитным ключом

Форум — Development

Допустим, я хочу, чтобы ключом в unordered_map выступала пара строки и числа.

Что-то вроде std::unordered_map<std::tuple<std::string, int>, MyStruct>. Хеширование легко можно реализовать следуя советам из https://stackoverflow.com/questions/7110301/generic-hash-for-tuples-in-unorde....

А вот дальше возникает проблема. Чтобы сделать find требуется создать экземпляр ключа для поиска. Так как ключ включает в себя строку, произойдёт копирование (допустим, наша функция получает const std::string& и должна действовать), что не есть хорошо.

Какое представление строки не требует копирование при создании? Правильно, std::string_view. Давайте сделаем ключом std::tuple<std::string_view, int>. Теперь операция поиска будет очень дешёвой.

Однако, возникает проблема как вставить в коллекцию новый элемент. Ведь string_view не хранит строку, а лишь ссылку на неё. Логичным решением выглядит сохранить строку в значении. Изменим тип коллекции на std::unordered_map<std::tuple<std::string_view, int>, std::tuple<std::string, MyStruct>>.

Надо чтобы string_view из ключа ссылался на string из значения. Тогда можно будет искать по легковесному ключу std::tuple<std::string_view, int>, а копированием заниматься лишь при добавлении элемента.

Но... Но как сделать так, чтобы string_view ссылался куда надо в момент insert/emplace?

Или, возможно, я что-то делаю не так и использую не те структуры данных.

P.S.: tuple здесь для простоты, на его месте, разумеется может быть своя структура из двух полей с определенным оператором сравнения и хеширования.

 ,

KivApple
()

C++: функция с переменным числом аргументов

Форум — Development

Пытаюсь создать функцию с переменным числом аргументов типобезопасным способом с помощью шаблонов.

#include <iostream>
#include <concepts>

template<typename First, typename... Rest> 
requires std::is_convertible_v<First, const std::string&> && (std::is_convertible_v<Rest, const std::string&> && ...)
void f(First &&first, Rest&&... rest) {
    f(first);
    f(std::forward(rest)...);
}

template<>
void f(const std::string &first) {
    std::cout << first << std::endl;
}

int main() {
    f("foo", "bar");
}

Однако компилятор игнорирует специализацию f и жалуется об отсутствии версии f без аргументов.

Перемещено hobbit из general

 

KivApple
()

Кроссплатформанная графическая библитека

Форум — Development

Уточню, что речь идёт о трёхмерной графике.

Итак:

OpenGL - поддерживается буквально везде, включая веб (WebGL) и мобилки. Можно писать на пересекающемся подмножестве OpenGL 3.0 Core и OpenGL 3.0 ES и иметь современный код с шейдерами, который везде работает. Минусы: в теории имеет меньшую производительность, чем более новые библиотеки, но насколько я понимаю 95 процентов приложений не почувствуют разницу. Неясное будущее, как минимум на яблоках помечен как deprecated и может быть удалён в любой момент.

Vulkan - предлагается как дефолтная замена OpenGL. В теории должен давать более высокую производительность, а также имеет более определённое будущее. На яблоках работает через MoltenVK, на остальных платформах нативно. В вебе не работает.

Metal - замена OpenGL от Apple, очевидный минус - работает только на яблочном оборудовании. Vulkan выглядит привлекательнее.

DirectX - альтернативна OpenGL и Vulkan от Microsoft. Очевидный минус - работает только на винде и икс коробке. Vulkan выглядит привлекательнее.

Выходит что по факту выбор получается между OpenGL и Vulkan, так как остальные библиотеки это библиотеки одной платформы, причём вряд ли дающие каких-то киллер-фич по сравнению с этими двумя.

Но OpenGL могут в любой момент выкинуть из яблочных устройств, а Vulkan не работает в браузере.

Интересно, какие шансы выкидывания OpenGL из яблок и каковы перспективы появления Vulkan в браузере (например, через прослойку аналогичную MoltenVK). Или же любой уважающий себя движкописатель обязан поддерживать обе библиотеки (допустим, нам важен и веб, и десктопы, и мобилки) или вообще все четыре.

 , , ,

KivApple
()

Паттерн Builder в C++

Форум — Development

Является ли нижеприведенный код корректным кодом C++ и не содержит ли UB?

struct MyObject {
    int a;
    int b;
};

class MyObjectBuilder {
    int m_a = 0;
    int m_b = 0;
public:
    MyObjectBuilder &a(int value) {
        m_a = value;
        return *this;
    }
    MyObjectBuilder &b(int value) {
        m_b = value;
        return *this;
    }
    MyObject build() {
        return MyObject { m_a, m_b };
    }
};

MyObject f() {
    return MyObjectBuilder().a(10).b(20).build();
}

(меня напрягает возврат ссылки на this из метода объекта, когда сам объект является временным)

 , ,

KivApple
()

CMake и упаковка ресурсов приложения

Форум — Development

Моей программе требуются некоторые ресурсы во время работы. Хочется иметь возможность распространять программу в виде одного статически слинкованного файла (особенно актуально для офтопика), однако оставить возможность пользователю покопаться в ресурсах. Оптимальным решением выглядит упаковка ресурсов в zip архив и склеивание с исполняемым файлом приложения. Из-за особенностей структуры zip большинство архиваторов смогут открыть такой файл и даже работать с ним, несмотря на то, что это вообще то исполняемый файл.

Вопрос в том как его собирать не руками. Я использую CMake. У него есть команда cmake -E tar, позволяющая через add_custom_command/add_custom_target создать zip (и не только) архив. Вопрос в том, как его приклеить к исполняемому файлу. Если просто указать имя исполняемого файла в качестве выходного, то он полностью перезаписывается. Значит нужно создать промежуточный zip-файл и потом приклеить его к исполняемому после сборки. Однако, я пока не нашёл в CMake возможность для этого. Использовать утилиты типа dd плохая идея, так как тогда проект будет собираться только на онтопике, а на офтопике таких полезных утилит нет.

 ,

KivApple
()

Док Mac OS X

Форум — Desktop

Допустим, имеется Macbook Air на M1 и иногда даже за ним приходится работать.

Система имеет свои нюансы, но меня уже несколько месяцев мучает один вопрос. Можно ли заставить док показывать приложения только с текущего рабочего стола. Иначе для меня теряется сама идея разделения контекстов, так как значки всё равно мельтешат перед глазами.

Я даже смотрел платные альтернативные доки (к счастью, ни один не купил), они хвалятся всякими свистелками и перделками типа миниатюр окон, но вот эту фичу как будто никто не догадался реализовать.

Хотя на Linux и даже на Windows (когда там появились рабочие столы) эта фича давно есть и отлично работает.

Помогите...

 ,

KivApple
()

RSS подписка на новые темы