2
// Copyright 2020 Serge Martin
4
// Permission is hereby granted, free of charge, to any person obtaining a
5
// copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
// OTHER DEALINGS IN THE SOFTWARE.
28
#include "util/u_math.h"
29
#include "core/printf.hpp"
31
#include "util/u_printf.h"
32
using namespace clover;
36
const cl_uint hdr_dwords = 2;
37
const cl_uint initial_buffer_offset = hdr_dwords * sizeof(cl_uint);
39
/* all valid chars that can appear in CL C printf string. */
40
const std::string clc_printf_whitelist = "%0123456789-+ #.AacdeEfFgGhilopsuvxX";
43
print_formatted(const std::vector<binary::printf_info> &formatters,
44
bool _strings_in_buffer,
45
const std::vector<char> &buffer) {
47
static std::atomic<unsigned> warn_count;
48
if (buffer.empty() && !warn_count++)
49
std::cerr << "Printf used but no printf occurred - may cause perfomance issue." << std::endl;
51
for (size_t buf_pos = 0; buf_pos < buffer.size(); ) {
52
cl_uint fmt_idx = *(cl_uint*)&buffer[buf_pos];
54
binary::printf_info fmt = formatters[fmt_idx-1];
56
std::string format = (char *)fmt.strings.data();
57
buf_pos += sizeof(cl_uint);
59
if (fmt.arg_sizes.empty()) {
60
printf("%s", format.c_str());
63
size_t fmt_last_pos = 0;
65
for (int arg_size : fmt.arg_sizes) {
66
const size_t spec_pos = util_printf_next_spec_pos(format.c_str(), fmt_pos);
67
const size_t cur_tok = format.rfind('%', spec_pos);
68
const size_t next_spec = util_printf_next_spec_pos(format.c_str(), spec_pos);
69
const size_t next_tok = next_spec == std::string::npos ? std::string::npos :
70
format.rfind('%', next_spec);
72
size_t vec_pos = format.find_first_of("v", cur_tok + 1);
73
size_t mod_pos = format.find_first_of("hl", cur_tok + 1);
75
// print the part before the format token
76
if (cur_tok != fmt_last_pos) {
77
std::string s = format.substr(fmt_last_pos,
78
cur_tok - fmt_last_pos);
79
printf("%s", s.c_str());
82
std::string print_str;
83
print_str = format.substr(cur_tok, spec_pos + 1 - cur_tok);
85
/* Never pass a 'n' spec to the host printf */
86
bool valid_str = print_str.find_first_not_of(clc_printf_whitelist) ==
89
// print the formated part
90
if (spec_pos != std::string::npos && valid_str) {
91
bool is_vector = vec_pos != std::string::npos &&
92
vec_pos + 1 < spec_pos;
93
bool is_string = format[spec_pos] == 's';
94
bool is_float = std::string("fFeEgGaA")
95
.find(format[spec_pos]) != std::string::npos;
98
if (_strings_in_buffer)
99
printf(print_str.c_str(), &buffer[buf_pos]);
102
memcpy(&idx, &buffer[buf_pos], 8);
103
printf(print_str.c_str(), &fmt.strings[idx]);
106
int component_count = 1;
109
size_t l = std::min(mod_pos, spec_pos) - vec_pos - 1;
110
std::string s = format.substr(vec_pos + 1, l);
111
component_count = std::stoi(s);
112
if (mod_pos != std::string::npos) {
113
// CL C has hl specifier for 32-bit vectors, C doesn't have it
115
std::string mod = format.substr(mod_pos, 2);
117
mod_pos = std::string::npos;
119
print_str.erase(vec_pos - cur_tok, std::min(mod_pos, spec_pos) - vec_pos);
120
print_str.push_back(',');
123
//in fact vec3 are vec4
125
component_count == 3 ? 4 : component_count;
126
size_t elmt_size = arg_size / men_components;
128
for (int i = 0; i < component_count; i++) {
129
size_t elmt_buf_pos = buf_pos + i * elmt_size;
130
if (is_vector && i + 1 == component_count)
131
print_str.pop_back();
137
std::memcpy(&h, &buffer[elmt_buf_pos], elmt_size);
138
printf(print_str.c_str(), h);
142
std::memcpy(&f, &buffer[elmt_buf_pos], elmt_size);
143
printf(print_str.c_str(), f);
147
std::memcpy(&d, &buffer[elmt_buf_pos], elmt_size);
148
printf(print_str.c_str(), d);
152
std::memcpy(&l, &buffer[elmt_buf_pos], elmt_size);
153
printf(print_str.c_str(), l);
157
// print the remaining
158
if (next_tok != spec_pos) {
159
std::string s = format.substr(spec_pos + 1,
160
next_tok - spec_pos - 1);
161
printf("%s", s.c_str());
166
fmt_last_pos = next_tok;
169
buf_pos = ALIGN(buf_pos, 4);
176
std::unique_ptr<printf_handler>
177
printf_handler::create(const intrusive_ptr<command_queue> &q,
178
const std::vector<binary::printf_info> &infos,
179
bool strings_in_buffer,
181
return std::unique_ptr<printf_handler>(
182
new printf_handler(q, infos, strings_in_buffer, size));
185
printf_handler::printf_handler(const intrusive_ptr<command_queue> &q,
186
const std::vector<binary::printf_info> &infos,
187
bool strings_in_buffer,
189
_q(q), _formatters(infos), _strings_in_buffer(strings_in_buffer), _size(size), _buffer() {
194
cl_uint header[2] = { 0 };
196
header[0] = initial_buffer_offset;
199
data.append((char *)header, (char *)(header+hdr_dwords));
200
_buffer = std::unique_ptr<root_buffer>(new root_buffer(_q->context,
201
std::vector<cl_mem_properties>(),
202
CL_MEM_COPY_HOST_PTR,
203
_size, (char*)data.data()));
208
printf_handler::get_mem() {
209
return (cl_mem)(_buffer.get());
213
printf_handler::print() {
217
mapping src = { *_q, _buffer->resource_in(*_q), CL_MAP_READ, true,
218
{{ 0 }}, {{ _size, 1, 1 }} };
220
cl_uint header[2] = { 0 };
222
static_cast<const char *>(src),
223
initial_buffer_offset);
225
cl_uint buffer_size = header[0];
226
buffer_size -= initial_buffer_offset;
227
std::vector<char> buf;
228
buf.resize(buffer_size);
230
std::memcpy(buf.data(),
231
static_cast<const char *>(src) + initial_buffer_offset,
234
// mixed endian isn't going to work, sort it out if anyone cares later.
235
assert(_q->device().endianness() == PIPE_ENDIAN_NATIVE);
236
print_formatted(_formatters, _strings_in_buffer, buf);