Path: blob/21.2-virgl/src/gallium/frontends/clover/core/printf.cpp
4572 views
//1// Copyright 2020 Serge Martin2//3// Permission is hereby granted, free of charge, to any person obtaining a4// copy of this software and associated documentation files (the "Software"),5// to deal in the Software without restriction, including without limitation6// the rights to use, copy, modify, merge, publish, distribute, sublicense,7// and/or sell copies of the Software, and to permit persons to whom the8// Software is furnished to do so, subject to the following conditions:9//10// The above copyright notice and this permission notice shall be included in11// all copies or substantial portions of the Software.12//13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19// OTHER DEALINGS IN THE SOFTWARE.20//2122#include <cstring>23#include <cstdio>24#include <string>25#include <iostream>2627#include "util/u_math.h"28#include "core/printf.hpp"2930#include "util/u_printf.h"31using namespace clover;3233namespace {3435const cl_uint hdr_dwords = 2;36const cl_uint initial_buffer_offset = hdr_dwords * sizeof(cl_uint);3738/* all valid chars that can appear in CL C printf string. */39const std::string clc_printf_whitelist = "%0123456789-+ #.AacdeEfFgGhilopsuvxX";4041void42print_formatted(const std::vector<module::printf_info> &formatters,43bool _strings_in_buffer,44const std::vector<char> &buffer) {4546static std::atomic<unsigned> warn_count;47if (buffer.empty() && !warn_count++)48std::cerr << "Printf used but no printf occurred - may cause perfomance issue." << std::endl;4950for (size_t buf_pos = 0; buf_pos < buffer.size(); ) {51cl_uint fmt_idx = *(cl_uint*)&buffer[buf_pos];52assert(fmt_idx > 0);53module::printf_info fmt = formatters[fmt_idx-1];5455std::string format = (char *)fmt.strings.data();56buf_pos += sizeof(cl_uint);5758if (fmt.arg_sizes.empty()) {59printf("%s", format.c_str());6061} else {62size_t fmt_last_pos = 0;63size_t fmt_pos = 0;64for (int arg_size : fmt.arg_sizes) {65const size_t spec_pos = util_printf_next_spec_pos(format, fmt_pos);66const size_t cur_tok = format.rfind('%', spec_pos);67const size_t next_spec = util_printf_next_spec_pos(format, spec_pos);68const size_t next_tok = next_spec == std::string::npos ? std::string::npos :69format.rfind('%', next_spec);7071size_t vec_pos = format.find_first_of("v", cur_tok + 1);72size_t mod_pos = format.find_first_of("hl", cur_tok + 1);7374// print the part before the format token75if (cur_tok != fmt_last_pos) {76std::string s = format.substr(fmt_last_pos,77cur_tok - fmt_last_pos);78printf("%s", s.c_str());79}8081std::string print_str;82print_str = format.substr(cur_tok, spec_pos + 1 - cur_tok);8384/* Never pass a 'n' spec to the host printf */85bool valid_str = print_str.find_first_not_of(clc_printf_whitelist) ==86std::string::npos;8788// print the formated part89if (spec_pos != std::string::npos && valid_str) {90bool is_vector = vec_pos != std::string::npos &&91vec_pos + 1 < spec_pos;92bool is_string = format[spec_pos] == 's';93bool is_float = std::string("fFeEgGaA")94.find(format[spec_pos]) != std::string::npos;9596if (is_string) {97if (_strings_in_buffer)98printf(print_str.c_str(), &buffer[buf_pos]);99else {100uint64_t idx;101memcpy(&idx, &buffer[buf_pos], 8);102printf(print_str.c_str(), &fmt.strings[idx]);103}104} else {105int component_count = 1;106107if (is_vector) {108size_t l = std::min(mod_pos, spec_pos) - vec_pos - 1;109std::string s = format.substr(vec_pos + 1, l);110component_count = std::stoi(s);111if (mod_pos != std::string::npos) {112// CL C has hl specifier for 32-bit vectors, C doesn't have it113// just remove it.114std::string mod = format.substr(mod_pos, 2);115if (mod == "hl")116mod_pos = std::string::npos;117}118print_str.erase(vec_pos - cur_tok, std::min(mod_pos, spec_pos) - vec_pos);119print_str.push_back(',');120}121122//in fact vec3 are vec4123int men_components =124component_count == 3 ? 4 : component_count;125size_t elmt_size = arg_size / men_components;126127for (int i = 0; i < component_count; i++) {128size_t elmt_buf_pos = buf_pos + i * elmt_size;129if (is_vector && i + 1 == component_count)130print_str.pop_back();131132if (is_float) {133switch (elmt_size) {134case 2:135cl_half h;136std::memcpy(&h, &buffer[elmt_buf_pos], elmt_size);137printf(print_str.c_str(), h);138break;139case 4:140cl_float f;141std::memcpy(&f, &buffer[elmt_buf_pos], elmt_size);142printf(print_str.c_str(), f);143break;144default:145cl_double d;146std::memcpy(&d, &buffer[elmt_buf_pos], elmt_size);147printf(print_str.c_str(), d);148}149} else {150cl_long l = 0;151std::memcpy(&l, &buffer[elmt_buf_pos], elmt_size);152printf(print_str.c_str(), l);153}154}155}156// print the remaining157if (next_tok != spec_pos) {158std::string s = format.substr(spec_pos + 1,159next_tok - spec_pos - 1);160printf("%s", s.c_str());161}162}163164fmt_pos = spec_pos;165fmt_last_pos = next_tok;166167buf_pos += arg_size;168buf_pos = ALIGN(buf_pos, 4);169}170}171}172}173}174175std::unique_ptr<printf_handler>176printf_handler::create(const intrusive_ptr<command_queue> &q,177const std::vector<module::printf_info> &infos,178bool strings_in_buffer,179cl_uint size) {180return std::unique_ptr<printf_handler>(181new printf_handler(q, infos, strings_in_buffer, size));182}183184printf_handler::printf_handler(const intrusive_ptr<command_queue> &q,185const std::vector<module::printf_info> &infos,186bool strings_in_buffer,187cl_uint size) :188_q(q), _formatters(infos), _strings_in_buffer(strings_in_buffer), _size(size), _buffer() {189190if (_size) {191std::string data;192data.reserve(_size);193cl_uint header[2] = { 0 };194195header[0] = initial_buffer_offset;196header[1] = _size;197198data.append((char *)header, (char *)(header+hdr_dwords));199_buffer = std::unique_ptr<root_buffer>(new root_buffer(_q->context,200std::vector<cl_mem_properties>(),201CL_MEM_COPY_HOST_PTR,202_size, (char*)data.data()));203}204}205206cl_mem207printf_handler::get_mem() {208return (cl_mem)(_buffer.get());209}210211void212printf_handler::print() {213if (!_buffer)214return;215216mapping src = { *_q, _buffer->resource_in(*_q), CL_MAP_READ, true,217{{ 0 }}, {{ _size, 1, 1 }} };218219cl_uint header[2] = { 0 };220std::memcpy(header,221static_cast<const char *>(src),222initial_buffer_offset);223224cl_uint buffer_size = header[0];225buffer_size -= initial_buffer_offset;226std::vector<char> buf;227buf.resize(buffer_size);228229std::memcpy(buf.data(),230static_cast<const char *>(src) + initial_buffer_offset,231buffer_size);232233// mixed endian isn't going to work, sort it out if anyone cares later.234assert(_q->device().endianness() == PIPE_ENDIAN_NATIVE);235print_formatted(_formatters, _strings_in_buffer, buf);236}237238239